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