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