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