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 bool SoftMPEG2::getSeqInfo() {
    464     IV_API_CALL_STATUS_T status;
    465     impeg2d_ctl_get_seq_info_ip_t s_ctl_get_seq_info_ip;
    466     impeg2d_ctl_get_seq_info_op_t s_ctl_get_seq_info_op;
    467 
    468     s_ctl_get_seq_info_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    469     s_ctl_get_seq_info_ip.e_sub_cmd =
    470         (IVD_CONTROL_API_COMMAND_TYPE_T)IMPEG2D_CMD_CTL_GET_SEQ_INFO;
    471 
    472     s_ctl_get_seq_info_ip.u4_size = sizeof(impeg2d_ctl_get_seq_info_ip_t);
    473     s_ctl_get_seq_info_op.u4_size = sizeof(impeg2d_ctl_get_seq_info_op_t);
    474 
    475     status = ivdec_api_function(
    476             (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_seq_info_ip,
    477             (void *)&s_ctl_get_seq_info_op);
    478 
    479     if (status != IV_SUCCESS) {
    480         ALOGW("Error in getting Sequence info: 0x%x",
    481                 s_ctl_get_seq_info_op.u4_error_code);
    482         return false;
    483     }
    484 
    485 
    486     int32_t primaries = s_ctl_get_seq_info_op.u1_colour_primaries;
    487     int32_t transfer = s_ctl_get_seq_info_op.u1_transfer_characteristics;
    488     int32_t coeffs = s_ctl_get_seq_info_op.u1_matrix_coefficients;
    489     bool fullRange = false;  // mpeg2 video has limited range.
    490 
    491     ColorAspects colorAspects;
    492     ColorUtils::convertIsoColorAspectsToCodecAspects(
    493             primaries, transfer, coeffs, fullRange, colorAspects);
    494 
    495     // Update color aspects if necessary.
    496     if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
    497         mBitstreamColorAspects = colorAspects;
    498         status_t err = handleColorAspectsChange();
    499         CHECK(err == OK);
    500     }
    501     return true;
    502 }
    503 
    504 OMX_ERRORTYPE SoftMPEG2::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
    505     const uint32_t oldWidth = mWidth;
    506     const uint32_t oldHeight = mHeight;
    507     OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
    508     if (mWidth != oldWidth || mHeight != oldHeight) {
    509         reInitDecoder();
    510     }
    511     return ret;
    512 }
    513 
    514 bool SoftMPEG2::setDecodeArgs(
    515         ivd_video_decode_ip_t *ps_dec_ip,
    516         ivd_video_decode_op_t *ps_dec_op,
    517         OMX_BUFFERHEADERTYPE *inHeader,
    518         OMX_BUFFERHEADERTYPE *outHeader,
    519         size_t timeStampIx) {
    520     size_t sizeY = outputBufferWidth() * outputBufferHeight();
    521     size_t sizeUV;
    522 
    523     ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
    524     ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
    525 
    526     ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
    527 
    528     /* When in flush and after EOS with zero byte input,
    529      * inHeader is set to zero. Hence check for non-null */
    530     if (inHeader) {
    531         ps_dec_ip->u4_ts = timeStampIx;
    532         ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
    533                 + inHeader->nOffset;
    534         ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
    535     } else {
    536         ps_dec_ip->u4_ts = 0;
    537         ps_dec_ip->pv_stream_buffer = NULL;
    538         ps_dec_ip->u4_num_Bytes = 0;
    539     }
    540 
    541     sizeUV = sizeY / 4;
    542     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
    543     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
    544     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
    545 
    546     uint8_t *pBuf;
    547     if (outHeader) {
    548         if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
    549             android_errorWriteLog(0x534e4554, "27833616");
    550             return false;
    551         }
    552         pBuf = outHeader->pBuffer;
    553     } else {
    554         // mFlushOutBuffer always has the right size.
    555         pBuf = mFlushOutBuffer;
    556     }
    557 
    558     ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
    559     ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
    560     ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
    561     ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
    562     return true;
    563 }
    564 void SoftMPEG2::onPortFlushCompleted(OMX_U32 portIndex) {
    565     /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
    566     if (kOutputPortIndex == portIndex) {
    567         setFlushMode();
    568 
    569         while (true) {
    570             ivd_video_decode_ip_t s_dec_ip;
    571             ivd_video_decode_op_t s_dec_op;
    572             IV_API_CALL_STATUS_T status;
    573             size_t sizeY, sizeUV;
    574 
    575             setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
    576 
    577             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    578             if (0 == s_dec_op.u4_output_present) {
    579                 resetPlugin();
    580                 break;
    581             }
    582         }
    583     }
    584 }
    585 
    586 void SoftMPEG2::onQueueFilled(OMX_U32 portIndex) {
    587     UNUSED(portIndex);
    588 
    589     if (mOutputPortSettingsChange != NONE) {
    590         return;
    591     }
    592 
    593     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
    594     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
    595 
    596     if (outputBufferWidth() != mStride) {
    597         /* Set the run-time (dynamic) parameters */
    598         mStride = outputBufferWidth();
    599         setParams(mStride);
    600     }
    601 
    602     while (!outQueue.empty()) {
    603         BufferInfo *inInfo;
    604         OMX_BUFFERHEADERTYPE *inHeader;
    605 
    606         BufferInfo *outInfo;
    607         OMX_BUFFERHEADERTYPE *outHeader;
    608         size_t timeStampIx;
    609 
    610         inInfo = NULL;
    611         inHeader = NULL;
    612 
    613         if (!mIsInFlush) {
    614             if (!inQueue.empty()) {
    615                 inInfo = *inQueue.begin();
    616                 inHeader = inInfo->mHeader;
    617             } else {
    618                 break;
    619             }
    620         }
    621 
    622         outInfo = *outQueue.begin();
    623         outHeader = outInfo->mHeader;
    624         outHeader->nFlags = 0;
    625         outHeader->nTimeStamp = 0;
    626         outHeader->nOffset = 0;
    627 
    628         if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
    629             mReceivedEOS = true;
    630             if (inHeader->nFilledLen == 0) {
    631                 inQueue.erase(inQueue.begin());
    632                 inInfo->mOwnedByUs = false;
    633                 notifyEmptyBufferDone(inHeader);
    634                 inHeader = NULL;
    635                 setFlushMode();
    636             }
    637         }
    638 
    639         // When there is an init required and the decoder is not in flush mode,
    640         // update output port's definition and reinitialize decoder.
    641         if (mInitNeeded && !mIsInFlush) {
    642             bool portWillReset = false;
    643             handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
    644 
    645             CHECK_EQ(reInitDecoder(), (status_t)OK);
    646             return;
    647         }
    648 
    649         /* Get a free slot in timestamp array to hold input timestamp */
    650         {
    651             size_t i;
    652             timeStampIx = 0;
    653             for (i = 0; i < MAX_TIME_STAMPS; i++) {
    654                 if (!mTimeStampsValid[i]) {
    655                     timeStampIx = i;
    656                     break;
    657                 }
    658             }
    659             if (inHeader != NULL) {
    660                 mTimeStampsValid[timeStampIx] = true;
    661                 mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
    662             }
    663         }
    664 
    665         {
    666             ivd_video_decode_ip_t s_dec_ip;
    667             ivd_video_decode_op_t s_dec_op;
    668             WORD32 timeDelay, timeTaken;
    669             size_t sizeY, sizeUV;
    670 
    671             if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
    672                 ALOGE("Decoder arg setup failed");
    673                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    674                 return;
    675             }
    676             // If input dump is enabled, then write to file
    677             DUMP_TO_FILE(mInFile, s_dec_ip.pv_stream_buffer, s_dec_ip.u4_num_Bytes);
    678 
    679             if (s_dec_ip.u4_num_Bytes > 0) {
    680                 char *ptr = (char *)s_dec_ip.pv_stream_buffer;
    681             }
    682 
    683             GETTIME(&mTimeStart, NULL);
    684             /* Compute time elapsed between end of previous decode()
    685              * to start of current decode() */
    686             TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
    687 
    688             IV_API_CALL_STATUS_T status;
    689             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    690 
    691             bool unsupportedDimensions = (IMPEG2D_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code);
    692             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
    693 
    694             getSeqInfo();
    695 
    696             GETTIME(&mTimeEnd, NULL);
    697             /* Compute time taken for decode() */
    698             TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
    699 
    700             ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
    701                    s_dec_op.u4_num_bytes_consumed);
    702             if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
    703                 mFlushNeeded = true;
    704             }
    705 
    706             if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
    707                 /* If the input did not contain picture data, then ignore
    708                  * the associated timestamp */
    709                 mTimeStampsValid[timeStampIx] = false;
    710             }
    711 
    712             // This is needed to handle CTS DecoderTest testCodecResetsMPEG2WithoutSurface,
    713             // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
    714             if (unsupportedDimensions && !mFlushNeeded) {
    715                 bool portWillReset = false;
    716                 handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
    717 
    718                 CHECK_EQ(reInitDecoder(), (status_t)OK);
    719 
    720                 if (setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
    721                     ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    722                 }
    723                 return;
    724             }
    725 
    726             // If the decoder is in the changing resolution mode and there is no output present,
    727             // that means the switching is done and it's ready to reset the decoder and the plugin.
    728             if (mChangingResolution && !s_dec_op.u4_output_present) {
    729                 mChangingResolution = false;
    730                 resetDecoder();
    731                 resetPlugin();
    732                 mStride = outputBufferWidth();
    733                 setParams(mStride);
    734                 continue;
    735             }
    736 
    737             if (unsupportedDimensions || resChanged) {
    738                 mChangingResolution = true;
    739                 if (mFlushNeeded) {
    740                     setFlushMode();
    741                 }
    742 
    743                 if (unsupportedDimensions) {
    744                     mNewWidth = s_dec_op.u4_pic_wd;
    745                     mNewHeight = s_dec_op.u4_pic_ht;
    746                     mInitNeeded = true;
    747                 }
    748                 continue;
    749             }
    750 
    751             // Combine the resolution change and coloraspects change in one PortSettingChange event
    752             // if necessary.
    753             if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
    754                 uint32_t width = s_dec_op.u4_pic_wd;
    755                 uint32_t height = s_dec_op.u4_pic_ht;
    756                 bool portWillReset = false;
    757                 handlePortSettingsChange(&portWillReset, width, height);
    758 
    759                 if (portWillReset) {
    760                     resetDecoder();
    761                     return;
    762                 }
    763             } else if (mUpdateColorAspects) {
    764                 notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
    765                     kDescribeColorAspectsIndex, NULL);
    766                 mUpdateColorAspects = false;
    767                 return;
    768             }
    769 
    770             if (s_dec_op.u4_output_present) {
    771                 size_t timeStampIdx;
    772                 outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
    773 
    774                 timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
    775                 outHeader->nTimeStamp = mTimeStamps[timeStampIdx];
    776                 mTimeStampsValid[timeStampIdx] = false;
    777 
    778                 /* mWaitForI waits for the first I picture. Once made FALSE, it
    779                    has to remain false till explicitly set to TRUE. */
    780                 mWaitForI = mWaitForI && !(IV_I_FRAME == s_dec_op.e_pic_type);
    781 
    782                 if (mWaitForI) {
    783                     s_dec_op.u4_output_present = false;
    784                 } else {
    785                     ALOGV("Output timestamp: %lld, res: %ux%u",
    786                             (long long)outHeader->nTimeStamp, mWidth, mHeight);
    787                     DUMP_TO_FILE(mOutFile, outHeader->pBuffer, outHeader->nFilledLen);
    788                     outInfo->mOwnedByUs = false;
    789                     outQueue.erase(outQueue.begin());
    790                     outInfo = NULL;
    791                     notifyFillBufferDone(outHeader);
    792                     outHeader = NULL;
    793                 }
    794             } else if (mIsInFlush) {
    795                 /* If in flush mode and no output is returned by the codec,
    796                  * then come out of flush mode */
    797                 mIsInFlush = false;
    798 
    799                 /* If EOS was recieved on input port and there is no output
    800                  * from the codec, then signal EOS on output port */
    801                 if (mReceivedEOS) {
    802                     outHeader->nFilledLen = 0;
    803                     outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
    804 
    805                     outInfo->mOwnedByUs = false;
    806                     outQueue.erase(outQueue.begin());
    807                     outInfo = NULL;
    808                     notifyFillBufferDone(outHeader);
    809                     outHeader = NULL;
    810                     resetPlugin();
    811                 }
    812             }
    813         }
    814 
    815         /* If input EOS is seen and decoder is not in flush mode,
    816          * set the decoder in flush mode.
    817          * There can be a case where EOS is sent along with last picture data
    818          * In that case, only after decoding that input data, decoder has to be
    819          * put in flush. This case is handled here  */
    820 
    821         if (mReceivedEOS && !mIsInFlush) {
    822             setFlushMode();
    823         }
    824 
    825         // TODO: Handle more than one picture data
    826         if (inHeader != NULL) {
    827             inInfo->mOwnedByUs = false;
    828             inQueue.erase(inQueue.begin());
    829             inInfo = NULL;
    830             notifyEmptyBufferDone(inHeader);
    831             inHeader = NULL;
    832         }
    833     }
    834 }
    835 
    836 int SoftMPEG2::getColorAspectPreference() {
    837     return kPreferBitstream;
    838 }
    839 
    840 }  // namespace android
    841 
    842 android::SoftOMXComponent *createSoftOMXComponent(
    843         const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
    844         OMX_COMPONENTTYPE **component) {
    845     return new android::SoftMPEG2(name, callbacks, appData, component);
    846 }
    847