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