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