SoftMPEG2.cpp revision 7406bc75c086534d574bee1e608de863fb276170
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 "SoftMPEG2"
19#include <utils/Log.h>
20
21#include "iv_datatypedef.h"
22#include "iv.h"
23#include "ivd.h"
24#include "impeg2d.h"
25#include "SoftMPEG2.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 componentName                   "video_decoder.mpeg2"
34#define codingType                      OMX_VIDEO_CodingMPEG2
35#define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_MPEG2
36
37/** Function and structure definitions to keep code similar for each codec */
38#define ivdec_api_function              impeg2d_api_function
39#define ivdext_init_ip_t                impeg2d_init_ip_t
40#define ivdext_init_op_t                impeg2d_init_op_t
41#define ivdext_fill_mem_rec_ip_t        impeg2d_fill_mem_rec_ip_t
42#define ivdext_fill_mem_rec_op_t        impeg2d_fill_mem_rec_op_t
43#define ivdext_ctl_set_num_cores_ip_t   impeg2d_ctl_set_num_cores_ip_t
44#define ivdext_ctl_set_num_cores_op_t   impeg2d_ctl_set_num_cores_op_t
45
46#define IVDEXT_CMD_CTL_SET_NUM_CORES    \
47        (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_SET_NUM_CORES
48
49static const CodecProfileLevel kProfileLevels[] = {
50    { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelLL  },
51    { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelML  },
52    { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelH14 },
53    { OMX_VIDEO_MPEG2ProfileSimple, OMX_VIDEO_MPEG2LevelHL  },
54
55    { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelLL  },
56    { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelML  },
57    { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelH14 },
58    { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelHL  },
59};
60
61SoftMPEG2::SoftMPEG2(
62        const char *name,
63        const OMX_CALLBACKTYPE *callbacks,
64        OMX_PTR appData,
65        OMX_COMPONENTTYPE **component)
66    : SoftVideoDecoderOMXComponent(
67            name, componentName, codingType,
68            kProfileLevels, ARRAY_SIZE(kProfileLevels),
69            320 /* width */, 240 /* height */, callbacks,
70            appData, component),
71      mMemRecords(NULL),
72      mFlushOutBuffer(NULL),
73      mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
74      mIvColorFormat(IV_YUV_420P),
75      mNewWidth(mWidth),
76      mNewHeight(mHeight),
77      mChangingResolution(false) {
78    initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
79
80    // If input dump is enabled, then open create an empty file
81    GENERATE_FILE_NAMES();
82    CREATE_DUMP_FILE(mInFile);
83
84    CHECK_EQ(initDecoder(), (status_t)OK);
85}
86
87SoftMPEG2::~SoftMPEG2() {
88    CHECK_EQ(deInitDecoder(), (status_t)OK);
89}
90
91
92static size_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) {
93    OMX_S64 minTimeStamp = LLONG_MAX;
94    int idx = -1;
95    for (size_t i = 0; i < MAX_TIME_STAMPS; i++) {
96        if (pIsTimeStampValid[i]) {
97            if (pNTimeStamp[i] < minTimeStamp) {
98                minTimeStamp = pNTimeStamp[i];
99                idx = i;
100            }
101        }
102    }
103    return idx;
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 SoftMPEG2::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 = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
133
134    if (status != IV_SUCCESS) {
135        ALOGE("Error in getting version number: 0x%x",
136                s_ctl_op.u4_error_code);
137    } else {
138        ALOGV("Ittiam decoder version number: %s",
139                (char *)s_ctl_ip.pv_version_buffer);
140    }
141    return;
142}
143
144status_t SoftMPEG2::setParams(size_t stride) {
145    ivd_ctl_set_config_ip_t s_ctl_ip;
146    ivd_ctl_set_config_op_t s_ctl_op;
147    IV_API_CALL_STATUS_T status;
148    s_ctl_ip.u4_disp_wd = (UWORD32)stride;
149    s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
150
151    s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
152    s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
153    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
154    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
155    s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
156    s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
157
158    ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride);
159    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
160
161    if (status != IV_SUCCESS) {
162        ALOGE("Error in setting the run-time parameters: 0x%x",
163                s_ctl_op.u4_error_code);
164
165        return UNKNOWN_ERROR;
166    }
167    return OK;
168}
169
170status_t SoftMPEG2::resetPlugin() {
171    mIsInFlush = false;
172    mReceivedEOS = false;
173    memset(mTimeStamps, 0, sizeof(mTimeStamps));
174    memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
175
176    /* Initialize both start and end times */
177    gettimeofday(&mTimeStart, NULL);
178    gettimeofday(&mTimeEnd, NULL);
179
180    return OK;
181}
182
183status_t SoftMPEG2::resetDecoder() {
184    ivd_ctl_reset_ip_t s_ctl_ip;
185    ivd_ctl_reset_op_t s_ctl_op;
186    IV_API_CALL_STATUS_T status;
187
188    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
189    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
190    s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
191    s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
192
193    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip, (void *)&s_ctl_op);
194    if (IV_SUCCESS != status) {
195        ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
196        return UNKNOWN_ERROR;
197    }
198
199    /* Set the run-time (dynamic) parameters */
200    setParams(outputBufferWidth());
201
202    /* Set number of cores/threads to be used by the codec */
203    setNumCores();
204
205    return OK;
206}
207
208status_t SoftMPEG2::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
218    status = ivdec_api_function(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 SoftMPEG2::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    mWaitForI = true;
248    mIsInFlush = true;
249    return OK;
250}
251
252status_t SoftMPEG2::initDecoder() {
253    IV_API_CALL_STATUS_T status;
254
255    UWORD32 u4_num_reorder_frames;
256    UWORD32 u4_num_ref_frames;
257    UWORD32 u4_share_disp_buf;
258
259    mNumCores = GetCPUCoreCount();
260    mWaitForI = true;
261
262    /* Initialize number of ref and reorder modes (for MPEG2) */
263    u4_num_reorder_frames = 16;
264    u4_num_ref_frames = 16;
265    u4_share_disp_buf = 0;
266
267    uint32_t displayStride = outputBufferWidth();
268    uint32_t displayHeight = outputBufferHeight();
269    uint32_t displaySizeY = displayStride * displayHeight;
270
271    {
272        iv_num_mem_rec_ip_t s_num_mem_rec_ip;
273        iv_num_mem_rec_op_t s_num_mem_rec_op;
274
275        s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
276        s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
277        s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
278
279        status = ivdec_api_function(
280                mCodecCtx, (void *)&s_num_mem_rec_ip, (void *)&s_num_mem_rec_op);
281        if (IV_SUCCESS != status) {
282            ALOGE("Error in getting mem records: 0x%x",
283                    s_num_mem_rec_op.u4_error_code);
284            return UNKNOWN_ERROR;
285        }
286
287        mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
288    }
289
290    mMemRecords = (iv_mem_rec_t *)ivd_aligned_malloc(
291            128, mNumMemRecords * sizeof(iv_mem_rec_t));
292    if (mMemRecords == NULL) {
293        ALOGE("Allocation failure");
294        return NO_MEMORY;
295    }
296
297    memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
298
299    {
300        size_t i;
301        ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
302        ivdext_fill_mem_rec_op_t s_fill_mem_op;
303        iv_mem_rec_t *ps_mem_rec;
304
305        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
306            sizeof(ivdext_fill_mem_rec_ip_t);
307
308        s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf;
309        s_fill_mem_ip.e_output_format = mIvColorFormat;
310
311        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
312        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
313        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride;
314        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight;
315        s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
316            sizeof(ivdext_fill_mem_rec_op_t);
317
318        ps_mem_rec = mMemRecords;
319        for (i = 0; i < mNumMemRecords; i++) {
320            ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
321        }
322
323        status = ivdec_api_function(
324                mCodecCtx, (void *)&s_fill_mem_ip, (void *)&s_fill_mem_op);
325
326        if (IV_SUCCESS != status) {
327            ALOGE("Error in filling mem records: 0x%x",
328                    s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
329            return UNKNOWN_ERROR;
330        }
331        mNumMemRecords =
332            s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
333
334        ps_mem_rec = mMemRecords;
335
336        for (i = 0; i < mNumMemRecords; i++) {
337            ps_mem_rec->pv_base = ivd_aligned_malloc(
338                    ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
339            if (ps_mem_rec->pv_base == NULL) {
340                ALOGE("Allocation failure for memory record #%zu of size %u",
341                        i, ps_mem_rec->u4_mem_size);
342                status = IV_FAIL;
343                return NO_MEMORY;
344            }
345
346            ps_mem_rec++;
347        }
348    }
349
350    /* Initialize the decoder */
351    {
352        ivdext_init_ip_t s_init_ip;
353        ivdext_init_op_t s_init_op;
354
355        void *dec_fxns = (void *)ivdec_api_function;
356
357        s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
358        s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
359        s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
360        s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride;
361        s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight;
362
363        s_init_ip.u4_share_disp_buf = u4_share_disp_buf;
364
365        s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op);
366
367        s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
368        s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat;
369
370        mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base;
371        mCodecCtx->pv_fxns = dec_fxns;
372        mCodecCtx->u4_size = sizeof(iv_obj_t);
373
374        status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, (void *)&s_init_op);
375        if (status != IV_SUCCESS) {
376            ALOGE("Error in init: 0x%x",
377                    s_init_op.s_ivd_init_op_t.u4_error_code);
378            return UNKNOWN_ERROR;
379        }
380    }
381
382    /* Reset the plugin state */
383    resetPlugin();
384
385    /* Set the run time (dynamic) parameters */
386    setParams(displayStride);
387
388    /* Set number of cores/threads to be used by the codec */
389    setNumCores();
390
391    /* Get codec version */
392    logVersion();
393
394    /* Allocate internal picture buffer */
395    uint32_t bufferSize = displaySizeY * 3 / 2;
396    mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
397    if (NULL == mFlushOutBuffer) {
398        ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
399        return NO_MEMORY;
400    }
401
402    mInitNeeded = false;
403    mFlushNeeded = false;
404    return OK;
405}
406
407status_t SoftMPEG2::deInitDecoder() {
408    size_t i;
409
410    if (mMemRecords) {
411        iv_mem_rec_t *ps_mem_rec;
412
413        ps_mem_rec = mMemRecords;
414        for (i = 0; i < mNumMemRecords; i++) {
415            if (ps_mem_rec->pv_base) {
416                ivd_aligned_free(ps_mem_rec->pv_base);
417            }
418            ps_mem_rec++;
419        }
420        ivd_aligned_free(mMemRecords);
421        mMemRecords = NULL;
422    }
423
424    if (mFlushOutBuffer) {
425        ivd_aligned_free(mFlushOutBuffer);
426        mFlushOutBuffer = NULL;
427    }
428
429    mInitNeeded = true;
430    mChangingResolution = false;
431
432    return OK;
433}
434
435status_t SoftMPEG2::reInitDecoder() {
436    status_t ret;
437
438    deInitDecoder();
439
440    ret = initDecoder();
441    if (OK != ret) {
442        ALOGE("Create failure");
443        deInitDecoder();
444        return NO_MEMORY;
445    }
446    return OK;
447}
448
449void SoftMPEG2::onReset() {
450    SoftVideoDecoderOMXComponent::onReset();
451
452    mWaitForI = true;
453
454    resetDecoder();
455    resetPlugin();
456}
457
458OMX_ERRORTYPE SoftMPEG2::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
459    const uint32_t oldWidth = mWidth;
460    const uint32_t oldHeight = mHeight;
461    OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
462    if (mWidth != oldWidth || mHeight != oldHeight) {
463        reInitDecoder();
464    }
465    return ret;
466}
467
468void SoftMPEG2::setDecodeArgs(
469        ivd_video_decode_ip_t *ps_dec_ip,
470        ivd_video_decode_op_t *ps_dec_op,
471        OMX_BUFFERHEADERTYPE *inHeader,
472        OMX_BUFFERHEADERTYPE *outHeader,
473        size_t timeStampIx) {
474    size_t sizeY = outputBufferWidth() * outputBufferHeight();
475    size_t sizeUV;
476    uint8_t *pBuf;
477
478    ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
479    ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
480
481    ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
482
483    /* When in flush and after EOS with zero byte input,
484     * inHeader is set to zero. Hence check for non-null */
485    if (inHeader) {
486        ps_dec_ip->u4_ts = timeStampIx;
487        ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
488                + inHeader->nOffset;
489        ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
490    } else {
491        ps_dec_ip->u4_ts = 0;
492        ps_dec_ip->pv_stream_buffer = NULL;
493        ps_dec_ip->u4_num_Bytes = 0;
494    }
495
496    if (outHeader) {
497        pBuf = outHeader->pBuffer;
498    } else {
499        pBuf = mFlushOutBuffer;
500    }
501
502    sizeUV = sizeY / 4;
503    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
504    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
505    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
506
507    ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
508    ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
509    ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
510    ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
511    return;
512}
513void SoftMPEG2::onPortFlushCompleted(OMX_U32 portIndex) {
514    /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
515    if (kOutputPortIndex == portIndex) {
516        setFlushMode();
517
518        while (true) {
519            ivd_video_decode_ip_t s_dec_ip;
520            ivd_video_decode_op_t s_dec_op;
521            IV_API_CALL_STATUS_T status;
522            size_t sizeY, sizeUV;
523
524            setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
525
526            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
527            if (0 == s_dec_op.u4_output_present) {
528                resetPlugin();
529                break;
530            }
531        }
532    }
533}
534
535void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
536    UNUSED(portIndex);
537
538    if (mOutputPortSettingsChange != NONE) {
539        return;
540    }
541
542    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
543    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
544
545    /* If input EOS is seen and decoder is not in flush mode,
546     * set the decoder in flush mode.
547     * There can be a case where EOS is sent along with last picture data
548     * In that case, only after decoding that input data, decoder has to be
549     * put in flush. This case is handled here  */
550
551    if (mReceivedEOS && !mIsInFlush) {
552        setFlushMode();
553    }
554
555    while (!outQueue.empty()) {
556        BufferInfo *inInfo;
557        OMX_BUFFERHEADERTYPE *inHeader;
558
559        BufferInfo *outInfo;
560        OMX_BUFFERHEADERTYPE *outHeader;
561        size_t timeStampIx;
562
563        inInfo = NULL;
564        inHeader = NULL;
565
566        if (!mIsInFlush) {
567            if (!inQueue.empty()) {
568                inInfo = *inQueue.begin();
569                inHeader = inInfo->mHeader;
570            } else {
571                break;
572            }
573        }
574
575        outInfo = *outQueue.begin();
576        outHeader = outInfo->mHeader;
577        outHeader->nFlags = 0;
578        outHeader->nTimeStamp = 0;
579        outHeader->nOffset = 0;
580
581        if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
582            mReceivedEOS = true;
583            if (inHeader->nFilledLen == 0) {
584                inQueue.erase(inQueue.begin());
585                inInfo->mOwnedByUs = false;
586                notifyEmptyBufferDone(inHeader);
587                inHeader = NULL;
588                setFlushMode();
589            }
590        }
591
592        // When there is an init required and the decoder is not in flush mode,
593        // update output port's definition and reinitialize decoder.
594        if (mInitNeeded && !mIsInFlush) {
595            bool portWillReset = false;
596            handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
597
598            CHECK_EQ(reInitDecoder(), (status_t)OK);
599            return;
600        }
601
602        /* Get a free slot in timestamp array to hold input timestamp */
603        {
604            size_t i;
605            timeStampIx = 0;
606            for (i = 0; i < MAX_TIME_STAMPS; i++) {
607                if (!mTimeStampsValid[i]) {
608                    timeStampIx = i;
609                    break;
610                }
611            }
612            if (inHeader != NULL) {
613                mTimeStampsValid[timeStampIx] = true;
614                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
615            }
616        }
617
618        {
619            ivd_video_decode_ip_t s_dec_ip;
620            ivd_video_decode_op_t s_dec_op;
621            WORD32 timeDelay, timeTaken;
622            size_t sizeY, sizeUV;
623
624            setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
625            // If input dump is enabled, then write to file
626            DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes);
627
628            if (s_dec_ip.u4_num_Bytes > 0) {
629                char *ptr = (char *)s_dec_ip.pv_stream_buffer;
630            }
631
632            GETTIME(&mTimeStart, NULL);
633            /* Compute time elapsed between end of previous decode()
634             * to start of current decode() */
635            TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
636
637            IV_API_CALL_STATUS_T status;
638            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
639
640            bool unsupportedDimensions = (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code);
641            bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
642
643            GETTIME(&mTimeEnd, NULL);
644            /* Compute time taken for decode() */
645            TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
646
647            ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
648                   s_dec_op.u4_num_bytes_consumed);
649            if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
650                mFlushNeeded = true;
651            }
652
653            if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
654                /* If the input did not contain picture data, then ignore
655                 * the associated timestamp */
656                mTimeStampsValid[timeStampIx] = false;
657            }
658
659            // This is needed to handle CTS DecoderTest testCodecResetsMPEG2WithoutSurface,
660            // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
661            if (unsupportedDimensions && !mFlushNeeded) {
662                bool portWillReset = false;
663                handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
664
665                CHECK_EQ(reInitDecoder(), (status_t)OK);
666
667                setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
668
669                ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
670                return;
671            }
672
673            // If the decoder is in the changing resolution mode and there is no output present,
674            // that means the switching is done and it's ready to reset the decoder and the plugin.
675            if (mChangingResolution && !s_dec_op.u4_output_present) {
676                mChangingResolution = false;
677                resetDecoder();
678                resetPlugin();
679                continue;
680            }
681
682            if (unsupportedDimensions || resChanged) {
683                mChangingResolution = true;
684                if (mFlushNeeded) {
685                    setFlushMode();
686                }
687
688                if (unsupportedDimensions) {
689                    mNewWidth = s_dec_op.u4_pic_wd;
690                    mNewHeight = s_dec_op.u4_pic_ht;
691                    mInitNeeded = true;
692                }
693                continue;
694            }
695
696            if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
697                uint32_t width = s_dec_op.u4_pic_wd;
698                uint32_t height = s_dec_op.u4_pic_ht;
699                bool portWillReset = false;
700                handlePortSettingsChange(&portWillReset, width, height);
701
702                if (portWillReset) {
703                    resetDecoder();
704                    return;
705                }
706            }
707
708            if (s_dec_op.u4_output_present) {
709                size_t timeStampIdx;
710                outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
711
712                timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
713                outHeader->nTimeStamp = mTimeStamps[timeStampIdx];
714                mTimeStampsValid[timeStampIdx] = false;
715
716                /* mWaitForI waits for the first I picture. Once made FALSE, it
717                   has to remain false till explicitly set to TRUE. */
718                mWaitForI = mWaitForI && !(IV_I_FRAME == s_dec_op.e_pic_type);
719
720                if (mWaitForI) {
721                    s_dec_op.u4_output_present = false;
722                } else {
723                    ALOGV("Output timestamp: %lld, res: %ux%u",
724                            (long long)outHeader->nTimeStamp, mWidth, mHeight);
725                    DUMP_TO_FILE(mOutFile, outHeader->pBuffer, outHeader->nFilledLen);
726                    outInfo->mOwnedByUs = false;
727                    outQueue.erase(outQueue.begin());
728                    outInfo = NULL;
729                    notifyFillBufferDone(outHeader);
730                    outHeader = NULL;
731                }
732            } else {
733                /* If in flush mode and no output is returned by the codec,
734                 * then come out of flush mode */
735                mIsInFlush = false;
736
737                /* If EOS was recieved on input port and there is no output
738                 * from the codec, then signal EOS on output port */
739                if (mReceivedEOS) {
740                    outHeader->nFilledLen = 0;
741                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
742
743                    outInfo->mOwnedByUs = false;
744                    outQueue.erase(outQueue.begin());
745                    outInfo = NULL;
746                    notifyFillBufferDone(outHeader);
747                    outHeader = NULL;
748                    resetPlugin();
749                }
750            }
751        }
752
753        // TODO: Handle more than one picture data
754        if (inHeader != NULL) {
755            inInfo->mOwnedByUs = false;
756            inQueue.erase(inQueue.begin());
757            inInfo = NULL;
758            notifyEmptyBufferDone(inHeader);
759            inHeader = NULL;
760        }
761    }
762}
763
764}  // namespace android
765
766android::SoftOMXComponent *createSoftOMXComponent(
767        const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
768        OMX_COMPONENTTYPE **component) {
769    return new android::SoftMPEG2(name, callbacks, appData, component);
770}
771