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_MPEG2LevelHL  },
     51 
     52     { OMX_VIDEO_MPEG2ProfileMain  , OMX_VIDEO_MPEG2LevelHL  },
     53 };
     54 
     55 SoftMPEG2::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 
     82 SoftMPEG2::~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 
     92 static ssize_t getMinTimestampIdx(OMX_S64 *pNTimeStamp, bool *pIsTimeStampValid) {
     93     OMX_S64 minTimeStamp = LLONG_MAX;
     94     ssize_t idx = -1;
     95     for (ssize_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 
    106 static 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 
    119 void 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 
    144 status_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 
    170 status_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 
    183 status_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 
    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     mCodecCtx = NULL;
    437 
    438     return OK;
    439 }
    440 
    441 status_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 
    456 void SoftMPEG2::onReset() {
    457     SoftVideoDecoderOMXComponent::onReset();
    458 
    459     mWaitForI = true;
    460 
    461     resetDecoder();
    462     resetPlugin();
    463 }
    464 
    465 bool 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 
    506 OMX_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 
    516 bool 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 }
    566 void 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 
    588 void 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                 ssize_t timeStampIdx;
    792                 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
    793 
    794                 timeStampIdx = getMinTimestampIdx(mTimeStamps, mTimeStampsValid);
    795                 if (timeStampIdx < 0) {
    796                     ALOGE("b/62872863, Invalid timestamp index!");
    797                     android_errorWriteLog(0x534e4554, "62872863");
    798                     return;
    799                 }
    800                 outHeader->nTimeStamp = mTimeStamps[timeStampIdx];
    801                 mTimeStampsValid[timeStampIdx] = false;
    802 
    803                 /* mWaitForI waits for the first I picture. Once made FALSE, it
    804                    has to remain false till explicitly set to TRUE. */
    805                 mWaitForI = mWaitForI && !(IV_I_FRAME == s_dec_op.e_pic_type);
    806 
    807                 if (mWaitForI) {
    808                     s_dec_op.u4_output_present = false;
    809                 } else {
    810                     ALOGV("Output timestamp: %lld, res: %ux%u",
    811                             (long long)outHeader->nTimeStamp, mWidth, mHeight);
    812                     DUMP_TO_FILE(mOutFile, outHeader->pBuffer, outHeader->nFilledLen);
    813                     outInfo->mOwnedByUs = false;
    814                     outQueue.erase(outQueue.begin());
    815                     outInfo = NULL;
    816                     notifyFillBufferDone(outHeader);
    817                     outHeader = NULL;
    818                 }
    819             } else if (mIsInFlush) {
    820                 /* If in flush mode and no output is returned by the codec,
    821                  * then come out of flush mode */
    822                 mIsInFlush = false;
    823 
    824                 /* If EOS was recieved on input port and there is no output
    825                  * from the codec, then signal EOS on output port */
    826                 if (mReceivedEOS) {
    827                     outHeader->nFilledLen = 0;
    828                     outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
    829 
    830                     outInfo->mOwnedByUs = false;
    831                     outQueue.erase(outQueue.begin());
    832                     outInfo = NULL;
    833                     notifyFillBufferDone(outHeader);
    834                     outHeader = NULL;
    835                     resetPlugin();
    836                 }
    837             }
    838         }
    839 
    840         /* If input EOS is seen and decoder is not in flush mode,
    841          * set the decoder in flush mode.
    842          * There can be a case where EOS is sent along with last picture data
    843          * In that case, only after decoding that input data, decoder has to be
    844          * put in flush. This case is handled here  */
    845 
    846         if (mReceivedEOS && !mIsInFlush) {
    847             setFlushMode();
    848         }
    849 
    850         // TODO: Handle more than one picture data
    851         if (inHeader != NULL) {
    852             inInfo->mOwnedByUs = false;
    853             inQueue.erase(inQueue.begin());
    854             inInfo = NULL;
    855             notifyEmptyBufferDone(inHeader);
    856             inHeader = NULL;
    857         }
    858     }
    859 }
    860 
    861 int SoftMPEG2::getColorAspectPreference() {
    862     return kPreferBitstream;
    863 }
    864 
    865 }  // namespace android
    866 
    867 android::SoftOMXComponent *createSoftOMXComponent(
    868         const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
    869         OMX_COMPONENTTYPE **component) {
    870     return new android::SoftMPEG2(name, callbacks, appData, component);
    871 }
    872