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_MPEG2LevelHL  },
51
52    { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelHL  },
53};
54
55SoftMPEG2::SoftMPEG2(
56        const char *name,
57        const OMX_CALLBACKTYPE *callbacks,
58        OMX_PTR appData,
59        OMX_COMPONENTTYPE **component)
60    : SoftVideoDecoderOMXComponent(
61            name, componentName, codingType,
62            kProfileLevels, ARRAY_SIZE(kProfileLevels),
63            320 /* width */, 240 /* height */, callbacks,
64            appData, component),
65      mCodecCtx(NULL),
66      mMemRecords(NULL),
67      mFlushOutBuffer(NULL),
68      mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
69      mIvColorFormat(IV_YUV_420P),
70      mNewWidth(mWidth),
71      mNewHeight(mHeight),
72      mChangingResolution(false),
73      mSignalledError(false),
74      mStride(mWidth) {
75    initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers, CODEC_MIME_TYPE);
76
77    // If input dump is enabled, then open create an empty file
78    GENERATE_FILE_NAMES();
79    CREATE_DUMP_FILE(mInFile);
80}
81
82SoftMPEG2::~SoftMPEG2() {
83    if (OK != deInitDecoder()) {
84        ALOGE("Failed to deinit decoder");
85        notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
86        mSignalledError = true;
87        return;
88    }
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    mStride = 0;
206    mSignalledError = false;
207
208    return OK;
209}
210
211status_t SoftMPEG2::setNumCores() {
212    ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
213    ivdext_ctl_set_num_cores_op_t s_set_cores_op;
214    IV_API_CALL_STATUS_T status;
215    s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
216    s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
217    s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
218    s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
219    s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
220
221    status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip, (void *)&s_set_cores_op);
222    if (IV_SUCCESS != status) {
223        ALOGE("Error in setting number of cores: 0x%x",
224                s_set_cores_op.u4_error_code);
225        return UNKNOWN_ERROR;
226    }
227    return OK;
228}
229
230status_t SoftMPEG2::setFlushMode() {
231    IV_API_CALL_STATUS_T status;
232    ivd_ctl_flush_ip_t s_video_flush_ip;
233    ivd_ctl_flush_op_t s_video_flush_op;
234
235    s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
236    s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
237    s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
238    s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
239
240    /* Set the decoder in Flush mode, subsequent decode() calls will flush */
241    status = ivdec_api_function(
242            mCodecCtx, (void *)&s_video_flush_ip, (void *)&s_video_flush_op);
243
244    if (status != IV_SUCCESS) {
245        ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
246                s_video_flush_op.u4_error_code);
247        return UNKNOWN_ERROR;
248    }
249
250    mWaitForI = true;
251    mIsInFlush = true;
252    return OK;
253}
254
255status_t SoftMPEG2::initDecoder() {
256    IV_API_CALL_STATUS_T status;
257
258    UWORD32 u4_num_reorder_frames;
259    UWORD32 u4_num_ref_frames;
260    UWORD32 u4_share_disp_buf;
261
262    mNumCores = GetCPUCoreCount();
263    mWaitForI = true;
264
265    /* Initialize number of ref and reorder modes (for MPEG2) */
266    u4_num_reorder_frames = 16;
267    u4_num_ref_frames = 16;
268    u4_share_disp_buf = 0;
269
270    uint32_t displayStride = outputBufferWidth();
271    uint32_t displayHeight = outputBufferHeight();
272    uint32_t displaySizeY = displayStride * displayHeight;
273
274    {
275        iv_num_mem_rec_ip_t s_num_mem_rec_ip;
276        iv_num_mem_rec_op_t s_num_mem_rec_op;
277
278        s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
279        s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
280        s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
281
282        status = ivdec_api_function(
283                mCodecCtx, (void *)&s_num_mem_rec_ip, (void *)&s_num_mem_rec_op);
284        if (IV_SUCCESS != status) {
285            ALOGE("Error in getting mem records: 0x%x",
286                    s_num_mem_rec_op.u4_error_code);
287            return UNKNOWN_ERROR;
288        }
289
290        mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
291    }
292
293    mMemRecords = (iv_mem_rec_t *)ivd_aligned_malloc(
294            128, mNumMemRecords * sizeof(iv_mem_rec_t));
295    if (mMemRecords == NULL) {
296        ALOGE("Allocation failure");
297        return NO_MEMORY;
298    }
299
300    memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
301
302    {
303        size_t i;
304        ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
305        ivdext_fill_mem_rec_op_t s_fill_mem_op;
306        iv_mem_rec_t *ps_mem_rec;
307
308        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
309            sizeof(ivdext_fill_mem_rec_ip_t);
310
311        s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf;
312        s_fill_mem_ip.e_output_format = mIvColorFormat;
313        s_fill_mem_ip.u4_deinterlace = 1;
314        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
315        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
316        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride;
317        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight;
318        s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
319            sizeof(ivdext_fill_mem_rec_op_t);
320
321        ps_mem_rec = mMemRecords;
322        for (i = 0; i < mNumMemRecords; i++) {
323            ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
324        }
325
326        status = ivdec_api_function(
327                mCodecCtx, (void *)&s_fill_mem_ip, (void *)&s_fill_mem_op);
328
329        if (IV_SUCCESS != status) {
330            ALOGE("Error in filling mem records: 0x%x",
331                    s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
332            return UNKNOWN_ERROR;
333        }
334        mNumMemRecords =
335            s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
336
337        ps_mem_rec = mMemRecords;
338
339        for (i = 0; i < mNumMemRecords; i++) {
340            ps_mem_rec->pv_base = ivd_aligned_malloc(
341                    ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
342            if (ps_mem_rec->pv_base == NULL) {
343                ALOGE("Allocation failure for memory record #%zu of size %u",
344                        i, ps_mem_rec->u4_mem_size);
345                status = IV_FAIL;
346                return NO_MEMORY;
347            }
348
349            ps_mem_rec++;
350        }
351    }
352
353    /* Initialize the decoder */
354    {
355        ivdext_init_ip_t s_init_ip;
356        ivdext_init_op_t s_init_op;
357
358        void *dec_fxns = (void *)ivdec_api_function;
359
360        s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
361        s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
362        s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
363        s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride;
364        s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight;
365
366        s_init_ip.u4_share_disp_buf = u4_share_disp_buf;
367        s_init_ip.u4_deinterlace = 1;
368
369        s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op);
370
371        s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
372        s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat;
373
374        mCodecCtx = (iv_obj_t *)mMemRecords[0].pv_base;
375        mCodecCtx->pv_fxns = dec_fxns;
376        mCodecCtx->u4_size = sizeof(iv_obj_t);
377
378        status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip, (void *)&s_init_op);
379        if (status != IV_SUCCESS) {
380            ALOGE("Error in init: 0x%x",
381                    s_init_op.s_ivd_init_op_t.u4_error_code);
382            return UNKNOWN_ERROR;
383        }
384    }
385
386    /* Reset the plugin state */
387    resetPlugin();
388
389    /* Set the run time (dynamic) parameters */
390    mStride = outputBufferWidth();
391    setParams(mStride);
392
393    /* Set number of cores/threads to be used by the codec */
394    setNumCores();
395
396    /* Get codec version */
397    logVersion();
398
399    /* Allocate internal picture buffer */
400    uint32_t bufferSize = displaySizeY * 3 / 2;
401    mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
402    if (NULL == mFlushOutBuffer) {
403        ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
404        return NO_MEMORY;
405    }
406
407    mInitNeeded = false;
408    mFlushNeeded = false;
409    return OK;
410}
411
412status_t SoftMPEG2::deInitDecoder() {
413    size_t i;
414
415    if (mMemRecords) {
416        iv_mem_rec_t *ps_mem_rec;
417
418        ps_mem_rec = mMemRecords;
419        for (i = 0; i < mNumMemRecords; i++) {
420            if (ps_mem_rec->pv_base) {
421                ivd_aligned_free(ps_mem_rec->pv_base);
422            }
423            ps_mem_rec++;
424        }
425        ivd_aligned_free(mMemRecords);
426        mMemRecords = NULL;
427    }
428
429    if (mFlushOutBuffer) {
430        ivd_aligned_free(mFlushOutBuffer);
431        mFlushOutBuffer = NULL;
432    }
433
434    mInitNeeded = true;
435    mChangingResolution = false;
436    mCodecCtx = NULL;
437
438    return OK;
439}
440
441status_t SoftMPEG2::reInitDecoder() {
442    status_t ret;
443
444    deInitDecoder();
445
446    ret = initDecoder();
447    if (OK != ret) {
448        ALOGE("Failed to initialize decoder");
449        deInitDecoder();
450        return ret;
451    }
452    mSignalledError = false;
453    return OK;
454}
455
456void SoftMPEG2::onReset() {
457    SoftVideoDecoderOMXComponent::onReset();
458
459    mWaitForI = true;
460
461    resetDecoder();
462    resetPlugin();
463}
464
465bool SoftMPEG2::getSeqInfo() {
466    IV_API_CALL_STATUS_T status;
467    impeg2d_ctl_get_seq_info_ip_t s_ctl_get_seq_info_ip;
468    impeg2d_ctl_get_seq_info_op_t s_ctl_get_seq_info_op;
469
470    s_ctl_get_seq_info_ip.e_cmd = IVD_CMD_VIDEO_CTL;
471    s_ctl_get_seq_info_ip.e_sub_cmd =
472        (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_GET_SEQ_INFO;
473
474    s_ctl_get_seq_info_ip.u4_size = sizeof(impeg2d_ctl_get_seq_info_ip_t);
475    s_ctl_get_seq_info_op.u4_size = sizeof(impeg2d_ctl_get_seq_info_op_t);
476
477    status = ivdec_api_function(
478            (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_seq_info_ip,
479            (void *)&s_ctl_get_seq_info_op);
480
481    if (status != IV_SUCCESS) {
482        ALOGW("Error in getting Sequence info: 0x%x",
483                s_ctl_get_seq_info_op.u4_error_code);
484        return false;
485    }
486
487
488    int32_t primaries = s_ctl_get_seq_info_op.u1_colour_primaries;
489    int32_t transfer = s_ctl_get_seq_info_op.u1_transfer_characteristics;
490    int32_t coeffs = s_ctl_get_seq_info_op.u1_matrix_coefficients;
491    bool fullRange = false;  // mpeg2 video has limited range.
492
493    ColorAspects colorAspects;
494    ColorUtils::convertIsoColorAspectsToCodecAspects(
495            primaries, transfer, coeffs, fullRange, colorAspects);
496
497    // Update color aspects if necessary.
498    if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
499        mBitstreamColorAspects = colorAspects;
500        status_t err = handleColorAspectsChange();
501        CHECK(err == OK);
502    }
503    return true;
504}
505
506OMX_ERRORTYPE SoftMPEG2::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
507    const uint32_t oldWidth = mWidth;
508    const uint32_t oldHeight = mHeight;
509    OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
510    if (mWidth != oldWidth || mHeight != oldHeight) {
511        reInitDecoder();
512    }
513    return ret;
514}
515
516bool SoftMPEG2::setDecodeArgs(
517        ivd_video_decode_ip_t *ps_dec_ip,
518        ivd_video_decode_op_t *ps_dec_op,
519        OMX_BUFFERHEADERTYPE *inHeader,
520        OMX_BUFFERHEADERTYPE *outHeader,
521        size_t timeStampIx) {
522    size_t sizeY = outputBufferWidth() * outputBufferHeight();
523    size_t sizeUV;
524
525    ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
526    ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
527
528    ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
529
530    /* When in flush and after EOS with zero byte input,
531     * inHeader is set to zero. Hence check for non-null */
532    if (inHeader) {
533        ps_dec_ip->u4_ts = timeStampIx;
534        ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
535                + inHeader->nOffset;
536        ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
537    } else {
538        ps_dec_ip->u4_ts = 0;
539        ps_dec_ip->pv_stream_buffer = NULL;
540        ps_dec_ip->u4_num_Bytes = 0;
541    }
542
543    sizeUV = sizeY / 4;
544    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
545    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
546    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
547
548    uint8_t *pBuf;
549    if (outHeader) {
550        if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
551            android_errorWriteLog(0x534e4554, "27833616");
552            return false;
553        }
554        pBuf = outHeader->pBuffer;
555    } else {
556        // mFlushOutBuffer always has the right size.
557        pBuf = mFlushOutBuffer;
558    }
559
560    ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
561    ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
562    ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
563    ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
564    return true;
565}
566void SoftMPEG2::onPortFlushCompleted(OMX_U32 portIndex) {
567    /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
568    if (kOutputPortIndex == portIndex) {
569        setFlushMode();
570
571        while (true) {
572            ivd_video_decode_ip_t s_dec_ip;
573            ivd_video_decode_op_t s_dec_op;
574            IV_API_CALL_STATUS_T status;
575            size_t sizeY, sizeUV;
576
577            setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
578
579            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
580            if (0 == s_dec_op.u4_output_present) {
581                resetPlugin();
582                break;
583            }
584        }
585    }
586}
587
588void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
589    UNUSED(portIndex);
590
591    if (mSignalledError) {
592        return;
593    }
594    if (mOutputPortSettingsChange != NONE) {
595        return;
596    }
597
598    if (NULL == mCodecCtx) {
599        if (OK != initDecoder()) {
600            ALOGE("Failed to initialize decoder");
601            notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
602            mSignalledError = true;
603            return;
604        }
605    }
606
607    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
608    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
609
610    if (outputBufferWidth() != mStride) {
611        /* Set the run-time (dynamic) parameters */
612        mStride = outputBufferWidth();
613        setParams(mStride);
614    }
615
616    while (!outQueue.empty()) {
617        BufferInfo *inInfo;
618        OMX_BUFFERHEADERTYPE *inHeader;
619
620        BufferInfo *outInfo;
621        OMX_BUFFERHEADERTYPE *outHeader;
622        size_t timeStampIx;
623
624        inInfo = NULL;
625        inHeader = NULL;
626
627        if (!mIsInFlush) {
628            if (!inQueue.empty()) {
629                inInfo = *inQueue.begin();
630                inHeader = inInfo->mHeader;
631            } else {
632                break;
633            }
634        }
635
636        outInfo = *outQueue.begin();
637        outHeader = outInfo->mHeader;
638        outHeader->nFlags = 0;
639        outHeader->nTimeStamp = 0;
640        outHeader->nOffset = 0;
641
642        if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
643            mReceivedEOS = true;
644            if (inHeader->nFilledLen == 0) {
645                inQueue.erase(inQueue.begin());
646                inInfo->mOwnedByUs = false;
647                notifyEmptyBufferDone(inHeader);
648                inHeader = NULL;
649                setFlushMode();
650            }
651        }
652
653        // When there is an init required and the decoder is not in flush mode,
654        // update output port's definition and reinitialize decoder.
655        if (mInitNeeded && !mIsInFlush) {
656            bool portWillReset = false;
657            handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
658
659            if (OK != reInitDecoder()) {
660                ALOGE("Failed to reinitialize decoder");
661            }
662            return;
663        }
664
665        /* Get a free slot in timestamp array to hold input timestamp */
666        {
667            size_t i;
668            timeStampIx = 0;
669            for (i = 0; i < MAX_TIME_STAMPS; i++) {
670                if (!mTimeStampsValid[i]) {
671                    timeStampIx = i;
672                    break;
673                }
674            }
675            if (inHeader != NULL) {
676                mTimeStampsValid[timeStampIx] = true;
677                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
678            }
679        }
680
681        {
682            ivd_video_decode_ip_t s_dec_ip;
683            ivd_video_decode_op_t s_dec_op;
684            WORD32 timeDelay, timeTaken;
685            size_t sizeY, sizeUV;
686
687            if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
688                ALOGE("Decoder arg setup failed");
689                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
690                return;
691            }
692            // If input dump is enabled, then write to file
693            DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes);
694
695            if (s_dec_ip.u4_num_Bytes > 0) {
696                char *ptr = (char *)s_dec_ip.pv_stream_buffer;
697            }
698
699            GETTIME(&mTimeStart, NULL);
700            /* Compute time elapsed between end of previous decode()
701             * to start of current decode() */
702            TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
703
704            IV_API_CALL_STATUS_T status;
705            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
706
707            bool unsupportedDimensions = (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code);
708            bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
709
710            getSeqInfo();
711
712            GETTIME(&mTimeEnd, NULL);
713            /* Compute time taken for decode() */
714            TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
715
716            ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
717                   s_dec_op.u4_num_bytes_consumed);
718            if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
719                mFlushNeeded = true;
720            }
721
722            if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
723                /* If the input did not contain picture data, then ignore
724                 * the associated timestamp */
725                mTimeStampsValid[timeStampIx] = false;
726            }
727
728            // This is needed to handle CTS DecoderTest testCodecResetsMPEG2WithoutSurface,
729            // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
730            if (unsupportedDimensions && !mFlushNeeded) {
731                bool portWillReset = false;
732                handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
733
734                if (OK != reInitDecoder()) {
735                    ALOGE("Failed to reinitialize decoder");
736                    return;
737                }
738
739                if (setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
740                    ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
741                }
742                return;
743            }
744
745            // If the decoder is in the changing resolution mode and there is no output present,
746            // that means the switching is done and it's ready to reset the decoder and the plugin.
747            if (mChangingResolution && !s_dec_op.u4_output_present) {
748                mChangingResolution = false;
749                resetDecoder();
750                resetPlugin();
751                mStride = outputBufferWidth();
752                setParams(mStride);
753                continue;
754            }
755
756            if (unsupportedDimensions || resChanged) {
757                mChangingResolution = true;
758                if (mFlushNeeded) {
759                    setFlushMode();
760                }
761
762                if (unsupportedDimensions) {
763                    mNewWidth = s_dec_op.u4_pic_wd;
764                    mNewHeight = s_dec_op.u4_pic_ht;
765                    mInitNeeded = true;
766                }
767                continue;
768            }
769
770            // Combine the resolution change and coloraspects change in one PortSettingChange event
771            // if necessary.
772            if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
773                uint32_t width = s_dec_op.u4_pic_wd;
774                uint32_t height = s_dec_op.u4_pic_ht;
775                bool portWillReset = false;
776                handlePortSettingsChange(&portWillReset, width, height);
777
778                if (portWillReset) {
779                    resetDecoder();
780                    resetPlugin();
781                    return;
782                }
783            } else if (mUpdateColorAspects) {
784                notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
785                    kDescribeColorAspectsIndex, NULL);
786                mUpdateColorAspects = false;
787                return;
788            }
789
790            if (s_dec_op.u4_output_present) {
791                size_t timeStampIdx;
792                outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
793
794                timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
795                outHeader->nTimeStamp = mTimeStamps[timeStampIdx];
796                mTimeStampsValid[timeStampIdx] = false;
797
798                /* mWaitForI waits for the first I picture. Once made FALSE, it
799                   has to remain false till explicitly set to TRUE. */
800                mWaitForI = mWaitForI && !(IV_I_FRAME == s_dec_op.e_pic_type);
801
802                if (mWaitForI) {
803                    s_dec_op.u4_output_present = false;
804                } else {
805                    ALOGV("Output timestamp: %lld, res: %ux%u",
806                            (long long)outHeader->nTimeStamp, mWidth, mHeight);
807                    DUMP_TO_FILE(mOutFile, outHeader->pBuffer, outHeader->nFilledLen);
808                    outInfo->mOwnedByUs = false;
809                    outQueue.erase(outQueue.begin());
810                    outInfo = NULL;
811                    notifyFillBufferDone(outHeader);
812                    outHeader = NULL;
813                }
814            } else if (mIsInFlush) {
815                /* If in flush mode and no output is returned by the codec,
816                 * then come out of flush mode */
817                mIsInFlush = false;
818
819                /* If EOS was recieved on input port and there is no output
820                 * from the codec, then signal EOS on output port */
821                if (mReceivedEOS) {
822                    outHeader->nFilledLen = 0;
823                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
824
825                    outInfo->mOwnedByUs = false;
826                    outQueue.erase(outQueue.begin());
827                    outInfo = NULL;
828                    notifyFillBufferDone(outHeader);
829                    outHeader = NULL;
830                    resetPlugin();
831                }
832            }
833        }
834
835        /* If input EOS is seen and decoder is not in flush mode,
836         * set the decoder in flush mode.
837         * There can be a case where EOS is sent along with last picture data
838         * In that case, only after decoding that input data, decoder has to be
839         * put in flush. This case is handled here  */
840
841        if (mReceivedEOS && !mIsInFlush) {
842            setFlushMode();
843        }
844
845        // TODO: Handle more than one picture data
846        if (inHeader != NULL) {
847            inInfo->mOwnedByUs = false;
848            inQueue.erase(inQueue.begin());
849            inInfo = NULL;
850            notifyEmptyBufferDone(inHeader);
851            inHeader = NULL;
852        }
853    }
854}
855
856int SoftMPEG2::getColorAspectPreference() {
857    return kPreferBitstream;
858}
859
860}  // namespace android
861
862android::SoftOMXComponent *createSoftOMXComponent(
863        const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
864        OMX_COMPONENTTYPE **component) {
865    return new android::SoftMPEG2(name, callbacks, appData, component);
866}
867