1 /*
2  * Copyright 2017 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 "C2SoftAvcDec"
19 #include <log/log.h>
20 
21 #include <media/stagefright/foundation/MediaDefs.h>
22 
23 #include <C2Debug.h>
24 #include <C2PlatformSupport.h>
25 #include <Codec2Mapper.h>
26 #include <SimpleC2Interface.h>
27 
28 #include "C2SoftAvcDec.h"
29 #include "ih264d.h"
30 
31 namespace android {
32 
33 namespace {
34 
35 constexpr char COMPONENT_NAME[] = "c2.android.avc.decoder";
36 
37 }  // namespace
38 
39 class C2SoftAvcDec::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_AVC) {
48         noPrivateBuffers(); // TODO: account for our buffers here
49         noInputReferences();
50         noOutputReferences();
51         noInputLatency();
52         noTimeStretch();
53 
54         // TODO: output latency and reordering
55 
56         addParameter(
57                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
58                 .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
59                 .build());
60 
61         // coded and output picture size is the same for this codec
62         addParameter(
63                 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
64                 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
65                 .withFields({
66                     C2F(mSize, width).inRange(2, 4080, 2),
67                     C2F(mSize, height).inRange(2, 4080, 2),
68                 })
69                 .withSetter(SizeSetter)
70                 .build());
71 
72         addParameter(
73                 DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
74                 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
75                 .withFields({
76                     C2F(mSize, width).inRange(2, 4080, 2),
77                     C2F(mSize, height).inRange(2, 4080, 2),
78                 })
79                 .withSetter(MaxPictureSizeSetter, mSize)
80                 .build());
81 
82         addParameter(
83                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
84                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
85                         C2Config::PROFILE_AVC_CONSTRAINED_BASELINE, C2Config::LEVEL_AVC_5_2))
86                 .withFields({
87                     C2F(mProfileLevel, profile).oneOf({
88                             C2Config::PROFILE_AVC_CONSTRAINED_BASELINE,
89                             C2Config::PROFILE_AVC_BASELINE,
90                             C2Config::PROFILE_AVC_MAIN,
91                             C2Config::PROFILE_AVC_CONSTRAINED_HIGH,
92                             C2Config::PROFILE_AVC_PROGRESSIVE_HIGH,
93                             C2Config::PROFILE_AVC_HIGH}),
94                     C2F(mProfileLevel, level).oneOf({
95                             C2Config::LEVEL_AVC_1, C2Config::LEVEL_AVC_1B, C2Config::LEVEL_AVC_1_1,
96                             C2Config::LEVEL_AVC_1_2, C2Config::LEVEL_AVC_1_3,
97                             C2Config::LEVEL_AVC_2, C2Config::LEVEL_AVC_2_1, C2Config::LEVEL_AVC_2_2,
98                             C2Config::LEVEL_AVC_3, C2Config::LEVEL_AVC_3_1, C2Config::LEVEL_AVC_3_2,
99                             C2Config::LEVEL_AVC_4, C2Config::LEVEL_AVC_4_1, C2Config::LEVEL_AVC_4_2,
100                             C2Config::LEVEL_AVC_5, C2Config::LEVEL_AVC_5_1, C2Config::LEVEL_AVC_5_2
101                     })
102                 })
103                 .withSetter(ProfileLevelSetter, mSize)
104                 .build());
105 
106         addParameter(
107                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
108                 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
109                 .withFields({
110                     C2F(mMaxInputSize, value).any(),
111                 })
112                 .calculatedAs(MaxInputSizeSetter, mMaxSize)
113                 .build());
114 
115         C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
116         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
117             C2StreamColorInfo::output::AllocShared(
118                     1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
119         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
120 
121         defaultColorInfo =
122             C2StreamColorInfo::output::AllocShared(
123                     { C2ChromaOffsetStruct::ITU_YUV_420_0() },
124                     0u, 8u /* bitDepth */, C2Color::YUV_420);
125         helper->addStructDescriptors<C2ChromaOffsetStruct>();
126 
127         addParameter(
128                 DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
129                 .withConstValue(defaultColorInfo)
130                 .build());
131 
132         addParameter(
133                 DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
134                 .withDefault(new C2StreamColorAspectsTuning::output(
135                         0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
136                         C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
137                 .withFields({
138                     C2F(mDefaultColorAspects, range).inRange(
139                                 C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
140                     C2F(mDefaultColorAspects, primaries).inRange(
141                                 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
142                     C2F(mDefaultColorAspects, transfer).inRange(
143                                 C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
144                     C2F(mDefaultColorAspects, matrix).inRange(
145                                 C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
146                 })
147                 .withSetter(DefaultColorAspectsSetter)
148                 .build());
149 
150         addParameter(
151                 DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
152                 .withDefault(new C2StreamColorAspectsInfo::input(
153                         0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
154                         C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
155                 .withFields({
156                     C2F(mCodedColorAspects, range).inRange(
157                                 C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
158                     C2F(mCodedColorAspects, primaries).inRange(
159                                 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
160                     C2F(mCodedColorAspects, transfer).inRange(
161                                 C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
162                     C2F(mCodedColorAspects, matrix).inRange(
163                                 C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
164                 })
165                 .withSetter(CodedColorAspectsSetter)
166                 .build());
167 
168         addParameter(
169                 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
170                 .withDefault(new C2StreamColorAspectsInfo::output(
171                         0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
172                         C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
173                 .withFields({
174                     C2F(mColorAspects, range).inRange(
175                                 C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
176                     C2F(mColorAspects, primaries).inRange(
177                                 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
178                     C2F(mColorAspects, transfer).inRange(
179                                 C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
180                     C2F(mColorAspects, matrix).inRange(
181                                 C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
182                 })
183                 .withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects)
184                 .build());
185 
186         // TODO: support more formats?
187         addParameter(
188                 DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
189                 .withConstValue(new C2StreamPixelFormatInfo::output(
190                                      0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
191                 .build());
192     }
193 
SizeSetter(bool mayBlock,const C2P<C2StreamPictureSizeInfo::output> & oldMe,C2P<C2VideoSizeStreamInfo::output> & me)194     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
195                           C2P<C2VideoSizeStreamInfo::output> &me) {
196         (void)mayBlock;
197         C2R res = C2R::Ok();
198         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
199             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
200             me.set().width = oldMe.v.width;
201         }
202         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
203             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
204             me.set().height = oldMe.v.height;
205         }
206         return res;
207     }
208 
MaxPictureSizeSetter(bool mayBlock,C2P<C2StreamMaxPictureSizeTuning::output> & me,const C2P<C2StreamPictureSizeInfo::output> & size)209     static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
210                                     const C2P<C2StreamPictureSizeInfo::output> &size) {
211         (void)mayBlock;
212         // TODO: get max width/height from the size's field helpers vs. hardcoding
213         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4080u);
214         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4080u);
215         return C2R::Ok();
216     }
217 
MaxInputSizeSetter(bool mayBlock,C2P<C2StreamMaxBufferSizeInfo::input> & me,const C2P<C2StreamMaxPictureSizeTuning::output> & maxSize)218     static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
219                                   const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
220         (void)mayBlock;
221         // assume compression ratio of 2
222         me.set().value = (((maxSize.v.width + 15) / 16) * ((maxSize.v.height + 15) / 16) * 192);
223         return C2R::Ok();
224     }
225 
ProfileLevelSetter(bool mayBlock,C2P<C2StreamProfileLevelInfo::input> & me,const C2P<C2StreamPictureSizeInfo::output> & size)226     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
227                                   const C2P<C2StreamPictureSizeInfo::output> &size) {
228         (void)mayBlock;
229         (void)size;
230         (void)me;  // TODO: validate
231         return C2R::Ok();
232     }
233 
DefaultColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsTuning::output> & me)234     static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
235         (void)mayBlock;
236         if (me.v.range > C2Color::RANGE_OTHER) {
237                 me.set().range = C2Color::RANGE_OTHER;
238         }
239         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
240                 me.set().primaries = C2Color::PRIMARIES_OTHER;
241         }
242         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
243                 me.set().transfer = C2Color::TRANSFER_OTHER;
244         }
245         if (me.v.matrix > C2Color::MATRIX_OTHER) {
246                 me.set().matrix = C2Color::MATRIX_OTHER;
247         }
248         return C2R::Ok();
249     }
250 
CodedColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::input> & me)251     static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) {
252         (void)mayBlock;
253         if (me.v.range > C2Color::RANGE_OTHER) {
254                 me.set().range = C2Color::RANGE_OTHER;
255         }
256         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
257                 me.set().primaries = C2Color::PRIMARIES_OTHER;
258         }
259         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
260                 me.set().transfer = C2Color::TRANSFER_OTHER;
261         }
262         if (me.v.matrix > C2Color::MATRIX_OTHER) {
263                 me.set().matrix = C2Color::MATRIX_OTHER;
264         }
265         return C2R::Ok();
266     }
267 
ColorAspectsSetter(bool mayBlock,C2P<C2StreamColorAspectsInfo::output> & me,const C2P<C2StreamColorAspectsTuning::output> & def,const C2P<C2StreamColorAspectsInfo::input> & coded)268     static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
269                                   const C2P<C2StreamColorAspectsTuning::output> &def,
270                                   const C2P<C2StreamColorAspectsInfo::input> &coded) {
271         (void)mayBlock;
272         // take default values for all unspecified fields, and coded values for specified ones
273         me.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
274         me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED
275                 ? def.v.primaries : coded.v.primaries;
276         me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED
277                 ? def.v.transfer : coded.v.transfer;
278         me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix;
279         return C2R::Ok();
280     }
281 
getColorAspects_l()282     std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() {
283         return mColorAspects;
284     }
285 
286 private:
287     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
288     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
289     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
290     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
291     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
292     std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
293     std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
294     std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
295     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
296 };
297 
getCpuCoreCount()298 static size_t getCpuCoreCount() {
299     long cpuCoreCount = 1;
300 #if defined(_SC_NPROCESSORS_ONLN)
301     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
302 #else
303     // _SC_NPROC_ONLN must be defined...
304     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
305 #endif
306     CHECK(cpuCoreCount >= 1);
307     ALOGV("Number of CPU cores: %ld", cpuCoreCount);
308     return (size_t)cpuCoreCount;
309 }
310 
ivd_aligned_malloc(void * ctxt,WORD32 alignment,WORD32 size)311 static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
312     (void) ctxt;
313     return memalign(alignment, size);
314 }
315 
ivd_aligned_free(void * ctxt,void * mem)316 static void ivd_aligned_free(void *ctxt, void *mem) {
317     (void) ctxt;
318     free(mem);
319 }
320 
C2SoftAvcDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)321 C2SoftAvcDec::C2SoftAvcDec(
322         const char *name,
323         c2_node_id_t id,
324         const std::shared_ptr<IntfImpl> &intfImpl)
325     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
326       mIntf(intfImpl),
327       mDecHandle(nullptr),
328       mOutBufferFlush(nullptr),
329       mIvColorFormat(IV_YUV_420P),
330       mWidth(320),
331       mHeight(240),
332       mHeaderDecoded(false) {
333     GENERATE_FILE_NAMES();
334     CREATE_DUMP_FILE(mInFile);
335 }
336 
~C2SoftAvcDec()337 C2SoftAvcDec::~C2SoftAvcDec() {
338     onRelease();
339 }
340 
onInit()341 c2_status_t C2SoftAvcDec::onInit() {
342     status_t err = initDecoder();
343     return err == OK ? C2_OK : C2_CORRUPTED;
344 }
345 
onStop()346 c2_status_t C2SoftAvcDec::onStop() {
347     if (OK != resetDecoder()) return C2_CORRUPTED;
348     resetPlugin();
349     return C2_OK;
350 }
351 
onReset()352 void C2SoftAvcDec::onReset() {
353     (void) onStop();
354 }
355 
onRelease()356 void C2SoftAvcDec::onRelease() {
357     (void) deleteDecoder();
358     if (mOutBufferFlush) {
359         ivd_aligned_free(nullptr, mOutBufferFlush);
360         mOutBufferFlush = nullptr;
361     }
362     if (mOutBlock) {
363         mOutBlock.reset();
364     }
365 }
366 
onFlush_sm()367 c2_status_t C2SoftAvcDec::onFlush_sm() {
368     if (OK != setFlushMode()) return C2_CORRUPTED;
369 
370     uint32_t bufferSize = mStride * mHeight * 3 / 2;
371     mOutBufferFlush = (uint8_t *)ivd_aligned_malloc(nullptr, 128, bufferSize);
372     if (!mOutBufferFlush) {
373         ALOGE("could not allocate tmp output buffer (for flush) of size %u ", bufferSize);
374         return C2_NO_MEMORY;
375     }
376 
377     while (true) {
378         ivd_video_decode_ip_t s_decode_ip;
379         ivd_video_decode_op_t s_decode_op;
380 
381         setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, nullptr, 0, 0, 0);
382         (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
383         if (0 == s_decode_op.u4_output_present) {
384             resetPlugin();
385             break;
386         }
387     }
388 
389     if (mOutBufferFlush) {
390         ivd_aligned_free(nullptr, mOutBufferFlush);
391         mOutBufferFlush = nullptr;
392     }
393 
394     return C2_OK;
395 }
396 
createDecoder()397 status_t C2SoftAvcDec::createDecoder() {
398     ivdext_create_ip_t s_create_ip;
399     ivdext_create_op_t s_create_op;
400 
401     s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
402     s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
403     s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
404     s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
405     s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
406     s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
407     s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = nullptr;
408     s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
409     IV_API_CALL_STATUS_T status = ivdec_api_function(nullptr,
410                                                      &s_create_ip,
411                                                      &s_create_op);
412     if (status != IV_SUCCESS) {
413         ALOGE("error in %s: 0x%x", __func__,
414               s_create_op.s_ivd_create_op_t.u4_error_code);
415         return UNKNOWN_ERROR;
416     }
417     mDecHandle = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
418     mDecHandle->pv_fxns = (void *)ivdec_api_function;
419     mDecHandle->u4_size = sizeof(iv_obj_t);
420 
421     return OK;
422 }
423 
setNumCores()424 status_t C2SoftAvcDec::setNumCores() {
425     ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip;
426     ivdext_ctl_set_num_cores_op_t s_set_num_cores_op;
427 
428     s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
429     s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
430     s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
431     s_set_num_cores_ip.u4_num_cores = mNumCores;
432     s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
433     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
434                                                      &s_set_num_cores_ip,
435                                                      &s_set_num_cores_op);
436     if (IV_SUCCESS != status) {
437         ALOGD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code);
438         return UNKNOWN_ERROR;
439     }
440 
441     return OK;
442 }
443 
setParams(size_t stride,IVD_VIDEO_DECODE_MODE_T dec_mode)444 status_t C2SoftAvcDec::setParams(size_t stride, IVD_VIDEO_DECODE_MODE_T dec_mode) {
445     ivd_ctl_set_config_ip_t s_set_dyn_params_ip;
446     ivd_ctl_set_config_op_t s_set_dyn_params_op;
447 
448     s_set_dyn_params_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
449     s_set_dyn_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
450     s_set_dyn_params_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
451     s_set_dyn_params_ip.u4_disp_wd = (UWORD32) stride;
452     s_set_dyn_params_ip.e_frm_skip_mode = IVD_SKIP_NONE;
453     s_set_dyn_params_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
454     s_set_dyn_params_ip.e_vid_dec_mode = dec_mode;
455     s_set_dyn_params_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
456     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
457                                                      &s_set_dyn_params_ip,
458                                                      &s_set_dyn_params_op);
459     if (status != IV_SUCCESS) {
460         ALOGE("error in %s: 0x%x", __func__, s_set_dyn_params_op.u4_error_code);
461         return UNKNOWN_ERROR;
462     }
463 
464     return OK;
465 }
466 
getVersion()467 void C2SoftAvcDec::getVersion() {
468     ivd_ctl_getversioninfo_ip_t s_get_versioninfo_ip;
469     ivd_ctl_getversioninfo_op_t s_get_versioninfo_op;
470     UWORD8 au1_buf[512];
471 
472     s_get_versioninfo_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
473     s_get_versioninfo_ip.e_cmd = IVD_CMD_VIDEO_CTL;
474     s_get_versioninfo_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
475     s_get_versioninfo_ip.pv_version_buffer = au1_buf;
476     s_get_versioninfo_ip.u4_version_buffer_size = sizeof(au1_buf);
477     s_get_versioninfo_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
478     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
479                                                      &s_get_versioninfo_ip,
480                                                      &s_get_versioninfo_op);
481     if (status != IV_SUCCESS) {
482         ALOGD("error in %s: 0x%x", __func__,
483               s_get_versioninfo_op.u4_error_code);
484     } else {
485         ALOGV("ittiam decoder version number: %s",
486               (char *) s_get_versioninfo_ip.pv_version_buffer);
487     }
488 }
489 
initDecoder()490 status_t C2SoftAvcDec::initDecoder() {
491     if (OK != createDecoder()) return UNKNOWN_ERROR;
492     mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
493     mStride = ALIGN64(mWidth);
494     mSignalledError = false;
495     resetPlugin();
496     (void) setNumCores();
497     if (OK != setParams(mStride, IVD_DECODE_FRAME)) return UNKNOWN_ERROR;
498     (void) getVersion();
499 
500     return OK;
501 }
502 
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)503 bool C2SoftAvcDec::setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
504                                  ivd_video_decode_op_t *ps_decode_op,
505                                  C2ReadView *inBuffer,
506                                  C2GraphicView *outBuffer,
507                                  size_t inOffset,
508                                  size_t inSize,
509                                  uint32_t tsMarker) {
510     uint32_t displayStride = mStride;
511     uint32_t displayHeight = mHeight;
512     size_t lumaSize = displayStride * displayHeight;
513     size_t chromaSize = lumaSize >> 2;
514 
515     ps_decode_ip->u4_size = sizeof(ivd_video_decode_ip_t);
516     ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
517     if (inBuffer) {
518         ps_decode_ip->u4_ts = tsMarker;
519         ps_decode_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer->data() + inOffset);
520         ps_decode_ip->u4_num_Bytes = inSize;
521     } else {
522         ps_decode_ip->u4_ts = 0;
523         ps_decode_ip->pv_stream_buffer = nullptr;
524         ps_decode_ip->u4_num_Bytes = 0;
525     }
526     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize;
527     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
528     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
529     if (outBuffer) {
530         if (outBuffer->width() < displayStride || outBuffer->height() < displayHeight) {
531             ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)",
532                   outBuffer->width(), outBuffer->height(), displayStride, displayHeight);
533             return false;
534         }
535         ps_decode_ip->s_out_buffer.pu1_bufs[0] = outBuffer->data()[C2PlanarLayout::PLANE_Y];
536         ps_decode_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[C2PlanarLayout::PLANE_U];
537         ps_decode_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[C2PlanarLayout::PLANE_V];
538     } else {
539         ps_decode_ip->s_out_buffer.pu1_bufs[0] = mOutBufferFlush;
540         ps_decode_ip->s_out_buffer.pu1_bufs[1] = mOutBufferFlush + lumaSize;
541         ps_decode_ip->s_out_buffer.pu1_bufs[2] = mOutBufferFlush + lumaSize + chromaSize;
542     }
543     ps_decode_ip->s_out_buffer.u4_num_bufs = 3;
544     ps_decode_op->u4_size = sizeof(ivd_video_decode_op_t);
545 
546     return true;
547 }
548 
getVuiParams()549 bool C2SoftAvcDec::getVuiParams() {
550     ivdext_ctl_get_vui_params_ip_t s_get_vui_params_ip;
551     ivdext_ctl_get_vui_params_op_t s_get_vui_params_op;
552 
553     s_get_vui_params_ip.u4_size = sizeof(ivdext_ctl_get_vui_params_ip_t);
554     s_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
555     s_get_vui_params_ip.e_sub_cmd =
556             (IVD_CONTROL_API_COMMAND_TYPE_T) IH264D_CMD_CTL_GET_VUI_PARAMS;
557     s_get_vui_params_op.u4_size = sizeof(ivdext_ctl_get_vui_params_op_t);
558     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
559                                                      &s_get_vui_params_ip,
560                                                      &s_get_vui_params_op);
561     if (status != IV_SUCCESS) {
562         ALOGD("error in %s: 0x%x", __func__, s_get_vui_params_op.u4_error_code);
563         return false;
564     }
565 
566     VuiColorAspects vuiColorAspects;
567     vuiColorAspects.primaries = s_get_vui_params_op.u1_colour_primaries;
568     vuiColorAspects.transfer = s_get_vui_params_op.u1_tfr_chars;
569     vuiColorAspects.coeffs = s_get_vui_params_op.u1_matrix_coeffs;
570     vuiColorAspects.fullRange = s_get_vui_params_op.u1_video_full_range_flag;
571 
572     // convert vui aspects to C2 values if changed
573     if (!(vuiColorAspects == mBitstreamColorAspects)) {
574         mBitstreamColorAspects = vuiColorAspects;
575         ColorAspects sfAspects;
576         C2StreamColorAspectsInfo::input codedAspects = { 0u };
577         ColorUtils::convertIsoColorAspectsToCodecAspects(
578                 vuiColorAspects.primaries, vuiColorAspects.transfer, vuiColorAspects.coeffs,
579                 vuiColorAspects.fullRange, sfAspects);
580         if (!C2Mapper::map(sfAspects.mPrimaries, &codedAspects.primaries)) {
581             codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED;
582         }
583         if (!C2Mapper::map(sfAspects.mRange, &codedAspects.range)) {
584             codedAspects.range = C2Color::RANGE_UNSPECIFIED;
585         }
586         if (!C2Mapper::map(sfAspects.mMatrixCoeffs, &codedAspects.matrix)) {
587             codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED;
588         }
589         if (!C2Mapper::map(sfAspects.mTransfer, &codedAspects.transfer)) {
590             codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED;
591         }
592         std::vector<std::unique_ptr<C2SettingResult>> failures;
593         (void)mIntf->config({&codedAspects}, C2_MAY_BLOCK, &failures);
594     }
595     return true;
596 }
597 
setFlushMode()598 status_t C2SoftAvcDec::setFlushMode() {
599     ivd_ctl_flush_ip_t s_set_flush_ip;
600     ivd_ctl_flush_op_t s_set_flush_op;
601 
602     s_set_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
603     s_set_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
604     s_set_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
605     s_set_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
606     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
607                                                      &s_set_flush_ip,
608                                                      &s_set_flush_op);
609     if (status != IV_SUCCESS) {
610         ALOGE("error in %s: 0x%x", __func__, s_set_flush_op.u4_error_code);
611         return UNKNOWN_ERROR;
612     }
613 
614     return OK;
615 }
616 
resetDecoder()617 status_t C2SoftAvcDec::resetDecoder() {
618     ivd_ctl_reset_ip_t s_reset_ip;
619     ivd_ctl_reset_op_t s_reset_op;
620 
621     s_reset_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
622     s_reset_ip.e_cmd = IVD_CMD_VIDEO_CTL;
623     s_reset_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
624     s_reset_op.u4_size = sizeof(ivd_ctl_reset_op_t);
625     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
626                                                      &s_reset_ip,
627                                                      &s_reset_op);
628     if (IV_SUCCESS != status) {
629         ALOGE("error in %s: 0x%x", __func__, s_reset_op.u4_error_code);
630         return UNKNOWN_ERROR;
631     }
632     mStride = 0;
633     (void) setNumCores();
634     mSignalledError = false;
635     mHeaderDecoded = false;
636 
637     return OK;
638 }
639 
resetPlugin()640 void C2SoftAvcDec::resetPlugin() {
641     mSignalledOutputEos = false;
642     gettimeofday(&mTimeStart, nullptr);
643     gettimeofday(&mTimeEnd, nullptr);
644 }
645 
deleteDecoder()646 status_t C2SoftAvcDec::deleteDecoder() {
647     if (mDecHandle) {
648         ivdext_delete_ip_t s_delete_ip;
649         ivdext_delete_op_t s_delete_op;
650 
651         s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
652         s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
653         s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
654         IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
655                                                          &s_delete_ip,
656                                                          &s_delete_op);
657         if (status != IV_SUCCESS) {
658             ALOGE("error in %s: 0x%x", __func__,
659                   s_delete_op.s_ivd_delete_op_t.u4_error_code);
660             return UNKNOWN_ERROR;
661         }
662         mDecHandle = nullptr;
663     }
664 
665     return OK;
666 }
667 
fillEmptyWork(const std::unique_ptr<C2Work> & work)668 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
669     uint32_t flags = 0;
670     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
671         flags |= C2FrameData::FLAG_END_OF_STREAM;
672         ALOGV("signalling eos");
673     }
674     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
675     work->worklets.front()->output.buffers.clear();
676     work->worklets.front()->output.ordinal = work->input.ordinal;
677     work->workletsProcessed = 1u;
678 }
679 
finishWork(uint64_t index,const std::unique_ptr<C2Work> & work)680 void C2SoftAvcDec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
681     std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock),
682                                                            C2Rect(mWidth, mHeight));
683     mOutBlock = nullptr;
684     {
685         IntfImpl::Lock lock = mIntf->lock();
686         buffer->setInfo(mIntf->getColorAspects_l());
687     }
688 
689     auto fillWork = [buffer](const std::unique_ptr<C2Work> &work) {
690         work->worklets.front()->output.flags = (C2FrameData::flags_t)0;
691         work->worklets.front()->output.buffers.clear();
692         work->worklets.front()->output.buffers.push_back(buffer);
693         work->worklets.front()->output.ordinal = work->input.ordinal;
694         work->workletsProcessed = 1u;
695     };
696     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
697         fillWork(work);
698     } else {
699         finish(index, fillWork);
700     }
701 }
702 
ensureDecoderState(const std::shared_ptr<C2BlockPool> & pool)703 c2_status_t C2SoftAvcDec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
704     if (!mDecHandle) {
705         ALOGE("not supposed to be here, invalid decoder context");
706         return C2_CORRUPTED;
707     }
708     if (mStride != ALIGN64(mWidth)) {
709         mStride = ALIGN64(mWidth);
710         if (OK != setParams(mStride, IVD_DECODE_FRAME)) return C2_CORRUPTED;
711     }
712     if (mOutBlock &&
713             (mOutBlock->width() != mStride || mOutBlock->height() != mHeight)) {
714         mOutBlock.reset();
715     }
716     if (!mOutBlock) {
717         uint32_t format = HAL_PIXEL_FORMAT_YV12;
718         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
719         c2_status_t err = pool->fetchGraphicBlock(mStride, mHeight, format, usage, &mOutBlock);
720         if (err != C2_OK) {
721             ALOGE("fetchGraphicBlock for Output failed with status %d", err);
722             return err;
723         }
724         ALOGV("provided (%dx%d) required (%dx%d)",
725               mOutBlock->width(), mOutBlock->height(), mStride, mHeight);
726     }
727 
728     return C2_OK;
729 }
730 
731 // TODO: can overall error checking be improved?
732 // TODO: allow configuration of color format and usage for graphic buffers instead
733 //       of hard coding them to HAL_PIXEL_FORMAT_YV12
734 // TODO: pass coloraspects information to surface
735 // TODO: test support for dynamic change in resolution
736 // TODO: verify if the decoder sent back all frames
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)737 void C2SoftAvcDec::process(
738         const std::unique_ptr<C2Work> &work,
739         const std::shared_ptr<C2BlockPool> &pool) {
740     // Initialize output work
741     work->result = C2_OK;
742     work->workletsProcessed = 0u;
743     work->worklets.front()->output.flags = work->input.flags;
744     if (mSignalledError || mSignalledOutputEos) {
745         work->result = C2_BAD_VALUE;
746         return;
747     }
748 
749     size_t inOffset = 0u;
750     size_t inSize = 0u;
751     uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
752     C2ReadView rView = mDummyReadView;
753     if (!work->input.buffers.empty()) {
754         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
755         inSize = rView.capacity();
756         if (inSize && rView.error()) {
757             ALOGE("read view map failed %d", rView.error());
758             work->result = rView.error();
759             return;
760         }
761     }
762     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
763     bool hasPicture = false;
764 
765     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
766           inSize, (int)work->input.ordinal.timestamp.peeku(),
767           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
768     size_t inPos = 0;
769     while (inPos < inSize) {
770         if (C2_OK != ensureDecoderState(pool)) {
771             mSignalledError = true;
772             work->workletsProcessed = 1u;
773             work->result = C2_CORRUPTED;
774             return;
775         }
776 
777         ivd_video_decode_ip_t s_decode_ip;
778         ivd_video_decode_op_t s_decode_op;
779         {
780             C2GraphicView wView = mOutBlock->map().get();
781             if (wView.error()) {
782                 ALOGE("graphic view map failed %d", wView.error());
783                 work->result = wView.error();
784                 return;
785             }
786             if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView,
787                                inOffset + inPos, inSize - inPos, workIndex)) {
788                 mSignalledError = true;
789                 work->workletsProcessed = 1u;
790                 work->result = C2_CORRUPTED;
791                 return;
792             }
793 
794             if (false == mHeaderDecoded) {
795                 /* Decode header and get dimensions */
796                 setParams(mStride, IVD_DECODE_HEADER);
797             }
798 
799             WORD32 delay;
800             GETTIME(&mTimeStart, nullptr);
801             TIME_DIFF(mTimeEnd, mTimeStart, delay);
802             (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
803             WORD32 decodeTime;
804             GETTIME(&mTimeEnd, nullptr);
805             TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
806             ALOGV("decodeTime=%6d delay=%6d numBytes=%6d", decodeTime, delay,
807                   s_decode_op.u4_num_bytes_consumed);
808         }
809         if (IVD_MEM_ALLOC_FAILED == (s_decode_op.u4_error_code & 0xFF)) {
810             ALOGE("allocation failure in decoder");
811             mSignalledError = true;
812             work->workletsProcessed = 1u;
813             work->result = C2_CORRUPTED;
814             return;
815         } else if (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_decode_op.u4_error_code & 0xFF)) {
816             ALOGE("unsupported resolution : %dx%d", mWidth, mHeight);
817             mSignalledError = true;
818             work->workletsProcessed = 1u;
819             work->result = C2_CORRUPTED;
820             return;
821         } else if (IVD_RES_CHANGED == (s_decode_op.u4_error_code & 0xFF)) {
822             ALOGV("resolution changed");
823             drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
824             resetDecoder();
825             resetPlugin();
826             work->workletsProcessed = 0u;
827 
828             /* Decode header and get new dimensions */
829             setParams(mStride, IVD_DECODE_HEADER);
830             (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
831         }
832         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
833             if (mHeaderDecoded == false) {
834                 mHeaderDecoded = true;
835                 setParams(ALIGN64(s_decode_op.u4_pic_wd), IVD_DECODE_FRAME);
836             }
837             if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) {
838                 mWidth = s_decode_op.u4_pic_wd;
839                 mHeight = s_decode_op.u4_pic_ht;
840                 CHECK_EQ(0u, s_decode_op.u4_output_present);
841 
842                 C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight);
843                 std::vector<std::unique_ptr<C2SettingResult>> failures;
844                 c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
845                 if (err == OK) {
846                     work->worklets.front()->output.configUpdate.push_back(
847                         C2Param::Copy(size));
848                 } else {
849                     ALOGE("Cannot set width and height");
850                     mSignalledError = true;
851                     work->workletsProcessed = 1u;
852                     work->result = C2_CORRUPTED;
853                     return;
854                 }
855                 continue;
856             }
857         }
858         (void)getVuiParams();
859         hasPicture |= (1 == s_decode_op.u4_frame_decoded_flag);
860         if (s_decode_op.u4_output_present) {
861             finishWork(s_decode_op.u4_ts, work);
862         }
863         if (0 == s_decode_op.u4_num_bytes_consumed) {
864             ALOGD("Bytes consumed is zero. Ignoring remaining bytes");
865             break;
866         }
867         inPos += s_decode_op.u4_num_bytes_consumed;
868         if (hasPicture && (inSize - inPos)) {
869             ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
870                   (int)inSize - (int)inPos);
871             break;
872         }
873     }
874     if (eos) {
875         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
876         mSignalledOutputEos = true;
877     } else if (!hasPicture) {
878         fillEmptyWork(work);
879     }
880 }
881 
drainInternal(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool,const std::unique_ptr<C2Work> & work)882 c2_status_t C2SoftAvcDec::drainInternal(
883         uint32_t drainMode,
884         const std::shared_ptr<C2BlockPool> &pool,
885         const std::unique_ptr<C2Work> &work) {
886     if (drainMode == NO_DRAIN) {
887         ALOGW("drain with NO_DRAIN: no-op");
888         return C2_OK;
889     }
890     if (drainMode == DRAIN_CHAIN) {
891         ALOGW("DRAIN_CHAIN not supported");
892         return C2_OMITTED;
893     }
894 
895     if (OK != setFlushMode()) return C2_CORRUPTED;
896     while (true) {
897         if (C2_OK != ensureDecoderState(pool)) {
898             mSignalledError = true;
899             work->workletsProcessed = 1u;
900             work->result = C2_CORRUPTED;
901             return C2_CORRUPTED;
902         }
903         C2GraphicView wView = mOutBlock->map().get();
904         if (wView.error()) {
905             ALOGE("graphic view map failed %d", wView.error());
906             return C2_CORRUPTED;
907         }
908         ivd_video_decode_ip_t s_decode_ip;
909         ivd_video_decode_op_t s_decode_op;
910         if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) {
911             mSignalledError = true;
912             work->workletsProcessed = 1u;
913             return C2_CORRUPTED;
914         }
915         (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
916         if (s_decode_op.u4_output_present) {
917             finishWork(s_decode_op.u4_ts, work);
918         } else {
919             fillEmptyWork(work);
920             break;
921         }
922     }
923 
924     return C2_OK;
925 }
926 
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)927 c2_status_t C2SoftAvcDec::drain(
928         uint32_t drainMode,
929         const std::shared_ptr<C2BlockPool> &pool) {
930     return drainInternal(drainMode, pool, nullptr);
931 }
932 
933 class C2SoftAvcDecFactory : public C2ComponentFactory {
934 public:
C2SoftAvcDecFactory()935     C2SoftAvcDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
936         GetCodec2PlatformComponentStore()->getParamReflector())) {
937     }
938 
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)939     virtual c2_status_t createComponent(
940             c2_node_id_t id,
941             std::shared_ptr<C2Component>* const component,
942             std::function<void(C2Component*)> deleter) override {
943         *component = std::shared_ptr<C2Component>(
944                 new C2SoftAvcDec(COMPONENT_NAME,
945                                  id,
946                                  std::make_shared<C2SoftAvcDec::IntfImpl>(mHelper)),
947                 deleter);
948         return C2_OK;
949     }
950 
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)951     virtual c2_status_t createInterface(
952             c2_node_id_t id,
953             std::shared_ptr<C2ComponentInterface>* const interface,
954             std::function<void(C2ComponentInterface*)> deleter) override {
955         *interface = std::shared_ptr<C2ComponentInterface>(
956                 new SimpleInterface<C2SoftAvcDec::IntfImpl>(
957                         COMPONENT_NAME, id, std::make_shared<C2SoftAvcDec::IntfImpl>(mHelper)),
958                 deleter);
959         return C2_OK;
960     }
961 
962     virtual ~C2SoftAvcDecFactory() override = default;
963 
964 private:
965     std::shared_ptr<C2ReflectorHelper> mHelper;
966 };
967 
968 }  // namespace android
969 
CreateCodec2Factory()970 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
971     ALOGV("in %s", __func__);
972     return new ::android::C2SoftAvcDecFactory();
973 }
974 
DestroyCodec2Factory(::C2ComponentFactory * factory)975 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
976     ALOGV("in %s", __func__);
977     delete factory;
978 }
979