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