Home | History | Annotate | Download | only in mpeg2dec
      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 
     31 namespace 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 
     49 static 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 
     61 SoftMPEG2::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       mStride(mWidth) {
     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 
     88 SoftMPEG2::~SoftMPEG2() {
     89     CHECK_EQ(deInitDecoder(), (status_t)OK);
     90 }
     91 
     92 
     93 static 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 
    107 static 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 
    120 void 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 
    145 status_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 = %zu", 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 
    171 status_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 
    184 status_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     mStride = 0;
    207 
    208     return OK;
    209 }
    210 
    211 status_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 
    230 status_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 
    255 status_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 
    412 status_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 
    437     return OK;
    438 }
    439 
    440 status_t SoftMPEG2::reInitDecoder() {
    441     status_t ret;
    442 
    443     deInitDecoder();
    444 
    445     ret = initDecoder();
    446     if (OK != ret) {
    447         ALOGE("Create failure");
    448         deInitDecoder();
    449         return NO_MEMORY;
    450     }
    451     return OK;
    452 }
    453 
    454 void SoftMPEG2::onReset() {
    455     SoftVideoDecoderOMXComponent::onReset();
    456 
    457     mWaitForI = true;
    458 
    459     resetDecoder();
    460     resetPlugin();
    461 }
    462 
    463 OMX_ERRORTYPE SoftMPEG2::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
    464     const uint32_t oldWidth = mWidth;
    465     const uint32_t oldHeight = mHeight;
    466     OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
    467     if (mWidth != oldWidth || mHeight != oldHeight) {
    468         reInitDecoder();
    469     }
    470     return ret;
    471 }
    472 
    473 bool SoftMPEG2::setDecodeArgs(
    474         ivd_video_decode_ip_t *ps_dec_ip,
    475         ivd_video_decode_op_t *ps_dec_op,
    476         OMX_BUFFERHEADERTYPE *inHeader,
    477         OMX_BUFFERHEADERTYPE *outHeader,
    478         size_t timeStampIx) {
    479     size_t sizeY = outputBufferWidth() * outputBufferHeight();
    480     size_t sizeUV;
    481 
    482     ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
    483     ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
    484 
    485     ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
    486 
    487     /* When in flush and after EOS with zero byte input,
    488      * inHeader is set to zero. Hence check for non-null */
    489     if (inHeader) {
    490         ps_dec_ip->u4_ts = timeStampIx;
    491         ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
    492                 + inHeader->nOffset;
    493         ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
    494     } else {
    495         ps_dec_ip->u4_ts = 0;
    496         ps_dec_ip->pv_stream_buffer = NULL;
    497         ps_dec_ip->u4_num_Bytes = 0;
    498     }
    499 
    500     sizeUV = sizeY / 4;
    501     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
    502     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
    503     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
    504 
    505     uint8_t *pBuf;
    506     if (outHeader) {
    507         if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
    508             android_errorWriteLog(0x534e4554, "27833616");
    509             return false;
    510         }
    511         pBuf = outHeader->pBuffer;
    512     } else {
    513         // mFlushOutBuffer always has the right size.
    514         pBuf = mFlushOutBuffer;
    515     }
    516 
    517     ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
    518     ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
    519     ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
    520     ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
    521     return true;
    522 }
    523 void SoftMPEG2::onPortFlushCompleted(OMX_U32 portIndex) {
    524     /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
    525     if (kOutputPortIndex == portIndex) {
    526         setFlushMode();
    527 
    528         while (true) {
    529             ivd_video_decode_ip_t s_dec_ip;
    530             ivd_video_decode_op_t s_dec_op;
    531             IV_API_CALL_STATUS_T status;
    532             size_t sizeY, sizeUV;
    533 
    534             setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
    535 
    536             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    537             if (0 == s_dec_op.u4_output_present) {
    538                 resetPlugin();
    539                 break;
    540             }
    541         }
    542     }
    543 }
    544 
    545 void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    546     UNUSED(portIndex);
    547 
    548     if (mOutputPortSettingsChange != NONE) {
    549         return;
    550     }
    551 
    552     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
    553     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
    554 
    555     if (outputBufferWidth() != mStride) {
    556         /* Set the run-time (dynamic) parameters */
    557         mStride = outputBufferWidth();
    558         setParams(mStride);
    559     }
    560 
    561     while (!outQueue.empty()) {
    562         BufferInfo *inInfo;
    563         OMX_BUFFERHEADERTYPE *inHeader;
    564 
    565         BufferInfo *outInfo;
    566         OMX_BUFFERHEADERTYPE *outHeader;
    567         size_t timeStampIx;
    568 
    569         inInfo = NULL;
    570         inHeader = NULL;
    571 
    572         if (!mIsInFlush) {
    573             if (!inQueue.empty()) {
    574                 inInfo = *inQueue.begin();
    575                 inHeader = inInfo->mHeader;
    576             } else {
    577                 break;
    578             }
    579         }
    580 
    581         outInfo = *outQueue.begin();
    582         outHeader = outInfo->mHeader;
    583         outHeader->nFlags = 0;
    584         outHeader->nTimeStamp = 0;
    585         outHeader->nOffset = 0;
    586 
    587         if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
    588             mReceivedEOS = true;
    589             if (inHeader->nFilledLen == 0) {
    590                 inQueue.erase(inQueue.begin());
    591                 inInfo->mOwnedByUs = false;
    592                 notifyEmptyBufferDone(inHeader);
    593                 inHeader = NULL;
    594                 setFlushMode();
    595             }
    596         }
    597 
    598         // When there is an init required and the decoder is not in flush mode,
    599         // update output port's definition and reinitialize decoder.
    600         if (mInitNeeded && !mIsInFlush) {
    601             bool portWillReset = false;
    602             handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
    603 
    604             CHECK_EQ(reInitDecoder(), (status_t)OK);
    605             return;
    606         }
    607 
    608         /* Get a free slot in timestamp array to hold input timestamp */
    609         {
    610             size_t i;
    611             timeStampIx = 0;
    612             for (i = 0; i < MAX_TIME_STAMPS; i++) {
    613                 if (!mTimeStampsValid[i]) {
    614                     timeStampIx = i;
    615                     break;
    616                 }
    617             }
    618             if (inHeader != NULL) {
    619                 mTimeStampsValid[timeStampIx] = true;
    620                 mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
    621             }
    622         }
    623 
    624         {
    625             ivd_video_decode_ip_t s_dec_ip;
    626             ivd_video_decode_op_t s_dec_op;
    627             WORD32 timeDelay, timeTaken;
    628             size_t sizeY, sizeUV;
    629 
    630             if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
    631                 ALOGE("Decoder arg setup failed");
    632                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    633                 return;
    634             }
    635             // If input dump is enabled, then write to file
    636             DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes);
    637 
    638             if (s_dec_ip.u4_num_Bytes > 0) {
    639                 char *ptr = (char *)s_dec_ip.pv_stream_buffer;
    640             }
    641 
    642             GETTIME(&mTimeStart, NULL);
    643             /* Compute time elapsed between end of previous decode()
    644              * to start of current decode() */
    645             TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
    646 
    647             IV_API_CALL_STATUS_T status;
    648             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    649 
    650             bool unsupportedDimensions = (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code);
    651             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
    652 
    653             GETTIME(&mTimeEnd, NULL);
    654             /* Compute time taken for decode() */
    655             TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
    656 
    657             ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
    658                    s_dec_op.u4_num_bytes_consumed);
    659             if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
    660                 mFlushNeeded = true;
    661             }
    662 
    663             if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
    664                 /* If the input did not contain picture data, then ignore
    665                  * the associated timestamp */
    666                 mTimeStampsValid[timeStampIx] = false;
    667             }
    668 
    669             // This is needed to handle CTS DecoderTest testCodecResetsMPEG2WithoutSurface,
    670             // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
    671             if (unsupportedDimensions && !mFlushNeeded) {
    672                 bool portWillReset = false;
    673                 handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
    674 
    675                 CHECK_EQ(reInitDecoder(), (status_t)OK);
    676 
    677                 if (setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
    678                     ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    679                 }
    680                 return;
    681             }
    682 
    683             // If the decoder is in the changing resolution mode and there is no output present,
    684             // that means the switching is done and it's ready to reset the decoder and the plugin.
    685             if (mChangingResolution && !s_dec_op.u4_output_present) {
    686                 mChangingResolution = false;
    687                 resetDecoder();
    688                 resetPlugin();
    689                 mStride = outputBufferWidth();
    690                 setParams(mStride);
    691                 continue;
    692             }
    693 
    694             if (unsupportedDimensions || resChanged) {
    695                 mChangingResolution = true;
    696                 if (mFlushNeeded) {
    697                     setFlushMode();
    698                 }
    699 
    700                 if (unsupportedDimensions) {
    701                     mNewWidth = s_dec_op.u4_pic_wd;
    702                     mNewHeight = s_dec_op.u4_pic_ht;
    703                     mInitNeeded = true;
    704                 }
    705                 continue;
    706             }
    707 
    708             if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
    709                 uint32_t width = s_dec_op.u4_pic_wd;
    710                 uint32_t height = s_dec_op.u4_pic_ht;
    711                 bool portWillReset = false;
    712                 handlePortSettingsChange(&portWillReset, width, height);
    713 
    714                 if (portWillReset) {
    715                     resetDecoder();
    716                     return;
    717                 }
    718             }
    719 
    720             if (s_dec_op.u4_output_present) {
    721                 size_t timeStampIdx;
    722                 outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
    723 
    724                 timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
    725                 outHeader->nTimeStamp = mTimeStamps[timeStampIdx];
    726                 mTimeStampsValid[timeStampIdx] = false;
    727 
    728                 /* mWaitForI waits for the first I picture. Once made FALSE, it
    729                    has to remain false till explicitly set to TRUE. */
    730                 mWaitForI = mWaitForI && !(IV_I_FRAME == s_dec_op.e_pic_type);
    731 
    732                 if (mWaitForI) {
    733                     s_dec_op.u4_output_present = false;
    734                 } else {
    735                     ALOGV("Output timestamp: %lld, res: %ux%u",
    736                             (long long)outHeader->nTimeStamp, mWidth, mHeight);
    737                     DUMP_TO_FILE(mOutFile, outHeader->pBuffer, outHeader->nFilledLen);
    738                     outInfo->mOwnedByUs = false;
    739                     outQueue.erase(outQueue.begin());
    740                     outInfo = NULL;
    741                     notifyFillBufferDone(outHeader);
    742                     outHeader = NULL;
    743                 }
    744             } else if (mIsInFlush) {
    745                 /* If in flush mode and no output is returned by the codec,
    746                  * then come out of flush mode */
    747                 mIsInFlush = false;
    748 
    749                 /* If EOS was recieved on input port and there is no output
    750                  * from the codec, then signal EOS on output port */
    751                 if (mReceivedEOS) {
    752                     outHeader->nFilledLen = 0;
    753                     outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
    754 
    755                     outInfo->mOwnedByUs = false;
    756                     outQueue.erase(outQueue.begin());
    757                     outInfo = NULL;
    758                     notifyFillBufferDone(outHeader);
    759                     outHeader = NULL;
    760                     resetPlugin();
    761                 }
    762             }
    763         }
    764 
    765         /* If input EOS is seen and decoder is not in flush mode,
    766          * set the decoder in flush mode.
    767          * There can be a case where EOS is sent along with last picture data
    768          * In that case, only after decoding that input data, decoder has to be
    769          * put in flush. This case is handled here  */
    770 
    771         if (mReceivedEOS && !mIsInFlush) {
    772             setFlushMode();
    773         }
    774 
    775         // TODO: Handle more than one picture data
    776         if (inHeader != NULL) {
    777             inInfo->mOwnedByUs = false;
    778             inQueue.erase(inQueue.begin());
    779             inInfo = NULL;
    780             notifyEmptyBufferDone(inHeader);
    781             inHeader = NULL;
    782         }
    783     }
    784 }
    785 
    786 }  // namespace android
    787 
    788 android::SoftOMXComponent *createSoftOMXComponent(
    789         const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
    790         OMX_COMPONENTTYPE **component) {
    791     return new android::SoftMPEG2(name, callbacks, appData, component);
    792 }
    793