blob: 52920c24b5d1971dd01acfe2509887d604a5c0d8 [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "C2SoftMpeg2Dec"
srujan vandrangiaa829c52024-05-30 11:27:35 +053019#ifndef KEEP_THREADS_ACTIVE
20#define KEEP_THREADS_ACTIVE 0
21#endif
Pawin Vongmasa36653902018-11-15 00:10:25 -080022#include <log/log.h>
23
24#include <media/stagefright/foundation/MediaDefs.h>
25
26#include <C2Debug.h>
27#include <C2PlatformSupport.h>
28#include <Codec2Mapper.h>
29#include <SimpleC2Interface.h>
30
31#include "C2SoftMpeg2Dec.h"
32#include "impeg2d.h"
33
34namespace android {
Harish Mahendrakare55c4712019-07-26 12:32:13 -070035constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
Harish Mahendrakarfb145812021-01-25 16:11:37 -080036constexpr size_t kMaxDimension = 1920;
Pawin Vongmasa36653902018-11-15 00:10:25 -080037constexpr char COMPONENT_NAME[] = "c2.android.mpeg2.decoder";
38
39class C2SoftMpeg2Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
40public:
41 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
42 : SimpleInterface<void>::BaseParams(
43 helper,
44 COMPONENT_NAME,
45 C2Component::KIND_DECODER,
46 C2Component::DOMAIN_VIDEO,
47 MEDIA_MIMETYPE_VIDEO_MPEG2) {
48 noPrivateBuffers(); // TODO: account for our buffers here
49 noInputReferences();
50 noOutputReferences();
51 noInputLatency();
52 noTimeStretch();
53
Harish Mahendrakar7be1bc92019-08-01 14:59:35 -070054 // TODO: Proper support for reorder depth.
55 addParameter(
56 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
57 .withConstValue(new C2PortActualDelayTuning::output(3u))
58 .build());
59
Pawin Vongmasa36653902018-11-15 00:10:25 -080060 // TODO: output latency and reordering
61
62 addParameter(
63 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
64 .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
65 .build());
66
67 addParameter(
68 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
69 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
70 .withFields({
Harish Mahendrakarfb145812021-01-25 16:11:37 -080071 C2F(mSize, width).inRange(16, kMaxDimension, 2),
72 C2F(mSize, height).inRange(16, kMaxDimension, 2),
Pawin Vongmasa36653902018-11-15 00:10:25 -080073 })
74 .withSetter(SizeSetter)
75 .build());
76
77 addParameter(
78 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
79 .withDefault(new C2StreamProfileLevelInfo::input(0u,
80 C2Config::PROFILE_MP2V_SIMPLE, C2Config::LEVEL_MP2V_HIGH))
81 .withFields({
82 C2F(mProfileLevel, profile).oneOf({
83 C2Config::PROFILE_MP2V_SIMPLE,
84 C2Config::PROFILE_MP2V_MAIN}),
85 C2F(mProfileLevel, level).oneOf({
86 C2Config::LEVEL_MP2V_LOW,
87 C2Config::LEVEL_MP2V_MAIN,
88 C2Config::LEVEL_MP2V_HIGH_1440,
89 C2Config::LEVEL_MP2V_HIGH})
90 })
91 .withSetter(ProfileLevelSetter, mSize)
92 .build());
93
94 addParameter(
95 DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
96 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
97 .withFields({
Harish Mahendrakarfb145812021-01-25 16:11:37 -080098 C2F(mSize, width).inRange(2, kMaxDimension, 2),
99 C2F(mSize, height).inRange(2, kMaxDimension, 2),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800100 })
101 .withSetter(MaxPictureSizeSetter, mSize)
102 .build());
103
104 addParameter(
105 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
Harish Mahendrakare55c4712019-07-26 12:32:13 -0700106 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
Pawin Vongmasa36653902018-11-15 00:10:25 -0800107 .withFields({
108 C2F(mMaxInputSize, value).any(),
109 })
110 .calculatedAs(MaxInputSizeSetter, mMaxSize)
111 .build());
112
113 C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
114 std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
115 C2StreamColorInfo::output::AllocShared(
116 1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
117 memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
118
119 defaultColorInfo =
120 C2StreamColorInfo::output::AllocShared(
121 { C2ChromaOffsetStruct::ITU_YUV_420_0() },
122 0u, 8u /* bitDepth */, C2Color::YUV_420);
123 helper->addStructDescriptors<C2ChromaOffsetStruct>();
124
125 addParameter(
126 DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
127 .withConstValue(defaultColorInfo)
128 .build());
129
130 addParameter(
131 DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
132 .withDefault(new C2StreamColorAspectsTuning::output(
133 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
134 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
135 .withFields({
136 C2F(mDefaultColorAspects, range).inRange(
137 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
138 C2F(mDefaultColorAspects, primaries).inRange(
139 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
140 C2F(mDefaultColorAspects, transfer).inRange(
141 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
142 C2F(mDefaultColorAspects, matrix).inRange(
143 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
144 })
145 .withSetter(DefaultColorAspectsSetter)
146 .build());
147
148 addParameter(
149 DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
150 .withDefault(new C2StreamColorAspectsInfo::input(
151 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
152 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
153 .withFields({
154 C2F(mCodedColorAspects, range).inRange(
155 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
156 C2F(mCodedColorAspects, primaries).inRange(
157 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
158 C2F(mCodedColorAspects, transfer).inRange(
159 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
160 C2F(mCodedColorAspects, matrix).inRange(
161 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
162 })
163 .withSetter(CodedColorAspectsSetter)
164 .build());
165
166 addParameter(
167 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
168 .withDefault(new C2StreamColorAspectsInfo::output(
169 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
170 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
171 .withFields({
172 C2F(mColorAspects, range).inRange(
173 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
174 C2F(mColorAspects, primaries).inRange(
175 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
176 C2F(mColorAspects, transfer).inRange(
177 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
178 C2F(mColorAspects, matrix).inRange(
179 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
180 })
181 .withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects)
182 .build());
183
184 // TODO: support more formats?
185 addParameter(
186 DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
187 .withConstValue(new C2StreamPixelFormatInfo::output(
188 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
189 .build());
190 }
191
192 static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800193 C2P<C2StreamPictureSizeInfo::output> &me) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800194 (void)mayBlock;
195 C2R res = C2R::Ok();
196 if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
197 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
198 me.set().width = oldMe.v.width;
199 }
200 if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
201 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
202 me.set().height = oldMe.v.height;
203 }
204 return res;
205 }
206
207 static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
208 const C2P<C2StreamPictureSizeInfo::output> &size) {
209 (void)mayBlock;
210 // TODO: get max width/height from the size's field helpers vs. hardcoding
Harish Mahendrakarfb145812021-01-25 16:11:37 -0800211 me.set().width = c2_min(c2_max(me.v.width, size.v.width), kMaxDimension);
212 me.set().height = c2_min(c2_max(me.v.height, size.v.height), kMaxDimension);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800213 return C2R::Ok();
214 }
215
216 static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
217 const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
218 (void)mayBlock;
219 // assume compression ratio of 1
Harish Mahendrakare55c4712019-07-26 12:32:13 -0700220 me.set().value = c2_max((((maxSize.v.width + 15) / 16)
221 * ((maxSize.v.height + 15) / 16) * 384), kMinInputBufferSize);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800222 return C2R::Ok();
223 }
224
225 static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
226 const C2P<C2StreamPictureSizeInfo::output> &size) {
227 (void)mayBlock;
228 (void)size;
229 (void)me; // TODO: validate
230 return C2R::Ok();
231 }
232
233 static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
234 (void)mayBlock;
235 if (me.v.range > C2Color::RANGE_OTHER) {
236 me.set().range = C2Color::RANGE_OTHER;
237 }
238 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
239 me.set().primaries = C2Color::PRIMARIES_OTHER;
240 }
241 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
242 me.set().transfer = C2Color::TRANSFER_OTHER;
243 }
244 if (me.v.matrix > C2Color::MATRIX_OTHER) {
245 me.set().matrix = C2Color::MATRIX_OTHER;
246 }
247 return C2R::Ok();
248 }
249
250 static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) {
251 (void)mayBlock;
252 if (me.v.range > C2Color::RANGE_OTHER) {
253 me.set().range = C2Color::RANGE_OTHER;
254 }
255 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
256 me.set().primaries = C2Color::PRIMARIES_OTHER;
257 }
258 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
259 me.set().transfer = C2Color::TRANSFER_OTHER;
260 }
261 if (me.v.matrix > C2Color::MATRIX_OTHER) {
262 me.set().matrix = C2Color::MATRIX_OTHER;
263 }
264 return C2R::Ok();
265 }
266
267 static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
268 const C2P<C2StreamColorAspectsTuning::output> &def,
269 const C2P<C2StreamColorAspectsInfo::input> &coded) {
270 (void)mayBlock;
271 // take default values for all unspecified fields, and coded values for specified ones
272 me.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
273 me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED
274 ? def.v.primaries : coded.v.primaries;
275 me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED
276 ? def.v.transfer : coded.v.transfer;
277 me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix;
278 return C2R::Ok();
279 }
280
281 std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() {
282 return mColorAspects;
283 }
284
285private:
286 std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
287 std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
288 std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
289 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
290 std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
291 std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
292 std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
293 std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
294 std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
295};
296
297static size_t getCpuCoreCount() {
298 long cpuCoreCount = 1;
299#if defined(_SC_NPROCESSORS_ONLN)
300 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
301#else
302 // _SC_NPROC_ONLN must be defined...
303 cpuCoreCount = sysconf(_SC_NPROC_ONLN);
304#endif
305 CHECK(cpuCoreCount >= 1);
306 ALOGV("Number of CPU cores: %ld", cpuCoreCount);
307 return (size_t)cpuCoreCount;
308}
309
310static void *ivd_aligned_malloc(WORD32 alignment, WORD32 size) {
311 return memalign(alignment, size);
312}
313
314static void ivd_aligned_free(void *mem) {
315 free(mem);
316}
317
318C2SoftMpeg2Dec::C2SoftMpeg2Dec(
319 const char *name,
320 c2_node_id_t id,
321 const std::shared_ptr<IntfImpl> &intfImpl)
322 : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
323 mIntf(intfImpl),
324 mDecHandle(nullptr),
325 mMemRecords(nullptr),
326 mOutBufferDrain(nullptr),
327 mIvColorformat(IV_YUV_420P),
328 mWidth(320),
Rakesh Kumard91bc482019-02-18 10:42:41 +0530329 mHeight(240),
330 mOutIndex(0u) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800331 // If input dump is enabled, then open create an empty file
332 GENERATE_FILE_NAMES();
333 CREATE_DUMP_FILE(mInFile);
334}
335
336C2SoftMpeg2Dec::~C2SoftMpeg2Dec() {
337 onRelease();
338}
339
340c2_status_t C2SoftMpeg2Dec::onInit() {
341 status_t err = initDecoder();
342 return err == OK ? C2_OK : C2_CORRUPTED;
343}
344
345c2_status_t C2SoftMpeg2Dec::onStop() {
346 if (OK != resetDecoder()) return C2_CORRUPTED;
347 resetPlugin();
348 return C2_OK;
349}
350
351void C2SoftMpeg2Dec::onReset() {
352 (void) onStop();
353}
354
355void C2SoftMpeg2Dec::onRelease() {
356 (void) deleteDecoder();
357 if (mOutBufferDrain) {
358 ivd_aligned_free(mOutBufferDrain);
359 mOutBufferDrain = nullptr;
360 }
361 if (mOutBlock) {
362 mOutBlock.reset();
363 }
364 if (mMemRecords) {
365 ivd_aligned_free(mMemRecords);
366 mMemRecords = nullptr;
367 }
368}
369
370c2_status_t C2SoftMpeg2Dec::onFlush_sm() {
371 if (OK != setFlushMode()) return C2_CORRUPTED;
372
373 uint32_t displayStride = mStride;
374 uint32_t displayHeight = mHeight;
375 uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
376 mOutBufferDrain = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
377 if (!mOutBufferDrain) {
378 ALOGE("could not allocate tmp output buffer (for flush) of size %u ", bufferSize);
379 return C2_NO_MEMORY;
380 }
381
382 while (true) {
383 ivd_video_decode_ip_t s_decode_ip;
384 ivd_video_decode_op_t s_decode_op;
385
386 setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, nullptr, 0, 0, 0);
387 (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
388 if (0 == s_decode_op.u4_output_present) {
389 resetPlugin();
390 break;
391 }
392 }
393
394 if (mOutBufferDrain) {
395 ivd_aligned_free(mOutBufferDrain);
396 mOutBufferDrain = nullptr;
397 }
398
399 return C2_OK;
400}
401
402status_t C2SoftMpeg2Dec::getNumMemRecords() {
403 iv_num_mem_rec_ip_t s_num_mem_rec_ip;
404 iv_num_mem_rec_op_t s_num_mem_rec_op;
405
406 s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
407 s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
408 s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
409
410 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
411 &s_num_mem_rec_ip,
412 &s_num_mem_rec_op);
413 if (IV_SUCCESS != status) {
414 ALOGE("Error in getting mem records: 0x%x", s_num_mem_rec_op.u4_error_code);
415 return UNKNOWN_ERROR;
416 }
417 mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
418
419 return OK;
420}
421
422status_t C2SoftMpeg2Dec::fillMemRecords() {
423 iv_mem_rec_t *ps_mem_rec = (iv_mem_rec_t *) ivd_aligned_malloc(
424 128, mNumMemRecords * sizeof(iv_mem_rec_t));
425 if (!ps_mem_rec) {
426 ALOGE("Allocation failure");
427 return NO_MEMORY;
428 }
429 memset(ps_mem_rec, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
430 for (size_t i = 0; i < mNumMemRecords; i++)
431 ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
432 mMemRecords = ps_mem_rec;
433
434 ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
435 ivdext_fill_mem_rec_op_t s_fill_mem_op;
436
437 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = sizeof(ivdext_fill_mem_rec_ip_t);
438 s_fill_mem_ip.u4_share_disp_buf = 0;
srujan vandrangiaa829c52024-05-30 11:27:35 +0530439 s_fill_mem_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800440 s_fill_mem_ip.e_output_format = mIvColorformat;
441 s_fill_mem_ip.u4_deinterlace = 1;
442 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
443 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
444 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth;
445 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight;
446 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = sizeof(ivdext_fill_mem_rec_op_t);
447 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
448 &s_fill_mem_ip,
449 &s_fill_mem_op);
450 if (IV_SUCCESS != status) {
451 ALOGE("Error in filling mem records: 0x%x",
452 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
453 return UNKNOWN_ERROR;
454 }
455
456 CHECK_EQ(mNumMemRecords, s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled);
457 for (size_t i = 0; i < mNumMemRecords; i++, ps_mem_rec++) {
458 ps_mem_rec->pv_base = ivd_aligned_malloc(
459 ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
460 if (!ps_mem_rec->pv_base) {
461 ALOGE("Allocation failure for memory record #%zu of size %u",
462 i, ps_mem_rec->u4_mem_size);
463 return NO_MEMORY;
464 }
465 }
466
467 return OK;
468}
469
470status_t C2SoftMpeg2Dec::createDecoder() {
471 ivdext_init_ip_t s_init_ip;
472 ivdext_init_op_t s_init_op;
473
474 s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
475 s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
476 s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
477 s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth;
478 s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
479 s_init_ip.u4_share_disp_buf = 0;
480 s_init_ip.u4_deinterlace = 1;
srujan vandrangiaa829c52024-05-30 11:27:35 +0530481 s_init_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800482 s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
483 s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorformat;
484 s_init_op.s_ivd_init_op_t.u4_size = sizeof(ivdext_init_op_t);
485
486 mDecHandle = (iv_obj_t *)mMemRecords[0].pv_base;
487 mDecHandle->pv_fxns = (void *)ivdec_api_function;
488 mDecHandle->u4_size = sizeof(iv_obj_t);
489
490 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
491 &s_init_ip,
492 &s_init_op);
493 if (status != IV_SUCCESS) {
494 ALOGE("error in %s: 0x%x", __func__,
495 s_init_op.s_ivd_init_op_t.u4_error_code);
496 return UNKNOWN_ERROR;
497 }
498
499 return OK;
500}
501
502status_t C2SoftMpeg2Dec::setNumCores() {
503 ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip;
504 ivdext_ctl_set_num_cores_op_t s_set_num_cores_op;
505
506 s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
507 s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
508 s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
509 s_set_num_cores_ip.u4_num_cores = mNumCores;
510 s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
511 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
512 &s_set_num_cores_ip,
513 &s_set_num_cores_op);
514 if (status != IV_SUCCESS) {
515 ALOGD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code);
516 return UNKNOWN_ERROR;
517 }
518
519 return OK;
520}
521
522status_t C2SoftMpeg2Dec::setParams(size_t stride) {
523 ivd_ctl_set_config_ip_t s_set_dyn_params_ip;
524 ivd_ctl_set_config_op_t s_set_dyn_params_op;
525
526 s_set_dyn_params_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
527 s_set_dyn_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
528 s_set_dyn_params_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
529 s_set_dyn_params_ip.u4_disp_wd = (UWORD32) stride;
530 s_set_dyn_params_ip.e_frm_skip_mode = IVD_SKIP_NONE;
531 s_set_dyn_params_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
532 s_set_dyn_params_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
533 s_set_dyn_params_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
534 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
535 &s_set_dyn_params_ip,
536 &s_set_dyn_params_op);
537 if (status != IV_SUCCESS) {
538 ALOGE("error in %s: 0x%x", __func__, s_set_dyn_params_op.u4_error_code);
539 return UNKNOWN_ERROR;
540 }
541
542 return OK;
543}
544
545status_t C2SoftMpeg2Dec::getVersion() {
546 ivd_ctl_getversioninfo_ip_t s_get_versioninfo_ip;
547 ivd_ctl_getversioninfo_op_t s_get_versioninfo_op;
548 UWORD8 au1_buf[512];
549
550 s_get_versioninfo_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
551 s_get_versioninfo_ip.e_cmd = IVD_CMD_VIDEO_CTL;
552 s_get_versioninfo_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
553 s_get_versioninfo_ip.pv_version_buffer = au1_buf;
554 s_get_versioninfo_ip.u4_version_buffer_size = sizeof(au1_buf);
555 s_get_versioninfo_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
556 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
557 &s_get_versioninfo_ip,
558 &s_get_versioninfo_op);
559 if (status != IV_SUCCESS) {
560 ALOGD("error in %s: 0x%x", __func__,
561 s_get_versioninfo_op.u4_error_code);
562 } else {
563 ALOGV("ittiam decoder version number: %s",
564 (char *) s_get_versioninfo_ip.pv_version_buffer);
565 }
566
567 return OK;
568}
569
570status_t C2SoftMpeg2Dec::initDecoder() {
571 status_t ret = getNumMemRecords();
572 if (OK != ret) return ret;
573
574 ret = fillMemRecords();
575 if (OK != ret) return ret;
576
577 if (OK != createDecoder()) return UNKNOWN_ERROR;
578
579 mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
Harish Mahendrakare403bf72021-10-21 10:30:35 -0700580 mStride = ALIGN128(mWidth);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800581 mSignalledError = false;
582 resetPlugin();
583 (void) setNumCores();
584 if (OK != setParams(mStride)) return UNKNOWN_ERROR;
585 (void) getVersion();
586
587 return OK;
588}
589
590bool C2SoftMpeg2Dec::setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
591 ivd_video_decode_op_t *ps_decode_op,
592 C2ReadView *inBuffer,
593 C2GraphicView *outBuffer,
594 size_t inOffset,
595 size_t inSize,
596 uint32_t tsMarker) {
597 uint32_t displayStride = mStride;
Harish Mahendrakardc1d2d92019-10-18 16:27:38 -0700598 if (outBuffer) {
599 C2PlanarLayout layout;
600 layout = outBuffer->layout();
601 displayStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
602 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800603 uint32_t displayHeight = mHeight;
604 size_t lumaSize = displayStride * displayHeight;
605 size_t chromaSize = lumaSize >> 2;
606
Harish Mahendrakardc1d2d92019-10-18 16:27:38 -0700607 if (mStride != displayStride) {
608 mStride = displayStride;
609 if (OK != setParams(mStride)) return false;
610 }
611
Pawin Vongmasa36653902018-11-15 00:10:25 -0800612 ps_decode_ip->u4_size = sizeof(ivd_video_decode_ip_t);
613 ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
614 if (inBuffer) {
615 ps_decode_ip->u4_ts = tsMarker;
616 ps_decode_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer->data() + inOffset);
617 ps_decode_ip->u4_num_Bytes = inSize;
618 } else {
619 ps_decode_ip->u4_ts = 0;
620 ps_decode_ip->pv_stream_buffer = nullptr;
621 ps_decode_ip->u4_num_Bytes = 0;
622 }
623 ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize;
624 ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
625 ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
626 if (outBuffer) {
Harish Mahendrakareb767792020-05-02 00:14:38 +0530627 if (outBuffer->height() < displayHeight) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800628 ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)",
629 outBuffer->width(), outBuffer->height(), displayStride, displayHeight);
630 return false;
631 }
632 ps_decode_ip->s_out_buffer.pu1_bufs[0] = outBuffer->data()[C2PlanarLayout::PLANE_Y];
633 ps_decode_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[C2PlanarLayout::PLANE_U];
634 ps_decode_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[C2PlanarLayout::PLANE_V];
635 } else {
636 ps_decode_ip->s_out_buffer.pu1_bufs[0] = mOutBufferDrain;
637 ps_decode_ip->s_out_buffer.pu1_bufs[1] = mOutBufferDrain + lumaSize;
638 ps_decode_ip->s_out_buffer.pu1_bufs[2] = mOutBufferDrain + lumaSize + chromaSize;
639 }
640 ps_decode_ip->s_out_buffer.u4_num_bufs = 3;
641 ps_decode_op->u4_size = sizeof(ivd_video_decode_op_t);
642
643 return true;
644}
645
646
647bool C2SoftMpeg2Dec::getSeqInfo() {
648 ivdext_ctl_get_seq_info_ip_t s_ctl_get_seq_info_ip;
649 ivdext_ctl_get_seq_info_op_t s_ctl_get_seq_info_op;
650
651 s_ctl_get_seq_info_ip.u4_size = sizeof(ivdext_ctl_get_seq_info_ip_t);
652 s_ctl_get_seq_info_ip.e_cmd = IVD_CMD_VIDEO_CTL;
653 s_ctl_get_seq_info_ip.e_sub_cmd =
654 (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_GET_SEQ_INFO;
655 s_ctl_get_seq_info_op.u4_size = sizeof(ivdext_ctl_get_seq_info_op_t);
656 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
657 &s_ctl_get_seq_info_ip,
658 &s_ctl_get_seq_info_op);
659 if (status != IV_SUCCESS) {
660 ALOGW("Error in getting Sequence info: 0x%x", s_ctl_get_seq_info_op.u4_error_code);
661 return false;
662 }
663
664 VuiColorAspects vuiColorAspects;
665 vuiColorAspects.primaries = s_ctl_get_seq_info_op.u1_colour_primaries;
666 vuiColorAspects.transfer = s_ctl_get_seq_info_op.u1_transfer_characteristics;
667 vuiColorAspects.coeffs = s_ctl_get_seq_info_op.u1_matrix_coefficients;
668 vuiColorAspects.fullRange = false; // mpeg2 video has limited range.
669
670 // convert vui aspects to C2 values if changed
671 if (!(vuiColorAspects == mBitstreamColorAspects)) {
672 mBitstreamColorAspects = vuiColorAspects;
673 ColorAspects sfAspects;
674 C2StreamColorAspectsInfo::input codedAspects = { 0u };
675 ColorUtils::convertIsoColorAspectsToCodecAspects(
676 vuiColorAspects.primaries, vuiColorAspects.transfer, vuiColorAspects.coeffs,
677 vuiColorAspects.fullRange, sfAspects);
678 if (!C2Mapper::map(sfAspects.mPrimaries, &codedAspects.primaries)) {
679 codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED;
680 }
681 if (!C2Mapper::map(sfAspects.mRange, &codedAspects.range)) {
682 codedAspects.range = C2Color::RANGE_UNSPECIFIED;
683 }
684 if (!C2Mapper::map(sfAspects.mMatrixCoeffs, &codedAspects.matrix)) {
685 codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED;
686 }
687 if (!C2Mapper::map(sfAspects.mTransfer, &codedAspects.transfer)) {
688 codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED;
689 }
690 std::vector<std::unique_ptr<C2SettingResult>> failures;
691 (void)mIntf->config({&codedAspects}, C2_MAY_BLOCK, &failures);
692 }
693 return true;
694}
695
696status_t C2SoftMpeg2Dec::setFlushMode() {
697 ivd_ctl_flush_ip_t s_set_flush_ip;
698 ivd_ctl_flush_op_t s_set_flush_op;
699
700 s_set_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
701 s_set_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
702 s_set_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
703 s_set_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
704 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
705 &s_set_flush_ip,
706 &s_set_flush_op);
707 if (status != IV_SUCCESS) {
708 ALOGE("error in %s: 0x%x", __func__, s_set_flush_op.u4_error_code);
709 return UNKNOWN_ERROR;
710 }
711
712 return OK;
713}
714
715status_t C2SoftMpeg2Dec::resetDecoder() {
716 ivd_ctl_reset_ip_t s_reset_ip;
717 ivd_ctl_reset_op_t s_reset_op;
718
719 s_reset_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
720 s_reset_ip.e_cmd = IVD_CMD_VIDEO_CTL;
721 s_reset_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
722 s_reset_op.u4_size = sizeof(ivd_ctl_reset_op_t);
723 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
724 &s_reset_ip,
725 &s_reset_op);
726 if (IV_SUCCESS != status) {
727 ALOGE("error in %s: 0x%x", __func__, s_reset_op.u4_error_code);
728 return UNKNOWN_ERROR;
729 }
730 (void) setNumCores();
731 mStride = 0;
732 mSignalledError = false;
733
734 return OK;
735}
736
737void C2SoftMpeg2Dec::resetPlugin() {
738 mSignalledOutputEos = false;
Ray Essick24754942022-04-16 09:50:35 -0700739 mTimeStart = mTimeEnd = systemTime();
Harish Mahendrakar05575b12022-10-19 18:17:07 -0700740 if (mOutBlock) {
741 mOutBlock.reset();
742 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800743}
744
745status_t C2SoftMpeg2Dec::deleteDecoder() {
Suyog Pawarc2f9e9d2024-10-16 21:18:34 +0530746 // API call to IV_CMD_RETRIEVE_MEMREC not only retrieves the memory records
747 // but also joins active threads and destroys conditional thread variables and
748 // mutex locks for each thread.
749 iv_retrieve_mem_rec_ip_t s_retrieve_mem_ip;
750 iv_retrieve_mem_rec_op_t s_retrieve_mem_op;
751
752 s_retrieve_mem_ip.pv_mem_rec_location = (iv_mem_rec_t *)mMemRecords;
753 s_retrieve_mem_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC;
754 s_retrieve_mem_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t);
755 s_retrieve_mem_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t);
756
757 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
758 &s_retrieve_mem_ip,
759 &s_retrieve_mem_op);
760 if (IV_SUCCESS != status) {
761 ALOGE("error in %s: 0x%x", __func__, s_retrieve_mem_op.u4_error_code);
762 return UNKNOWN_ERROR;
763 }
764
Pawin Vongmasa36653902018-11-15 00:10:25 -0800765 if (mMemRecords) {
766 iv_mem_rec_t *ps_mem_rec = mMemRecords;
767
768 for (size_t i = 0; i < mNumMemRecords; i++, ps_mem_rec++) {
769 if (ps_mem_rec->pv_base) {
770 ivd_aligned_free(ps_mem_rec->pv_base);
771 }
772 }
773 ivd_aligned_free(mMemRecords);
774 mMemRecords = nullptr;
775 }
776 mDecHandle = nullptr;
777
778 return OK;
779}
780
781status_t C2SoftMpeg2Dec::reInitDecoder() {
782 deleteDecoder();
783
784 status_t ret = initDecoder();
785 if (OK != ret) {
786 ALOGE("Failed to initialize decoder");
787 deleteDecoder();
788 return ret;
789 }
790 return OK;
791}
792
793void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
794 uint32_t flags = 0;
795 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
796 flags |= C2FrameData::FLAG_END_OF_STREAM;
797 ALOGV("signalling eos");
798 }
799 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
800 work->worklets.front()->output.buffers.clear();
801 work->worklets.front()->output.ordinal = work->input.ordinal;
802 work->workletsProcessed = 1u;
803}
804
805void C2SoftMpeg2Dec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
806 std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock),
807 C2Rect(mWidth, mHeight));
808 mOutBlock = nullptr;
809 {
810 IntfImpl::Lock lock = mIntf->lock();
811 buffer->setInfo(mIntf->getColorAspects_l());
812 }
813
Rakesh Kumard91bc482019-02-18 10:42:41 +0530814 class FillWork {
815 public:
816 FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
817 const std::shared_ptr<C2Buffer>& buffer)
818 : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {}
819 ~FillWork() = default;
820
821 void operator()(const std::unique_ptr<C2Work>& work) {
822 work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
823 work->worklets.front()->output.buffers.clear();
824 work->worklets.front()->output.ordinal = mOrdinal;
825 work->workletsProcessed = 1u;
826 work->result = C2_OK;
827 if (mBuffer) {
828 work->worklets.front()->output.buffers.push_back(mBuffer);
829 }
830 ALOGV("timestamp = %lld, index = %lld, w/%s buffer",
831 mOrdinal.timestamp.peekll(), mOrdinal.frameIndex.peekll(),
832 mBuffer ? "" : "o");
833 }
834
835 private:
836 const uint32_t mFlags;
837 const C2WorkOrdinalStruct mOrdinal;
838 const std::shared_ptr<C2Buffer> mBuffer;
839 };
840
Pawin Vongmasa36653902018-11-15 00:10:25 -0800841 auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
842 work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
843 work->worklets.front()->output.buffers.clear();
844 work->worklets.front()->output.buffers.push_back(buffer);
845 work->worklets.front()->output.ordinal = work->input.ordinal;
846 work->workletsProcessed = 1u;
847 };
848 if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
Rakesh Kumard91bc482019-02-18 10:42:41 +0530849 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
850 // TODO: Check if cloneAndSend can be avoided by tracking number of frames remaining
851 if (eos) {
852 if (buffer) {
853 mOutIndex = index;
854 C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
855 cloneAndSend(
856 mOutIndex, work,
857 FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
858 buffer.reset();
859 }
860 } else {
861 fillWork(work);
862 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800863 } else {
864 finish(index, fillWork);
865 }
866}
867
868c2_status_t C2SoftMpeg2Dec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
869 if (!mDecHandle) {
870 ALOGE("not supposed to be here, invalid decoder context");
871 return C2_CORRUPTED;
872 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800873 if (mOutBlock &&
Harish Mahendrakare403bf72021-10-21 10:30:35 -0700874 (mOutBlock->width() != ALIGN128(mWidth) || mOutBlock->height() != mHeight)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800875 mOutBlock.reset();
876 }
877 if (!mOutBlock) {
878 uint32_t format = HAL_PIXEL_FORMAT_YV12;
879 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
Harish Mahendrakardc1d2d92019-10-18 16:27:38 -0700880 c2_status_t err =
Harish Mahendrakare403bf72021-10-21 10:30:35 -0700881 pool->fetchGraphicBlock(ALIGN128(mWidth), mHeight, format, usage, &mOutBlock);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800882 if (err != C2_OK) {
883 ALOGE("fetchGraphicBlock for Output failed with status %d", err);
884 return err;
885 }
886 ALOGV("provided (%dx%d) required (%dx%d)",
Harish Mahendrakare403bf72021-10-21 10:30:35 -0700887 mOutBlock->width(), mOutBlock->height(), ALIGN128(mWidth), mHeight);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800888 }
889
890 return C2_OK;
891}
892
893// TODO: can overall error checking be improved?
894// TODO: allow configuration of color format and usage for graphic buffers instead
895// of hard coding them to HAL_PIXEL_FORMAT_YV12
896// TODO: pass coloraspects information to surface
897// TODO: test support for dynamic change in resolution
898// TODO: verify if the decoder sent back all frames
899void C2SoftMpeg2Dec::process(
900 const std::unique_ptr<C2Work> &work,
901 const std::shared_ptr<C2BlockPool> &pool) {
902 // Initialize output work
903 work->result = C2_OK;
904 work->workletsProcessed = 0u;
905 work->worklets.front()->output.configUpdate.clear();
906 work->worklets.front()->output.flags = work->input.flags;
907
908 if (mSignalledError || mSignalledOutputEos) {
909 work->result = C2_BAD_VALUE;
910 return;
911 }
912
913 size_t inOffset = 0u;
914 size_t inSize = 0u;
915 uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
916 C2ReadView rView = mDummyReadView;
917 if (!work->input.buffers.empty()) {
918 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
919 inSize = rView.capacity();
920 if (inSize && rView.error()) {
921 ALOGE("read view map failed %d", rView.error());
922 work->result = C2_CORRUPTED;
923 return;
924 }
925 }
926 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
927 bool hasPicture = false;
928
929 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
930 inSize, (int)work->input.ordinal.timestamp.peeku(),
931 (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
932 size_t inPos = 0;
933 while (inPos < inSize) {
934 if (C2_OK != ensureDecoderState(pool)) {
935 mSignalledError = true;
936 work->workletsProcessed = 1u;
937 work->result = C2_CORRUPTED;
938 return;
939 }
940 C2GraphicView wView = mOutBlock->map().get();
941 if (wView.error()) {
942 ALOGE("graphic view map failed %d", wView.error());
943 work->result = C2_CORRUPTED;
944 return;
945 }
946
947 ivd_video_decode_ip_t s_decode_ip;
948 ivd_video_decode_op_t s_decode_op;
949 if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView,
950 inOffset + inPos, inSize - inPos, workIndex)) {
951 mSignalledError = true;
952 work->workletsProcessed = 1u;
953 work->result = C2_CORRUPTED;
954 return;
955 }
956 // If input dump is enabled, then write to file
957 DUMP_TO_FILE(mInFile, s_decode_ip.pv_stream_buffer, s_decode_ip.u4_num_Bytes);
Ray Essick24754942022-04-16 09:50:35 -0700958 nsecs_t delay = mTimeStart - mTimeEnd;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800959 (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
Ray Essick24754942022-04-16 09:50:35 -0700960
961 mTimeEnd = systemTime();
962 nsecs_t decodeTime = mTimeEnd - mTimeStart;
963 ALOGV("decodeTime=%" PRId64 " delay=%" PRId64 " numBytes=%6d ", decodeTime, delay,
Pawin Vongmasa36653902018-11-15 00:10:25 -0800964 s_decode_op.u4_num_bytes_consumed);
965 if (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_decode_op.u4_error_code) {
966 ALOGV("unsupported resolution : %dx%d", s_decode_op.u4_pic_wd, s_decode_op.u4_pic_ht);
967 drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
968 resetPlugin();
969 work->workletsProcessed = 0u;
970 mWidth = s_decode_op.u4_pic_wd;
971 mHeight = s_decode_op.u4_pic_ht;
972
973 ALOGI("Configuring decoder: mWidth %d , mHeight %d ",
974 mWidth, mHeight);
Lajos Molnar3bb81cd2019-02-20 15:10:30 -0800975 C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800976 std::vector<std::unique_ptr<C2SettingResult>> failures;
977 c2_status_t err =
978 mIntf->config({&size}, C2_MAY_BLOCK, &failures);
979 if (err == OK) {
980 work->worklets.front()->output.configUpdate.push_back(
981 C2Param::Copy(size));
982 } else {
983 ALOGE("Cannot set width and height");
984 mSignalledError = true;
985 work->workletsProcessed = 1u;
986 work->result = C2_CORRUPTED;
987 return;
988 }
989
990 if (OK != reInitDecoder()) {
991 ALOGE("Failed to reinitialize decoder");
992 mSignalledError = true;
993 work->workletsProcessed = 1u;
994 work->result = C2_CORRUPTED;
995 return;
996 }
997 continue;
998 } else if (IVD_RES_CHANGED == (s_decode_op.u4_error_code & 0xFF)) {
999 ALOGV("resolution changed");
1000 drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
1001 resetDecoder();
1002 resetPlugin();
1003 work->workletsProcessed = 0u;
1004 continue;
1005 }
1006 if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
1007 if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) {
1008 mWidth = s_decode_op.u4_pic_wd;
1009 mHeight = s_decode_op.u4_pic_ht;
1010 CHECK_EQ(0u, s_decode_op.u4_output_present);
1011
1012 ALOGI("Configuring decoder out: mWidth %d , mHeight %d ",
1013 mWidth, mHeight);
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001014 C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001015 std::vector<std::unique_ptr<C2SettingResult>> failures;
1016 c2_status_t err =
1017 mIntf->config({&size}, C2_MAY_BLOCK, &failures);
1018 if (err == OK) {
1019 work->worklets.front()->output.configUpdate.push_back(
1020 C2Param::Copy(size));
1021 } else {
1022 ALOGE("Cannot set width and height");
1023 mSignalledError = true;
1024 work->workletsProcessed = 1u;
1025 work->result = C2_CORRUPTED;
1026 return;
1027 }
1028 }
1029 }
1030
1031 (void) getSeqInfo();
1032 hasPicture |= (1 == s_decode_op.u4_frame_decoded_flag);
1033 if (s_decode_op.u4_output_present) {
1034 finishWork(s_decode_op.u4_ts, work);
1035 }
1036
1037 inPos += s_decode_op.u4_num_bytes_consumed;
1038 if (hasPicture && (inSize - inPos) != 0) {
1039 ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
1040 (int)inSize - (int)inPos);
1041 break;
1042 }
1043 }
1044
1045 if (eos) {
1046 drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
1047 mSignalledOutputEos = true;
1048 } else if (!hasPicture) {
1049 fillEmptyWork(work);
1050 }
1051}
1052
1053c2_status_t C2SoftMpeg2Dec::drainInternal(
1054 uint32_t drainMode,
1055 const std::shared_ptr<C2BlockPool> &pool,
1056 const std::unique_ptr<C2Work> &work) {
1057 if (drainMode == NO_DRAIN) {
1058 ALOGW("drain with NO_DRAIN: no-op");
1059 return C2_OK;
1060 }
1061 if (drainMode == DRAIN_CHAIN) {
1062 ALOGW("DRAIN_CHAIN not supported");
1063 return C2_OMITTED;
1064 }
1065
1066 if (OK != setFlushMode()) return C2_CORRUPTED;
1067 while (true) {
1068 if (C2_OK != ensureDecoderState(pool)) {
1069 mSignalledError = true;
1070 work->workletsProcessed = 1u;
1071 work->result = C2_CORRUPTED;
1072 return C2_CORRUPTED;
1073 }
1074 C2GraphicView wView = mOutBlock->map().get();
1075 if (wView.error()) {
1076 ALOGE("graphic view map failed %d", wView.error());
1077 return C2_CORRUPTED;
1078 }
1079 ivd_video_decode_ip_t s_decode_ip;
1080 ivd_video_decode_op_t s_decode_op;
1081 if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) {
1082 mSignalledError = true;
1083 work->workletsProcessed = 1u;
1084 return C2_CORRUPTED;
1085 }
1086 (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
1087 if (s_decode_op.u4_output_present) {
1088 finishWork(s_decode_op.u4_ts, work);
1089 } else {
1090 fillEmptyWork(work);
1091 break;
1092 }
1093 }
1094
1095 return C2_OK;
1096}
1097
1098c2_status_t C2SoftMpeg2Dec::drain(
1099 uint32_t drainMode,
1100 const std::shared_ptr<C2BlockPool> &pool) {
1101 return drainInternal(drainMode, pool, nullptr);
1102}
1103
1104class C2SoftMpeg2DecFactory : public C2ComponentFactory {
1105public:
1106 C2SoftMpeg2DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1107 GetCodec2PlatformComponentStore()->getParamReflector())) {
1108 }
1109
1110 virtual c2_status_t createComponent(
1111 c2_node_id_t id,
1112 std::shared_ptr<C2Component>* const component,
1113 std::function<void(C2Component*)> deleter) override {
1114 *component = std::shared_ptr<C2Component>(
1115 new C2SoftMpeg2Dec(COMPONENT_NAME,
1116 id,
1117 std::make_shared<C2SoftMpeg2Dec::IntfImpl>(mHelper)),
1118 deleter);
1119 return C2_OK;
1120 }
1121
1122 virtual c2_status_t createInterface(
1123 c2_node_id_t id,
1124 std::shared_ptr<C2ComponentInterface>* const interface,
1125 std::function<void(C2ComponentInterface*)> deleter) override {
1126 *interface = std::shared_ptr<C2ComponentInterface>(
1127 new SimpleInterface<C2SoftMpeg2Dec::IntfImpl>(
1128 COMPONENT_NAME, id, std::make_shared<C2SoftMpeg2Dec::IntfImpl>(mHelper)),
1129 deleter);
1130 return C2_OK;
1131 }
1132
1133 virtual ~C2SoftMpeg2DecFactory() override = default;
1134
1135private:
1136 std::shared_ptr<C2ReflectorHelper> mHelper;
1137};
1138
1139} // namespace android
1140
Cindy Zhouf6c0c3c2020-12-02 10:53:40 -08001141__attribute__((cfi_canonical_jump_table))
Pawin Vongmasa36653902018-11-15 00:10:25 -08001142extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
1143 ALOGV("in %s", __func__);
1144 return new ::android::C2SoftMpeg2DecFactory();
1145}
1146
Cindy Zhouf6c0c3c2020-12-02 10:53:40 -08001147__attribute__((cfi_canonical_jump_table))
Pawin Vongmasa36653902018-11-15 00:10:25 -08001148extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
1149 ALOGV("in %s", __func__);
1150 delete factory;
1151}