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