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