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