1 /*
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"
19 #ifndef KEEP_THREADS_ACTIVE
20 #define KEEP_THREADS_ACTIVE 0
21 #endif
22 #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
34 namespace android {
35 constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
36 constexpr size_t kMaxDimension = 1920;
37 constexpr char COMPONENT_NAME[] = "c2.android.mpeg2.decoder";
38
39 class C2SoftMpeg2Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
40 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)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
54 // TODO: Proper support for reorder depth.
55 addParameter(
56 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
57 .withConstValue(new C2PortActualDelayTuning::output(3u))
58 .build());
59
60 // 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({
71 C2F(mSize, width).inRange(16, kMaxDimension, 2),
72 C2F(mSize, height).inRange(16, kMaxDimension, 2),
73 })
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({
98 C2F(mSize, width).inRange(2, kMaxDimension, 2),
99 C2F(mSize, height).inRange(2, kMaxDimension, 2),
100 })
101 .withSetter(MaxPictureSizeSetter, mSize)
102 .build());
103
104 addParameter(
105 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
106 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
107 .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
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2StreamPictureSizeInfo::output> & me)192 static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
193 C2P<C2StreamPictureSizeInfo::output> &me) {
194 (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
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)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
211 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);
213 return C2R::Ok();
214 }
215
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)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
220 me.set().value = c2_max((((maxSize.v.width + 15) / 16)
221 * ((maxSize.v.height + 15) / 16) * 384), kMinInputBufferSize);
222 return C2R::Ok();
223 }
224
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)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
DefaultColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsTuning::output> & me)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
CodedColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::input> & me)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
ColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::output> & me,const C2P<C2StreamColorAspectsTuning::output> & def,const C2P<C2StreamColorAspectsInfo::input> & coded)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
getColorAspects_l()281 std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() {
282 return mColorAspects;
283 }
284
285 private:
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
getCpuCoreCount()297 static 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
ivd_aligned_malloc(WORD32 alignment,WORD32 size)310 static void *ivd_aligned_malloc(WORD32 alignment, WORD32 size) {
311 return memalign(alignment, size);
312 }
313
ivd_aligned_free(void * mem)314 static void ivd_aligned_free(void *mem) {
315 free(mem);
316 }
317
C2SoftMpeg2Dec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)318 C2SoftMpeg2Dec::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),
329 mHeight(240),
330 mOutIndex(0u) {
331 // If input dump is enabled, then open create an empty file
332 GENERATE_FILE_NAMES();
333 CREATE_DUMP_FILE(mInFile);
334 }
335
~C2SoftMpeg2Dec()336 C2SoftMpeg2Dec::~C2SoftMpeg2Dec() {
337 onRelease();
338 }
339
onInit()340 c2_status_t C2SoftMpeg2Dec::onInit() {
341 status_t err = initDecoder();
342 return err == OK ? C2_OK : C2_CORRUPTED;
343 }
344
onStop()345 c2_status_t C2SoftMpeg2Dec::onStop() {
346 if (OK != resetDecoder()) return C2_CORRUPTED;
347 resetPlugin();
348 return C2_OK;
349 }
350
onReset()351 void C2SoftMpeg2Dec::onReset() {
352 (void) onStop();
353 }
354
onRelease()355 void 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
onFlush_sm()370 c2_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
getNumMemRecords()402 status_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
fillMemRecords()422 status_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;
439 s_fill_mem_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
440 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
createDecoder()470 status_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;
481 s_init_ip.u4_keep_threads_active = KEEP_THREADS_ACTIVE;
482 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
setNumCores()502 status_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
setParams(size_t stride)522 status_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
getVersion()545 status_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
initDecoder()570 status_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);
580 mStride = ALIGN128(mWidth);
581 mSignalledError = false;
582 resetPlugin();
583 (void) setNumCores();
584 if (OK != setParams(mStride)) return UNKNOWN_ERROR;
585 (void) getVersion();
586
587 return OK;
588 }
589
setDecodeArgs(ivd_video_decode_ip_t * ps_decode_ip,ivd_video_decode_op_t * ps_decode_op,C2ReadView * inBuffer,C2GraphicView * outBuffer,size_t inOffset,size_t inSize,uint32_t tsMarker)590 bool 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;
598 if (outBuffer) {
599 C2PlanarLayout layout;
600 layout = outBuffer->layout();
601 displayStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
602 }
603 uint32_t displayHeight = mHeight;
604 size_t lumaSize = displayStride * displayHeight;
605 size_t chromaSize = lumaSize >> 2;
606
607 if (mStride != displayStride) {
608 mStride = displayStride;
609 if (OK != setParams(mStride)) return false;
610 }
611
612 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) {
627 if (outBuffer->height() < displayHeight) {
628 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
getSeqInfo()647 bool 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
setFlushMode()696 status_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
resetDecoder()715 status_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
resetPlugin()737 void C2SoftMpeg2Dec::resetPlugin() {
738 mSignalledOutputEos = false;
739 mTimeStart = mTimeEnd = systemTime();
740 if (mOutBlock) {
741 mOutBlock.reset();
742 }
743 }
744
deleteDecoder()745 status_t C2SoftMpeg2Dec::deleteDecoder() {
746 if (mMemRecords) {
747 iv_mem_rec_t *ps_mem_rec = mMemRecords;
748
749 for (size_t i = 0; i < mNumMemRecords; i++, ps_mem_rec++) {
750 if (ps_mem_rec->pv_base) {
751 ivd_aligned_free(ps_mem_rec->pv_base);
752 }
753 }
754 ivd_aligned_free(mMemRecords);
755 mMemRecords = nullptr;
756 }
757 mDecHandle = nullptr;
758
759 return OK;
760 }
761
reInitDecoder()762 status_t C2SoftMpeg2Dec::reInitDecoder() {
763 deleteDecoder();
764
765 status_t ret = initDecoder();
766 if (OK != ret) {
767 ALOGE("Failed to initialize decoder");
768 deleteDecoder();
769 return ret;
770 }
771 return OK;
772 }
773
fillEmptyWork(const std::unique_ptr<C2Work> & work)774 void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
775 uint32_t flags = 0;
776 if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
777 flags |= C2FrameData::FLAG_END_OF_STREAM;
778 ALOGV("signalling eos");
779 }
780 work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
781 work->worklets.front()->output.buffers.clear();
782 work->worklets.front()->output.ordinal = work->input.ordinal;
783 work->workletsProcessed = 1u;
784 }
785
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work)786 void C2SoftMpeg2Dec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
787 std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock),
788 C2Rect(mWidth, mHeight));
789 mOutBlock = nullptr;
790 {
791 IntfImpl::Lock lock = mIntf->lock();
792 buffer->setInfo(mIntf->getColorAspects_l());
793 }
794
795 class FillWork {
796 public:
797 FillWork(uint32_t flags, C2WorkOrdinalStruct ordinal,
798 const std::shared_ptr<C2Buffer>& buffer)
799 : mFlags(flags), mOrdinal(ordinal), mBuffer(buffer) {}
800 ~FillWork() = default;
801
802 void operator()(const std::unique_ptr<C2Work>& work) {
803 work->worklets.front()->output.flags = (C2FrameData::flags_t)mFlags;
804 work->worklets.front()->output.buffers.clear();
805 work->worklets.front()->output.ordinal = mOrdinal;
806 work->workletsProcessed = 1u;
807 work->result = C2_OK;
808 if (mBuffer) {
809 work->worklets.front()->output.buffers.push_back(mBuffer);
810 }
811 ALOGV("timestamp = %lld, index = %lld, w/%s buffer",
812 mOrdinal.timestamp.peekll(), mOrdinal.frameIndex.peekll(),
813 mBuffer ? "" : "o");
814 }
815
816 private:
817 const uint32_t mFlags;
818 const C2WorkOrdinalStruct mOrdinal;
819 const std::shared_ptr<C2Buffer> mBuffer;
820 };
821
822 auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
823 work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
824 work->worklets.front()->output.buffers.clear();
825 work->worklets.front()->output.buffers.push_back(buffer);
826 work->worklets.front()->output.ordinal = work->input.ordinal;
827 work->workletsProcessed = 1u;
828 };
829 if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
830 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
831 // TODO: Check if cloneAndSend can be avoided by tracking number of frames remaining
832 if (eos) {
833 if (buffer) {
834 mOutIndex = index;
835 C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
836 cloneAndSend(
837 mOutIndex, work,
838 FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
839 buffer.reset();
840 }
841 } else {
842 fillWork(work);
843 }
844 } else {
845 finish(index, fillWork);
846 }
847 }
848
ensureDecoderState(const std::shared_ptr<C2BlockPool> & pool)849 c2_status_t C2SoftMpeg2Dec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
850 if (!mDecHandle) {
851 ALOGE("not supposed to be here, invalid decoder context");
852 return C2_CORRUPTED;
853 }
854 if (mOutBlock &&
855 (mOutBlock->width() != ALIGN128(mWidth) || mOutBlock->height() != mHeight)) {
856 mOutBlock.reset();
857 }
858 if (!mOutBlock) {
859 uint32_t format = HAL_PIXEL_FORMAT_YV12;
860 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
861 c2_status_t err =
862 pool->fetchGraphicBlock(ALIGN128(mWidth), mHeight, format, usage, &mOutBlock);
863 if (err != C2_OK) {
864 ALOGE("fetchGraphicBlock for Output failed with status %d", err);
865 return err;
866 }
867 ALOGV("provided (%dx%d) required (%dx%d)",
868 mOutBlock->width(), mOutBlock->height(), ALIGN128(mWidth), mHeight);
869 }
870
871 return C2_OK;
872 }
873
874 // TODO: can overall error checking be improved?
875 // TODO: allow configuration of color format and usage for graphic buffers instead
876 // of hard coding them to HAL_PIXEL_FORMAT_YV12
877 // TODO: pass coloraspects information to surface
878 // TODO: test support for dynamic change in resolution
879 // TODO: verify if the decoder sent back all frames
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)880 void C2SoftMpeg2Dec::process(
881 const std::unique_ptr<C2Work> &work,
882 const std::shared_ptr<C2BlockPool> &pool) {
883 // Initialize output work
884 work->result = C2_OK;
885 work->workletsProcessed = 0u;
886 work->worklets.front()->output.configUpdate.clear();
887 work->worklets.front()->output.flags = work->input.flags;
888
889 if (mSignalledError || mSignalledOutputEos) {
890 work->result = C2_BAD_VALUE;
891 return;
892 }
893
894 size_t inOffset = 0u;
895 size_t inSize = 0u;
896 uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
897 C2ReadView rView = mDummyReadView;
898 if (!work->input.buffers.empty()) {
899 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
900 inSize = rView.capacity();
901 if (inSize && rView.error()) {
902 ALOGE("read view map failed %d", rView.error());
903 work->result = C2_CORRUPTED;
904 return;
905 }
906 }
907 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
908 bool hasPicture = false;
909
910 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
911 inSize, (int)work->input.ordinal.timestamp.peeku(),
912 (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
913 size_t inPos = 0;
914 while (inPos < inSize) {
915 if (C2_OK != ensureDecoderState(pool)) {
916 mSignalledError = true;
917 work->workletsProcessed = 1u;
918 work->result = C2_CORRUPTED;
919 return;
920 }
921 C2GraphicView wView = mOutBlock->map().get();
922 if (wView.error()) {
923 ALOGE("graphic view map failed %d", wView.error());
924 work->result = C2_CORRUPTED;
925 return;
926 }
927
928 ivd_video_decode_ip_t s_decode_ip;
929 ivd_video_decode_op_t s_decode_op;
930 if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView,
931 inOffset + inPos, inSize - inPos, workIndex)) {
932 mSignalledError = true;
933 work->workletsProcessed = 1u;
934 work->result = C2_CORRUPTED;
935 return;
936 }
937 // If input dump is enabled, then write to file
938 DUMP_TO_FILE(mInFile, s_decode_ip.pv_stream_buffer, s_decode_ip.u4_num_Bytes);
939 nsecs_t delay = mTimeStart - mTimeEnd;
940 (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
941
942 mTimeEnd = systemTime();
943 nsecs_t decodeTime = mTimeEnd - mTimeStart;
944 ALOGV("decodeTime=%" PRId64 " delay=%" PRId64 " numBytes=%6d ", decodeTime, delay,
945 s_decode_op.u4_num_bytes_consumed);
946 if (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_decode_op.u4_error_code) {
947 ALOGV("unsupported resolution : %dx%d", s_decode_op.u4_pic_wd, s_decode_op.u4_pic_ht);
948 drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
949 resetPlugin();
950 work->workletsProcessed = 0u;
951 mWidth = s_decode_op.u4_pic_wd;
952 mHeight = s_decode_op.u4_pic_ht;
953
954 ALOGI("Configuring decoder: mWidth %d , mHeight %d ",
955 mWidth, mHeight);
956 C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
957 std::vector<std::unique_ptr<C2SettingResult>> failures;
958 c2_status_t err =
959 mIntf->config({&size}, C2_MAY_BLOCK, &failures);
960 if (err == OK) {
961 work->worklets.front()->output.configUpdate.push_back(
962 C2Param::Copy(size));
963 } else {
964 ALOGE("Cannot set width and height");
965 mSignalledError = true;
966 work->workletsProcessed = 1u;
967 work->result = C2_CORRUPTED;
968 return;
969 }
970
971 if (OK != reInitDecoder()) {
972 ALOGE("Failed to reinitialize decoder");
973 mSignalledError = true;
974 work->workletsProcessed = 1u;
975 work->result = C2_CORRUPTED;
976 return;
977 }
978 continue;
979 } else if (IVD_RES_CHANGED == (s_decode_op.u4_error_code & 0xFF)) {
980 ALOGV("resolution changed");
981 drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
982 resetDecoder();
983 resetPlugin();
984 work->workletsProcessed = 0u;
985 continue;
986 }
987 if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
988 if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) {
989 mWidth = s_decode_op.u4_pic_wd;
990 mHeight = s_decode_op.u4_pic_ht;
991 CHECK_EQ(0u, s_decode_op.u4_output_present);
992
993 ALOGI("Configuring decoder out: mWidth %d , mHeight %d ",
994 mWidth, mHeight);
995 C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
996 std::vector<std::unique_ptr<C2SettingResult>> failures;
997 c2_status_t err =
998 mIntf->config({&size}, C2_MAY_BLOCK, &failures);
999 if (err == OK) {
1000 work->worklets.front()->output.configUpdate.push_back(
1001 C2Param::Copy(size));
1002 } else {
1003 ALOGE("Cannot set width and height");
1004 mSignalledError = true;
1005 work->workletsProcessed = 1u;
1006 work->result = C2_CORRUPTED;
1007 return;
1008 }
1009 }
1010 }
1011
1012 (void) getSeqInfo();
1013 hasPicture |= (1 == s_decode_op.u4_frame_decoded_flag);
1014 if (s_decode_op.u4_output_present) {
1015 finishWork(s_decode_op.u4_ts, work);
1016 }
1017
1018 inPos += s_decode_op.u4_num_bytes_consumed;
1019 if (hasPicture && (inSize - inPos) != 0) {
1020 ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
1021 (int)inSize - (int)inPos);
1022 break;
1023 }
1024 }
1025
1026 if (eos) {
1027 drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
1028 mSignalledOutputEos = true;
1029 } else if (!hasPicture) {
1030 fillEmptyWork(work);
1031 }
1032 }
1033
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)1034 c2_status_t C2SoftMpeg2Dec::drainInternal(
1035 uint32_t drainMode,
1036 const std::shared_ptr<C2BlockPool> &pool,
1037 const std::unique_ptr<C2Work> &work) {
1038 if (drainMode == NO_DRAIN) {
1039 ALOGW("drain with NO_DRAIN: no-op");
1040 return C2_OK;
1041 }
1042 if (drainMode == DRAIN_CHAIN) {
1043 ALOGW("DRAIN_CHAIN not supported");
1044 return C2_OMITTED;
1045 }
1046
1047 if (OK != setFlushMode()) return C2_CORRUPTED;
1048 while (true) {
1049 if (C2_OK != ensureDecoderState(pool)) {
1050 mSignalledError = true;
1051 work->workletsProcessed = 1u;
1052 work->result = C2_CORRUPTED;
1053 return C2_CORRUPTED;
1054 }
1055 C2GraphicView wView = mOutBlock->map().get();
1056 if (wView.error()) {
1057 ALOGE("graphic view map failed %d", wView.error());
1058 return C2_CORRUPTED;
1059 }
1060 ivd_video_decode_ip_t s_decode_ip;
1061 ivd_video_decode_op_t s_decode_op;
1062 if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) {
1063 mSignalledError = true;
1064 work->workletsProcessed = 1u;
1065 return C2_CORRUPTED;
1066 }
1067 (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
1068 if (s_decode_op.u4_output_present) {
1069 finishWork(s_decode_op.u4_ts, work);
1070 } else {
1071 fillEmptyWork(work);
1072 break;
1073 }
1074 }
1075
1076 return C2_OK;
1077 }
1078
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)1079 c2_status_t C2SoftMpeg2Dec::drain(
1080 uint32_t drainMode,
1081 const std::shared_ptr<C2BlockPool> &pool) {
1082 return drainInternal(drainMode, pool, nullptr);
1083 }
1084
1085 class C2SoftMpeg2DecFactory : public C2ComponentFactory {
1086 public:
C2SoftMpeg2DecFactory()1087 C2SoftMpeg2DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1088 GetCodec2PlatformComponentStore()->getParamReflector())) {
1089 }
1090
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)1091 virtual c2_status_t createComponent(
1092 c2_node_id_t id,
1093 std::shared_ptr<C2Component>* const component,
1094 std::function<void(C2Component*)> deleter) override {
1095 *component = std::shared_ptr<C2Component>(
1096 new C2SoftMpeg2Dec(COMPONENT_NAME,
1097 id,
1098 std::make_shared<C2SoftMpeg2Dec::IntfImpl>(mHelper)),
1099 deleter);
1100 return C2_OK;
1101 }
1102
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)1103 virtual c2_status_t createInterface(
1104 c2_node_id_t id,
1105 std::shared_ptr<C2ComponentInterface>* const interface,
1106 std::function<void(C2ComponentInterface*)> deleter) override {
1107 *interface = std::shared_ptr<C2ComponentInterface>(
1108 new SimpleInterface<C2SoftMpeg2Dec::IntfImpl>(
1109 COMPONENT_NAME, id, std::make_shared<C2SoftMpeg2Dec::IntfImpl>(mHelper)),
1110 deleter);
1111 return C2_OK;
1112 }
1113
1114 virtual ~C2SoftMpeg2DecFactory() override = default;
1115
1116 private:
1117 std::shared_ptr<C2ReflectorHelper> mHelper;
1118 };
1119
1120 } // namespace android
1121
1122 __attribute__((cfi_canonical_jump_table))
CreateCodec2Factory()1123 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
1124 ALOGV("in %s", __func__);
1125 return new ::android::C2SoftMpeg2DecFactory();
1126 }
1127
1128 __attribute__((cfi_canonical_jump_table))
DestroyCodec2Factory(::C2ComponentFactory * factory)1129 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
1130 ALOGV("in %s", __func__);
1131 delete factory;
1132 }
1133