1 /*
2 * Copyright (C) 2014 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 "SoftHEVC"
19 #include <utils/Log.h>
20
21 #include "ihevc_typedefs.h"
22 #include "iv.h"
23 #include "ivd.h"
24 #include "ihevcd_cxa.h"
25 #include "SoftHEVC.h"
26
27 #include <media/stagefright/foundation/ADebug.h>
28 #include <media/stagefright/foundation/AUtils.h>
29 #include <media/stagefright/MediaDefs.h>
30 #include <OMX_VideoExt.h>
31
32 namespace android {
33
34 #define componentName "video_decoder.hevc"
35 #define codingType OMX_VIDEO_CodingHEVC
36 #define CODEC_MIME_TYPE MEDIA_MIMETYPE_VIDEO_HEVC
37
38 /** Function and structure definitions to keep code similar for each codec */
39 #define ivdec_api_function ihevcd_cxa_api_function
40 #define ivdext_create_ip_t ihevcd_cxa_create_ip_t
41 #define ivdext_create_op_t ihevcd_cxa_create_op_t
42 #define ivdext_delete_ip_t ihevcd_cxa_delete_ip_t
43 #define ivdext_delete_op_t ihevcd_cxa_delete_op_t
44 #define ivdext_ctl_set_num_cores_ip_t ihevcd_cxa_ctl_set_num_cores_ip_t
45 #define ivdext_ctl_set_num_cores_op_t ihevcd_cxa_ctl_set_num_cores_op_t
46
47 #define IVDEXT_CMD_CTL_SET_NUM_CORES \
48 (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
49
50 static const CodecProfileLevel kProfileLevels[] = {
51 { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 },
52 { OMX_VIDEO_HEVCProfileMainStill, OMX_VIDEO_HEVCMainTierLevel51 },
53 };
54
SoftHEVC(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)55 SoftHEVC::SoftHEVC(
56 const char *name,
57 const OMX_CALLBACKTYPE *callbacks,
58 OMX_PTR appData,
59 OMX_COMPONENTTYPE **component)
60 : SoftVideoDecoderOMXComponent(name, componentName, codingType,
61 kProfileLevels, ARRAY_SIZE(kProfileLevels),
62 320 /* width */, 240 /* height */, callbacks,
63 appData, component),
64 mCodecCtx(NULL),
65 mFlushOutBuffer(NULL),
66 mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
67 mIvColorFormat(IV_YUV_420P),
68 mChangingResolution(false),
69 mSignalledError(false),
70 mStride(mWidth) {
71 const size_t kMinCompressionRatio = 4 /* compressionRatio (for Level 4+) */;
72 const size_t kMaxOutputBufferSize = 2048 * 2048 * 3 / 2;
73 // INPUT_BUF_SIZE is given by HEVC codec as minimum input size
74 initPorts(
75 kNumBuffers, max(kMaxOutputBufferSize / kMinCompressionRatio, (size_t)INPUT_BUF_SIZE),
76 kNumBuffers, CODEC_MIME_TYPE, kMinCompressionRatio);
77 }
78
init()79 status_t SoftHEVC::init() {
80 return initDecoder();
81 }
82
~SoftHEVC()83 SoftHEVC::~SoftHEVC() {
84 ALOGV("In SoftHEVC::~SoftHEVC");
85 CHECK_EQ(deInitDecoder(), (status_t)OK);
86 }
87
ivd_aligned_malloc(void * ctxt,WORD32 alignment,WORD32 size)88 static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
89 UNUSED(ctxt);
90 return memalign(alignment, size);
91 }
92
ivd_aligned_free(void * ctxt,void * buf)93 static void ivd_aligned_free(void *ctxt, void *buf) {
94 UNUSED(ctxt);
95 free(buf);
96 return;
97 }
98
GetCPUCoreCount()99 static size_t GetCPUCoreCount() {
100 long cpuCoreCount = 1;
101 #if defined(_SC_NPROCESSORS_ONLN)
102 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
103 #else
104 // _SC_NPROC_ONLN must be defined...
105 cpuCoreCount = sysconf(_SC_NPROC_ONLN);
106 #endif
107 CHECK(cpuCoreCount >= 1);
108 ALOGV("Number of CPU cores: %ld", cpuCoreCount);
109 return (size_t)cpuCoreCount;
110 }
111
logVersion()112 void SoftHEVC::logVersion() {
113 ivd_ctl_getversioninfo_ip_t s_ctl_ip;
114 ivd_ctl_getversioninfo_op_t s_ctl_op;
115 UWORD8 au1_buf[512];
116 IV_API_CALL_STATUS_T status;
117
118 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
119 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
120 s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
121 s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
122 s_ctl_ip.pv_version_buffer = au1_buf;
123 s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);
124
125 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
126 (void *)&s_ctl_op);
127
128 if (status != IV_SUCCESS) {
129 ALOGE("Error in getting version number: 0x%x",
130 s_ctl_op.u4_error_code);
131 } else {
132 ALOGV("Ittiam decoder version number: %s",
133 (char *)s_ctl_ip.pv_version_buffer);
134 }
135 return;
136 }
137
setParams(size_t stride)138 status_t SoftHEVC::setParams(size_t stride) {
139 ivd_ctl_set_config_ip_t s_ctl_ip;
140 ivd_ctl_set_config_op_t s_ctl_op;
141 IV_API_CALL_STATUS_T status;
142 s_ctl_ip.u4_disp_wd = (UWORD32)stride;
143 s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
144
145 s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
146 s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
147 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
148 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
149 s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
150 s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
151
152 ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride);
153 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
154 (void *)&s_ctl_op);
155
156 if (status != IV_SUCCESS) {
157 ALOGE("Error in setting the run-time parameters: 0x%x",
158 s_ctl_op.u4_error_code);
159
160 return UNKNOWN_ERROR;
161 }
162 return OK;
163 }
164
resetPlugin()165 status_t SoftHEVC::resetPlugin() {
166 mIsInFlush = false;
167 mReceivedEOS = false;
168 memset(mTimeStamps, 0, sizeof(mTimeStamps));
169 memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
170
171 /* Initialize both start and end times */
172 gettimeofday(&mTimeStart, NULL);
173 gettimeofday(&mTimeEnd, NULL);
174
175 return OK;
176 }
177
getVUIParams()178 bool SoftHEVC::getVUIParams() {
179 IV_API_CALL_STATUS_T status;
180 ihevcd_cxa_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;
181 ihevcd_cxa_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;
182
183 s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
184 s_ctl_get_vui_params_ip.e_sub_cmd =
185 (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_GET_VUI_PARAMS;
186
187 s_ctl_get_vui_params_ip.u4_size =
188 sizeof(ihevcd_cxa_ctl_get_vui_params_ip_t);
189
190 s_ctl_get_vui_params_op.u4_size = sizeof(ihevcd_cxa_ctl_get_vui_params_op_t);
191
192 status = ivdec_api_function(
193 (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip,
194 (void *)&s_ctl_get_vui_params_op);
195
196 if (status != IV_SUCCESS) {
197 ALOGW("Error in getting VUI params: 0x%x",
198 s_ctl_get_vui_params_op.u4_error_code);
199 return false;
200 }
201
202 int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries;
203 int32_t transfer = s_ctl_get_vui_params_op.u1_transfer_characteristics;
204 int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coefficients;
205 bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag;
206
207 ColorAspects colorAspects;
208 ColorUtils::convertIsoColorAspectsToCodecAspects(
209 primaries, transfer, coeffs, fullRange, colorAspects);
210
211 // Update color aspects if necessary.
212 if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
213 mBitstreamColorAspects = colorAspects;
214 status_t err = handleColorAspectsChange();
215 CHECK(err == OK);
216 }
217 return true;
218 }
219
resetDecoder()220 status_t SoftHEVC::resetDecoder() {
221 ivd_ctl_reset_ip_t s_ctl_ip;
222 ivd_ctl_reset_op_t s_ctl_op;
223 IV_API_CALL_STATUS_T status;
224
225 s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
226 s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
227 s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
228 s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
229
230 status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
231 (void *)&s_ctl_op);
232 if (IV_SUCCESS != status) {
233 ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
234 return UNKNOWN_ERROR;
235 }
236 mSignalledError = false;
237
238 /* Set number of cores/threads to be used by the codec */
239 setNumCores();
240
241 mStride = 0;
242 return OK;
243 }
244
setNumCores()245 status_t SoftHEVC::setNumCores() {
246 ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
247 ivdext_ctl_set_num_cores_op_t s_set_cores_op;
248 IV_API_CALL_STATUS_T status;
249 s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
250 s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
251 s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
252 s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
253 s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
254 ALOGV("Set number of cores to %u", s_set_cores_ip.u4_num_cores);
255 status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip,
256 (void *)&s_set_cores_op);
257 if (IV_SUCCESS != status) {
258 ALOGE("Error in setting number of cores: 0x%x",
259 s_set_cores_op.u4_error_code);
260 return UNKNOWN_ERROR;
261 }
262 return OK;
263 }
264
setFlushMode()265 status_t SoftHEVC::setFlushMode() {
266 IV_API_CALL_STATUS_T status;
267 ivd_ctl_flush_ip_t s_video_flush_ip;
268 ivd_ctl_flush_op_t s_video_flush_op;
269
270 s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
271 s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
272 s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
273 s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
274 ALOGV("Set the decoder in flush mode ");
275
276 /* Set the decoder in Flush mode, subsequent decode() calls will flush */
277 status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip,
278 (void *)&s_video_flush_op);
279
280 if (status != IV_SUCCESS) {
281 ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
282 s_video_flush_op.u4_error_code);
283 return UNKNOWN_ERROR;
284 }
285
286 mIsInFlush = true;
287 return OK;
288 }
289
initDecoder()290 status_t SoftHEVC::initDecoder() {
291 IV_API_CALL_STATUS_T status;
292
293 mNumCores = GetCPUCoreCount();
294 mCodecCtx = NULL;
295
296 mStride = outputBufferWidth();
297
298 /* Initialize the decoder */
299 {
300 ivdext_create_ip_t s_create_ip;
301 ivdext_create_op_t s_create_op;
302
303 void *dec_fxns = (void *)ivdec_api_function;
304
305 s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
306 s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
307 s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
308 s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
309 s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
310 s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
311 s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
312 s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
313
314 status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
315
316 if (status != IV_SUCCESS) {
317 ALOGE("Error in create: 0x%x",
318 s_create_op.s_ivd_create_op_t.u4_error_code);
319 deInitDecoder();
320 mCodecCtx = NULL;
321 return UNKNOWN_ERROR;
322 }
323
324 mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
325 mCodecCtx->pv_fxns = dec_fxns;
326 mCodecCtx->u4_size = sizeof(iv_obj_t);
327 }
328
329 /* Reset the plugin state */
330 resetPlugin();
331
332 /* Set the run time (dynamic) parameters */
333 setParams(mStride);
334
335 /* Set number of cores/threads to be used by the codec */
336 setNumCores();
337
338 /* Get codec version */
339 logVersion();
340
341 mFlushNeeded = false;
342 return OK;
343 }
344
deInitDecoder()345 status_t SoftHEVC::deInitDecoder() {
346 size_t i;
347 IV_API_CALL_STATUS_T status;
348
349 if (mCodecCtx) {
350 ivdext_delete_ip_t s_delete_ip;
351 ivdext_delete_op_t s_delete_op;
352
353 s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
354 s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
355
356 s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
357
358 status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op);
359 if (status != IV_SUCCESS) {
360 ALOGE("Error in delete: 0x%x",
361 s_delete_op.s_ivd_delete_op_t.u4_error_code);
362 return UNKNOWN_ERROR;
363 }
364 }
365
366
367 mChangingResolution = false;
368
369 return OK;
370 }
371
onReset()372 void SoftHEVC::onReset() {
373 ALOGV("onReset called");
374 SoftVideoDecoderOMXComponent::onReset();
375
376 mSignalledError = false;
377 resetDecoder();
378 resetPlugin();
379 }
380
setDecodeArgs(ivd_video_decode_ip_t * ps_dec_ip,ivd_video_decode_op_t * ps_dec_op,OMX_BUFFERHEADERTYPE * inHeader,OMX_BUFFERHEADERTYPE * outHeader,size_t timeStampIx)381 bool SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip,
382 ivd_video_decode_op_t *ps_dec_op,
383 OMX_BUFFERHEADERTYPE *inHeader,
384 OMX_BUFFERHEADERTYPE *outHeader,
385 size_t timeStampIx) {
386 size_t sizeY = outputBufferWidth() * outputBufferHeight();
387 size_t sizeUV;
388
389 ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
390 ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
391
392 ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
393
394 /* When in flush and after EOS with zero byte input,
395 * inHeader is set to zero. Hence check for non-null */
396 if (inHeader) {
397 ps_dec_ip->u4_ts = timeStampIx;
398 ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
399 + inHeader->nOffset;
400 ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
401 } else {
402 ps_dec_ip->u4_ts = 0;
403 ps_dec_ip->pv_stream_buffer = NULL;
404 ps_dec_ip->u4_num_Bytes = 0;
405 }
406
407 sizeUV = sizeY / 4;
408 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
409 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
410 ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
411
412 uint8_t *pBuf;
413 if (outHeader) {
414 if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
415 android_errorWriteLog(0x534e4554, "27833616");
416 return false;
417 }
418 pBuf = outHeader->pBuffer;
419 } else {
420 // mFlushOutBuffer always has the right size.
421 pBuf = mFlushOutBuffer;
422 }
423
424 ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
425 ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
426 ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
427 ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
428 return true;
429 }
onPortFlushCompleted(OMX_U32 portIndex)430 void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) {
431 /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
432 if (kOutputPortIndex == portIndex) {
433 setFlushMode();
434
435 /* Allocate a picture buffer to flushed data */
436 uint32_t displayStride = outputBufferWidth();
437 uint32_t displayHeight = outputBufferHeight();
438
439 uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
440 mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize);
441 if (NULL == mFlushOutBuffer) {
442 ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
443 return;
444 }
445
446 while (true) {
447 ivd_video_decode_ip_t s_dec_ip;
448 ivd_video_decode_op_t s_dec_op;
449 IV_API_CALL_STATUS_T status;
450 size_t sizeY, sizeUV;
451
452 setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
453
454 status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
455 (void *)&s_dec_op);
456 if (0 == s_dec_op.u4_output_present) {
457 resetPlugin();
458 break;
459 }
460 }
461
462 if (mFlushOutBuffer) {
463 free(mFlushOutBuffer);
464 mFlushOutBuffer = NULL;
465 }
466
467 }
468 }
469
onQueueFilled(OMX_U32 portIndex)470 void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
471 UNUSED(portIndex);
472
473 if (mSignalledError) {
474 return;
475 }
476 if (mOutputPortSettingsChange != NONE) {
477 return;
478 }
479
480 if (NULL == mCodecCtx) {
481 if (OK != initDecoder()) {
482 ALOGE("Failed to initialize decoder");
483 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
484 mSignalledError = true;
485 return;
486 }
487 }
488 if (outputBufferWidth() != mStride) {
489 /* Set the run-time (dynamic) parameters */
490 mStride = outputBufferWidth();
491 setParams(mStride);
492 }
493
494 List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
495 List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
496
497 while (!outQueue.empty()) {
498 BufferInfo *inInfo;
499 OMX_BUFFERHEADERTYPE *inHeader;
500
501 BufferInfo *outInfo;
502 OMX_BUFFERHEADERTYPE *outHeader;
503 size_t timeStampIx;
504
505 inInfo = NULL;
506 inHeader = NULL;
507
508 if (!mIsInFlush) {
509 if (!inQueue.empty()) {
510 inInfo = *inQueue.begin();
511 inHeader = inInfo->mHeader;
512 } else {
513 break;
514 }
515 }
516
517 outInfo = *outQueue.begin();
518 outHeader = outInfo->mHeader;
519 outHeader->nFlags = 0;
520 outHeader->nTimeStamp = 0;
521 outHeader->nOffset = 0;
522
523 if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
524 mReceivedEOS = true;
525 if (inHeader->nFilledLen == 0) {
526 inQueue.erase(inQueue.begin());
527 inInfo->mOwnedByUs = false;
528 notifyEmptyBufferDone(inHeader);
529 inHeader = NULL;
530 setFlushMode();
531 }
532 }
533
534 /* Get a free slot in timestamp array to hold input timestamp */
535 {
536 size_t i;
537 timeStampIx = 0;
538 for (i = 0; i < MAX_TIME_STAMPS; i++) {
539 if (!mTimeStampsValid[i]) {
540 timeStampIx = i;
541 break;
542 }
543 }
544 if (inHeader != NULL) {
545 mTimeStampsValid[timeStampIx] = true;
546 mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
547 }
548 }
549
550 {
551 ivd_video_decode_ip_t s_dec_ip;
552 ivd_video_decode_op_t s_dec_op;
553 WORD32 timeDelay, timeTaken;
554 size_t sizeY, sizeUV;
555
556 if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
557 ALOGE("Decoder arg setup failed");
558 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
559 mSignalledError = true;
560 return;
561 }
562
563 GETTIME(&mTimeStart, NULL);
564 /* Compute time elapsed between end of previous decode()
565 * to start of current decode() */
566 TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
567
568 IV_API_CALL_STATUS_T status;
569 status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
570
571 bool unsupportedResolution =
572 (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & IVD_ERROR_MASK));
573
574 /* Check for unsupported dimensions */
575 if (unsupportedResolution) {
576 ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight);
577 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
578 mSignalledError = true;
579 return;
580 }
581
582 bool allocationFailed =
583 (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & IVD_ERROR_MASK));
584 if (allocationFailed) {
585 ALOGE("Allocation failure in decoder");
586 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
587 mSignalledError = true;
588 return;
589 }
590
591 if (IS_IVD_FATAL_ERROR(s_dec_op.u4_error_code)) {
592 ALOGE("Fatal Error : 0x%x", s_dec_op.u4_error_code);
593 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
594 mSignalledError = true;
595 return;
596 }
597
598 bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & IVD_ERROR_MASK));
599
600 getVUIParams();
601
602 GETTIME(&mTimeEnd, NULL);
603 /* Compute time taken for decode() */
604 TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
605
606 ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
607 s_dec_op.u4_num_bytes_consumed);
608 if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
609 mFlushNeeded = true;
610 }
611
612 if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
613 /* If the input did not contain picture data, then ignore
614 * the associated timestamp */
615 mTimeStampsValid[timeStampIx] = false;
616 }
617
618 // If the decoder is in the changing resolution mode and there is no output present,
619 // that means the switching is done and it's ready to reset the decoder and the plugin.
620 if (mChangingResolution && !s_dec_op.u4_output_present) {
621 mChangingResolution = false;
622 resetDecoder();
623 resetPlugin();
624 mStride = outputBufferWidth();
625 setParams(mStride);
626 continue;
627 }
628
629 if (resChanged) {
630 mChangingResolution = true;
631 if (mFlushNeeded) {
632 setFlushMode();
633 }
634 continue;
635 }
636
637 // Combine the resolution change and coloraspects change in one PortSettingChange event
638 // if necessary.
639 if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
640 uint32_t width = s_dec_op.u4_pic_wd;
641 uint32_t height = s_dec_op.u4_pic_ht;
642 bool portWillReset = false;
643 handlePortSettingsChange(&portWillReset, width, height);
644
645 if (portWillReset) {
646 resetDecoder();
647 resetPlugin();
648 return;
649 }
650 } else if (mUpdateColorAspects) {
651 notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
652 kDescribeColorAspectsIndex, NULL);
653 mUpdateColorAspects = false;
654 return;
655 }
656
657 if (s_dec_op.u4_output_present) {
658 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
659
660 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
661 mTimeStampsValid[s_dec_op.u4_ts] = false;
662
663 outInfo->mOwnedByUs = false;
664 outQueue.erase(outQueue.begin());
665 outInfo = NULL;
666 notifyFillBufferDone(outHeader);
667 outHeader = NULL;
668 } else if (mIsInFlush) {
669 /* If in flush mode and no output is returned by the codec,
670 * then come out of flush mode */
671 mIsInFlush = false;
672
673 /* If EOS was recieved on input port and there is no output
674 * from the codec, then signal EOS on output port */
675 if (mReceivedEOS) {
676 outHeader->nFilledLen = 0;
677 outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
678
679 outInfo->mOwnedByUs = false;
680 outQueue.erase(outQueue.begin());
681 outInfo = NULL;
682 notifyFillBufferDone(outHeader);
683 outHeader = NULL;
684 resetPlugin();
685 }
686 }
687 }
688
689 /* If input EOS is seen and decoder is not in flush mode,
690 * set the decoder in flush mode.
691 * There can be a case where EOS is sent along with last picture data
692 * In that case, only after decoding that input data, decoder has to be
693 * put in flush. This case is handled here */
694
695 if (mReceivedEOS && !mIsInFlush) {
696 setFlushMode();
697 }
698
699 // TODO: Handle more than one picture data
700 if (inHeader != NULL) {
701 inInfo->mOwnedByUs = false;
702 inQueue.erase(inQueue.begin());
703 inInfo = NULL;
704 notifyEmptyBufferDone(inHeader);
705 inHeader = NULL;
706 }
707 }
708 }
709
getColorAspectPreference()710 int SoftHEVC::getColorAspectPreference() {
711 return kPreferBitstream;
712 }
713
714 } // namespace android
715
716 __attribute__((cfi_canonical_jump_table))
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)717 android::SoftOMXComponent *createSoftOMXComponent(const char *name,
718 const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
719 OMX_COMPONENTTYPE **component) {
720 android::SoftHEVC *codec = new android::SoftHEVC(name, callbacks, appData, component);
721 if (codec->init() != android::OK) {
722 android::sp<android::SoftOMXComponent> release = codec;
723 return NULL;
724 }
725 return codec;
726 }
727