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 #include <log/log.h>
20
21 #include <android_media_swcodec_flags.h>
22
23 #include <media/stagefright/foundation/MediaDefs.h>
24
25 #include <C2Debug.h>
26 #include <C2PlatformSupport.h>
27 #include <Codec2Mapper.h>
28 #include <SimpleC2Interface.h>
29
30 #include "C2SoftMpeg2Dec.h"
31 #include "impeg2d.h"
32
33 namespace android {
34 constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
35 constexpr size_t kMaxDimension = 1920;
36 constexpr char COMPONENT_NAME[] = "c2.android.mpeg2.decoder";
37
38 class C2SoftMpeg2Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
39 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)40 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
41 : SimpleInterface<void>::BaseParams(
42 helper,
43 COMPONENT_NAME,
44 C2Component::KIND_DECODER,
45 C2Component::DOMAIN_VIDEO,
46 MEDIA_MIMETYPE_VIDEO_MPEG2) {
47 noPrivateBuffers(); // TODO: account for our buffers here
48 noInputReferences();
49 noOutputReferences();
50 noInputLatency();
51 noTimeStretch();
52
53 // TODO: Proper support for reorder depth.
54 addParameter(
55 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
56 .withConstValue(new C2PortActualDelayTuning::output(3u))
57 .build());
58
59 // TODO: output latency and reordering
60
61 addParameter(
62 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
63 .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
64 .build());
65
66 addParameter(
67 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
68 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
69 .withFields({
70 C2F(mSize, width).inRange(16, kMaxDimension, 2),
71 C2F(mSize, height).inRange(16, kMaxDimension, 2),
72 })
73 .withSetter(SizeSetter)
74 .build());
75
76 addParameter(
77 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
78 .withDefault(new C2StreamProfileLevelInfo::input(0u,
79 C2Config::PROFILE_MP2V_SIMPLE, C2Config::LEVEL_MP2V_HIGH))
80 .withFields({
81 C2F(mProfileLevel, profile).oneOf({
82 C2Config::PROFILE_MP2V_SIMPLE,
83 C2Config::PROFILE_MP2V_MAIN}),
84 C2F(mProfileLevel, level).oneOf({
85 C2Config::LEVEL_MP2V_LOW,
86 C2Config::LEVEL_MP2V_MAIN,
87 C2Config::LEVEL_MP2V_HIGH_1440,
88 C2Config::LEVEL_MP2V_HIGH})
89 })
90 .withSetter(ProfileLevelSetter, mSize)
91 .build());
92
93 addParameter(
94 DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
95 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
96 .withFields({
97 C2F(mSize, width).inRange(2, kMaxDimension, 2),
98 C2F(mSize, height).inRange(2, kMaxDimension, 2),
99 })
100 .withSetter(MaxPictureSizeSetter, mSize)
101 .build());
102
103 addParameter(
104 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
105 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
106 .withFields({
107 C2F(mMaxInputSize, value).any(),
108 })
109 .calculatedAs(MaxInputSizeSetter, mMaxSize)
110 .build());
111
112 C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
113 std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
114 C2StreamColorInfo::output::AllocShared(
115 1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
116 memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
117
118 defaultColorInfo =
119 C2StreamColorInfo::output::AllocShared(
120 { C2ChromaOffsetStruct::ITU_YUV_420_0() },
121 0u, 8u /* bitDepth */, C2Color::YUV_420);
122 helper->addStructDescriptors<C2ChromaOffsetStruct>();
123
124 addParameter(
125 DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
126 .withConstValue(defaultColorInfo)
127 .build());
128
129 addParameter(
130 DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
131 .withDefault(new C2StreamColorAspectsTuning::output(
132 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
133 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
134 .withFields({
135 C2F(mDefaultColorAspects, range).inRange(
136 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
137 C2F(mDefaultColorAspects, primaries).inRange(
138 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
139 C2F(mDefaultColorAspects, transfer).inRange(
140 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
141 C2F(mDefaultColorAspects, matrix).inRange(
142 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
143 })
144 .withSetter(DefaultColorAspectsSetter)
145 .build());
146
147 addParameter(
148 DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
149 .withDefault(new C2StreamColorAspectsInfo::input(
150 0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
151 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
152 .withFields({
153 C2F(mCodedColorAspects, range).inRange(
154 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
155 C2F(mCodedColorAspects, primaries).inRange(
156 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
157 C2F(mCodedColorAspects, transfer).inRange(
158 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
159 C2F(mCodedColorAspects, matrix).inRange(
160 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
161 })
162 .withSetter(CodedColorAspectsSetter)
163 .build());
164
165 addParameter(
166 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
167 .withDefault(new C2StreamColorAspectsInfo::output(
168 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
169 C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
170 .withFields({
171 C2F(mColorAspects, range).inRange(
172 C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
173 C2F(mColorAspects, primaries).inRange(
174 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
175 C2F(mColorAspects, transfer).inRange(
176 C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
177 C2F(mColorAspects, matrix).inRange(
178 C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
179 })
180 .withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects)
181 .build());
182
183 // TODO: support more formats?
184 addParameter(
185 DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
186 .withConstValue(new C2StreamPixelFormatInfo::output(
187 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
188 .build());
189 }
190
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2StreamPictureSizeInfo::output> & me)191 static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
192 C2P<C2StreamPictureSizeInfo::output> &me) {
193 (void)mayBlock;
194 C2R res = C2R::Ok();
195 if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
196 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
197 me.set().width = oldMe.v.width;
198 }
199 if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
200 res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
201 me.set().height = oldMe.v.height;
202 }
203 return res;
204 }
205
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)206 static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
207 const C2P<C2StreamPictureSizeInfo::output> &size) {
208 (void)mayBlock;
209 // TODO: get max width/height from the size's field helpers vs. hardcoding
210 me.set().width = c2_min(c2_max(me.v.width, size.v.width), kMaxDimension);
211 me.set().height = c2_min(c2_max(me.v.height, size.v.height), kMaxDimension);
212 return C2R::Ok();
213 }
214
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)215 static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
216 const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
217 (void)mayBlock;
218 // assume compression ratio of 1
219 me.set().value = c2_max((((maxSize.v.width + 15) / 16)
220 * ((maxSize.v.height + 15) / 16) * 384), kMinInputBufferSize);
221 return C2R::Ok();
222 }
223
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)224 static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
225 const C2P<C2StreamPictureSizeInfo::output> &size) {
226 (void)mayBlock;
227 (void)size;
228 (void)me; // TODO: validate
229 return C2R::Ok();
230 }
231
DefaultColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsTuning::output> & me)232 static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
233 (void)mayBlock;
234 if (me.v.range > C2Color::RANGE_OTHER) {
235 me.set().range = C2Color::RANGE_OTHER;
236 }
237 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
238 me.set().primaries = C2Color::PRIMARIES_OTHER;
239 }
240 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
241 me.set().transfer = C2Color::TRANSFER_OTHER;
242 }
243 if (me.v.matrix > C2Color::MATRIX_OTHER) {
244 me.set().matrix = C2Color::MATRIX_OTHER;
245 }
246 return C2R::Ok();
247 }
248
CodedColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::input> & me)249 static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) {
250 (void)mayBlock;
251 if (me.v.range > C2Color::RANGE_OTHER) {
252 me.set().range = C2Color::RANGE_OTHER;
253 }
254 if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
255 me.set().primaries = C2Color::PRIMARIES_OTHER;
256 }
257 if (me.v.transfer > C2Color::TRANSFER_OTHER) {
258 me.set().transfer = C2Color::TRANSFER_OTHER;
259 }
260 if (me.v.matrix > C2Color::MATRIX_OTHER) {
261 me.set().matrix = C2Color::MATRIX_OTHER;
262 }
263 return C2R::Ok();
264 }
265
ColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::output> & me,const C2P<C2StreamColorAspectsTuning::output> & def,const C2P<C2StreamColorAspectsInfo::input> & coded)266 static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
267 const C2P<C2StreamColorAspectsTuning::output> &def,
268 const C2P<C2StreamColorAspectsInfo::input> &coded) {
269 (void)mayBlock;
270 // take default values for all unspecified fields, and coded values for specified ones
271 me.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
272 me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED
273 ? def.v.primaries : coded.v.primaries;
274 me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED
275 ? def.v.transfer : coded.v.transfer;
276 me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix;
277 return C2R::Ok();
278 }
279
getColorAspects_l()280 std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() {
281 return mColorAspects;
282 }
283
284 private:
285 std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
286 std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
287 std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
288 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
289 std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
290 std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
291 std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
292 std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
293 std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
294 };
295
getCpuCoreCount()296 static size_t getCpuCoreCount() {
297 long cpuCoreCount = 1;
298 #if defined(_SC_NPROCESSORS_ONLN)
299 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
300 #else
301 // _SC_NPROC_ONLN must be defined...
302 cpuCoreCount = sysconf(_SC_NPROC_ONLN);
303 #endif
304 CHECK(cpuCoreCount >= 1);
305 ALOGV("Number of CPU cores: %ld", cpuCoreCount);
306 return (size_t)cpuCoreCount;
307 }
308
ivd_aligned_malloc(WORD32 alignment,WORD32 size)309 static void *ivd_aligned_malloc(WORD32 alignment, WORD32 size) {
310 return memalign(alignment, size);
311 }
312
ivd_aligned_free(void * mem)313 static void ivd_aligned_free(void *mem) {
314 free(mem);
315 }
316
C2SoftMpeg2Dec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)317 C2SoftMpeg2Dec::C2SoftMpeg2Dec(
318 const char *name,
319 c2_node_id_t id,
320 const std::shared_ptr<IntfImpl> &intfImpl)
321 : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
322 mIntf(intfImpl) {
323 // If input dump is enabled, then open create an empty file
324 GENERATE_FILE_NAMES();
325 CREATE_DUMP_FILE(mInFile);
326 }
327
C2SoftMpeg2Dec(const char * name,c2_node_id_t id,const std::shared_ptr<C2ReflectorHelper> & helper)328 C2SoftMpeg2Dec::C2SoftMpeg2Dec(
329 const char *name,
330 c2_node_id_t id,
331 const std::shared_ptr<C2ReflectorHelper> &helper)
332 : C2SoftMpeg2Dec(name, id, std::make_shared<IntfImpl>(helper)) {
333 }
334
~C2SoftMpeg2Dec()335 C2SoftMpeg2Dec::~C2SoftMpeg2Dec() {
336 onRelease();
337 }
338
onInit()339 c2_status_t C2SoftMpeg2Dec::onInit() {
340 status_t err = initDecoder();
341 return err == OK ? C2_OK : C2_CORRUPTED;
342 }
343
onStop()344 c2_status_t C2SoftMpeg2Dec::onStop() {
345 if (OK != resetDecoder()) return C2_CORRUPTED;
346 resetPlugin();
347 return C2_OK;
348 }
349
onReset()350 void C2SoftMpeg2Dec::onReset() {
351 (void) onStop();
352 }
353
onRelease()354 void C2SoftMpeg2Dec::onRelease() {
355 (void) deleteDecoder();
356 if (mOutBufferDrain) {
357 ivd_aligned_free(mOutBufferDrain);
358 mOutBufferDrain = nullptr;
359 }
360 if (mOutBlock) {
361 mOutBlock.reset();
362 }
363 if (mMemRecords) {
364 ivd_aligned_free(mMemRecords);
365 mMemRecords = nullptr;
366 }
367 }
368
onFlush_sm()369 c2_status_t C2SoftMpeg2Dec::onFlush_sm() {
370 if (OK != setFlushMode()) return C2_CORRUPTED;
371
372 uint32_t displayStride = mStride;
373 uint32_t displayHeight = mHeight;
374 uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
375 mOutBufferDrain = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
376 if (!mOutBufferDrain) {
377 ALOGE("could not allocate tmp output buffer (for flush) of size %u ", bufferSize);
378 return C2_NO_MEMORY;
379 }
380
381 while (true) {
382 ivd_video_decode_ip_t s_decode_ip;
383 ivd_video_decode_op_t s_decode_op;
384
385 setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, nullptr, 0, 0, 0);
386 (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
387 if (0 == s_decode_op.u4_output_present) {
388 resetPlugin();
389 break;
390 }
391 }
392
393 if (mOutBufferDrain) {
394 ivd_aligned_free(mOutBufferDrain);
395 mOutBufferDrain = nullptr;
396 }
397
398 return C2_OK;
399 }
400
getNumMemRecords()401 status_t C2SoftMpeg2Dec::getNumMemRecords() {
402 iv_num_mem_rec_ip_t s_num_mem_rec_ip;
403 iv_num_mem_rec_op_t s_num_mem_rec_op;
404
405 s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
406 s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
407 s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
408
409 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
410 &s_num_mem_rec_ip,
411 &s_num_mem_rec_op);
412 if (IV_SUCCESS != status) {
413 ALOGE("Error in getting mem records: 0x%x", s_num_mem_rec_op.u4_error_code);
414 return UNKNOWN_ERROR;
415 }
416 mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
417
418 return OK;
419 }
420
fillMemRecords()421 status_t C2SoftMpeg2Dec::fillMemRecords() {
422 iv_mem_rec_t *ps_mem_rec = (iv_mem_rec_t *) ivd_aligned_malloc(
423 128, mNumMemRecords * sizeof(iv_mem_rec_t));
424 if (!ps_mem_rec) {
425 ALOGE("Allocation failure");
426 return NO_MEMORY;
427 }
428 memset(ps_mem_rec, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
429 for (size_t i = 0; i < mNumMemRecords; i++)
430 ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
431 mMemRecords = ps_mem_rec;
432
433 ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
434 ivdext_fill_mem_rec_op_t s_fill_mem_op;
435
436 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size = sizeof(ivdext_fill_mem_rec_ip_t);
437 s_fill_mem_ip.u4_share_disp_buf = 0;
438 s_fill_mem_ip.u4_keep_threads_active = mKeepThreadsActive;
439 s_fill_mem_ip.e_output_format = mIvColorformat;
440 s_fill_mem_ip.u4_deinterlace = 1;
441 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
442 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
443 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth;
444 s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight;
445 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size = sizeof(ivdext_fill_mem_rec_op_t);
446 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
447 &s_fill_mem_ip,
448 &s_fill_mem_op);
449 if (IV_SUCCESS != status) {
450 ALOGE("Error in filling mem records: 0x%x",
451 s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
452 return UNKNOWN_ERROR;
453 }
454
455 CHECK_EQ(mNumMemRecords, s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled);
456 for (size_t i = 0; i < mNumMemRecords; i++, ps_mem_rec++) {
457 ps_mem_rec->pv_base = ivd_aligned_malloc(
458 ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
459 if (!ps_mem_rec->pv_base) {
460 ALOGE("Allocation failure for memory record #%zu of size %u",
461 i, ps_mem_rec->u4_mem_size);
462 return NO_MEMORY;
463 }
464 }
465
466 return OK;
467 }
468
createDecoder()469 status_t C2SoftMpeg2Dec::createDecoder() {
470 ivdext_init_ip_t s_init_ip;
471 ivdext_init_op_t s_init_op;
472
473 s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
474 s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
475 s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
476 s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth;
477 s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
478 s_init_ip.u4_share_disp_buf = 0;
479 s_init_ip.u4_deinterlace = 1;
480 s_init_ip.u4_keep_threads_active = mKeepThreadsActive;
481 s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
482 s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorformat;
483 s_init_op.s_ivd_init_op_t.u4_size = sizeof(ivdext_init_op_t);
484
485 mDecHandle = (iv_obj_t *)mMemRecords[0].pv_base;
486 mDecHandle->pv_fxns = (void *)ivdec_api_function;
487 mDecHandle->u4_size = sizeof(iv_obj_t);
488
489 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
490 &s_init_ip,
491 &s_init_op);
492 if (status != IV_SUCCESS) {
493 ALOGE("error in %s: 0x%x", __func__,
494 s_init_op.s_ivd_init_op_t.u4_error_code);
495 return UNKNOWN_ERROR;
496 }
497
498 return OK;
499 }
500
setNumCores()501 status_t C2SoftMpeg2Dec::setNumCores() {
502 ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip;
503 ivdext_ctl_set_num_cores_op_t s_set_num_cores_op;
504
505 s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
506 s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
507 s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
508 s_set_num_cores_ip.u4_num_cores = mNumCores;
509 s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
510 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
511 &s_set_num_cores_ip,
512 &s_set_num_cores_op);
513 if (status != IV_SUCCESS) {
514 ALOGD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code);
515 return UNKNOWN_ERROR;
516 }
517
518 return OK;
519 }
520
setParams(size_t stride)521 status_t C2SoftMpeg2Dec::setParams(size_t stride) {
522 ivd_ctl_set_config_ip_t s_set_dyn_params_ip;
523 ivd_ctl_set_config_op_t s_set_dyn_params_op;
524
525 s_set_dyn_params_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
526 s_set_dyn_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
527 s_set_dyn_params_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
528 s_set_dyn_params_ip.u4_disp_wd = (UWORD32) stride;
529 s_set_dyn_params_ip.e_frm_skip_mode = IVD_SKIP_NONE;
530 s_set_dyn_params_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
531 s_set_dyn_params_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
532 s_set_dyn_params_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
533 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
534 &s_set_dyn_params_ip,
535 &s_set_dyn_params_op);
536 if (status != IV_SUCCESS) {
537 ALOGE("error in %s: 0x%x", __func__, s_set_dyn_params_op.u4_error_code);
538 return UNKNOWN_ERROR;
539 }
540
541 return OK;
542 }
543
getVersion()544 status_t C2SoftMpeg2Dec::getVersion() {
545 ivd_ctl_getversioninfo_ip_t s_get_versioninfo_ip;
546 ivd_ctl_getversioninfo_op_t s_get_versioninfo_op;
547 UWORD8 au1_buf[512];
548
549 s_get_versioninfo_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
550 s_get_versioninfo_ip.e_cmd = IVD_CMD_VIDEO_CTL;
551 s_get_versioninfo_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
552 s_get_versioninfo_ip.pv_version_buffer = au1_buf;
553 s_get_versioninfo_ip.u4_version_buffer_size = sizeof(au1_buf);
554 s_get_versioninfo_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
555 IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
556 &s_get_versioninfo_ip,
557 &s_get_versioninfo_op);
558 if (status != IV_SUCCESS) {
559 ALOGD("error in %s: 0x%x", __func__,
560 s_get_versioninfo_op.u4_error_code);
561 } else {
562 ALOGV("ittiam decoder version number: %s",
563 (char *) s_get_versioninfo_ip.pv_version_buffer);
564 }
565
566 return OK;
567 }
568
initDecoder()569 status_t C2SoftMpeg2Dec::initDecoder() {
570 status_t ret = getNumMemRecords();
571 if (OK != ret) return ret;
572
573 mKeepThreadsActive = android::media::swcodec::flags::mpeg2_keep_threads_active();
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 // 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
765 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
reInitDecoder()781 status_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
fillEmptyWork(const std::unique_ptr<C2Work> & work)793 void 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
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work)805 void 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
814 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
841 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) {
849 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 }
863 } else {
864 finish(index, fillWork);
865 }
866 }
867
ensureDecoderState(const std::shared_ptr<C2BlockPool> & pool)868 c2_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 }
873 if (mOutBlock &&
874 (mOutBlock->width() != ALIGN128(mWidth) || mOutBlock->height() != mHeight)) {
875 mOutBlock.reset();
876 }
877 if (!mOutBlock) {
878 uint32_t format = HAL_PIXEL_FORMAT_YV12;
879 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
880 c2_status_t err =
881 pool->fetchGraphicBlock(ALIGN128(mWidth), mHeight, format, usage, &mOutBlock);
882 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)",
887 mOutBlock->width(), mOutBlock->height(), ALIGN128(mWidth), mHeight);
888 }
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
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)899 void 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);
958 nsecs_t delay = mTimeStart - mTimeEnd;
959 (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
960
961 mTimeEnd = systemTime();
962 nsecs_t decodeTime = mTimeEnd - mTimeStart;
963 ALOGV("decodeTime=%" PRId64 " delay=%" PRId64 " numBytes=%6d ", decodeTime, delay,
964 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);
975 C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
976 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);
1014 C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
1015 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
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)1053 c2_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
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)1098 c2_status_t C2SoftMpeg2Dec::drain(
1099 uint32_t drainMode,
1100 const std::shared_ptr<C2BlockPool> &pool) {
1101 return drainInternal(drainMode, pool, nullptr);
1102 }
1103
1104 class C2SoftMpeg2DecFactory : public C2ComponentFactory {
1105 public:
C2SoftMpeg2DecFactory()1106 C2SoftMpeg2DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
1107 GetCodec2PlatformComponentStore()->getParamReflector())) {
1108 }
1109
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)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
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)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
1135 private:
1136 std::shared_ptr<C2ReflectorHelper> mHelper;
1137 };
1138
1139 } // namespace android
1140
1141 __attribute__((cfi_canonical_jump_table))
CreateCodec2Factory()1142 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
1143 ALOGV("in %s", __func__);
1144 return new ::android::C2SoftMpeg2DecFactory();
1145 }
1146
1147 __attribute__((cfi_canonical_jump_table))
DestroyCodec2Factory(::C2ComponentFactory * factory)1148 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
1149 ALOGV("in %s", __func__);
1150 delete factory;
1151 }
1152