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