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