Home | History | Annotate | Download | only in hevcdec
      1 /*
      2  * Copyright (C) 2014 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 "SoftHEVC"
     19 #include <utils/Log.h>
     20 
     21 #include "ihevc_typedefs.h"
     22 #include "iv.h"
     23 #include "ivd.h"
     24 #include "ihevcd_cxa.h"
     25 #include "SoftHEVC.h"
     26 
     27 #include <media/stagefright/foundation/ADebug.h>
     28 #include <media/stagefright/foundation/AUtils.h>
     29 #include <media/stagefright/MediaDefs.h>
     30 #include <OMX_VideoExt.h>
     31 
     32 namespace android {
     33 
     34 #define componentName                   "video_decoder.hevc"
     35 #define codingType                      OMX_VIDEO_CodingHEVC
     36 #define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_HEVC
     37 
     38 /** Function and structure definitions to keep code similar for each codec */
     39 #define ivdec_api_function              ihevcd_cxa_api_function
     40 #define ivdext_create_ip_t              ihevcd_cxa_create_ip_t
     41 #define ivdext_create_op_t              ihevcd_cxa_create_op_t
     42 #define ivdext_delete_ip_t              ihevcd_cxa_delete_ip_t
     43 #define ivdext_delete_op_t              ihevcd_cxa_delete_op_t
     44 #define ivdext_ctl_set_num_cores_ip_t   ihevcd_cxa_ctl_set_num_cores_ip_t
     45 #define ivdext_ctl_set_num_cores_op_t   ihevcd_cxa_ctl_set_num_cores_op_t
     46 
     47 #define IVDEXT_CMD_CTL_SET_NUM_CORES    \
     48         (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
     49 
     50 static const CodecProfileLevel kProfileLevels[] = {
     51     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel1  },
     52     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel2  },
     53     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel21 },
     54     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel3  },
     55     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel31 },
     56     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel4  },
     57     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel41 },
     58     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel5  },
     59     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 },
     60 };
     61 
     62 SoftHEVC::SoftHEVC(
     63         const char *name,
     64         const OMX_CALLBACKTYPE *callbacks,
     65         OMX_PTR appData,
     66         OMX_COMPONENTTYPE **component)
     67     : SoftVideoDecoderOMXComponent(name, componentName, codingType,
     68             kProfileLevels, ARRAY_SIZE(kProfileLevels),
     69             320 /* width */, 240 /* height */, callbacks,
     70             appData, component),
     71       mCodecCtx(NULL),
     72       mFlushOutBuffer(NULL),
     73       mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
     74       mIvColorFormat(IV_YUV_420P),
     75       mChangingResolution(false),
     76       mSignalledError(false),
     77       mStride(mWidth) {
     78     const size_t kMinCompressionRatio = 4 /* compressionRatio (for Level 4+) */;
     79     const size_t kMaxOutputBufferSize = 2048 * 2048 * 3 / 2;
     80     // INPUT_BUF_SIZE is given by HEVC codec as minimum input size
     81     initPorts(
     82             kNumBuffers, max(kMaxOutputBufferSize / kMinCompressionRatio, (size_t)INPUT_BUF_SIZE),
     83             kNumBuffers, CODEC_MIME_TYPE, kMinCompressionRatio);
     84 }
     85 
     86 status_t SoftHEVC::init() {
     87     return initDecoder();
     88 }
     89 
     90 SoftHEVC::~SoftHEVC() {
     91     ALOGV("In SoftHEVC::~SoftHEVC");
     92     CHECK_EQ(deInitDecoder(), (status_t)OK);
     93 }
     94 
     95 static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
     96     UNUSED(ctxt);
     97     return memalign(alignment, size);
     98 }
     99 
    100 static void ivd_aligned_free(void *ctxt, void *buf) {
    101     UNUSED(ctxt);
    102     free(buf);
    103     return;
    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 SoftHEVC::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,
    133             (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 SoftHEVC::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,
    161             (void *)&s_ctl_op);
    162 
    163     if (status != IV_SUCCESS) {
    164         ALOGE("Error in setting the run-time parameters: 0x%x",
    165                 s_ctl_op.u4_error_code);
    166 
    167         return UNKNOWN_ERROR;
    168     }
    169     return OK;
    170 }
    171 
    172 status_t SoftHEVC::resetPlugin() {
    173     mIsInFlush = false;
    174     mReceivedEOS = false;
    175     memset(mTimeStamps, 0, sizeof(mTimeStamps));
    176     memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
    177 
    178     /* Initialize both start and end times */
    179     gettimeofday(&mTimeStart, NULL);
    180     gettimeofday(&mTimeEnd, NULL);
    181 
    182     return OK;
    183 }
    184 
    185 bool SoftHEVC::getVUIParams() {
    186     IV_API_CALL_STATUS_T status;
    187     ihevcd_cxa_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;
    188     ihevcd_cxa_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;
    189 
    190     s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    191     s_ctl_get_vui_params_ip.e_sub_cmd =
    192         (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_GET_VUI_PARAMS;
    193 
    194     s_ctl_get_vui_params_ip.u4_size =
    195         sizeof(ihevcd_cxa_ctl_get_vui_params_ip_t);
    196 
    197     s_ctl_get_vui_params_op.u4_size = sizeof(ihevcd_cxa_ctl_get_vui_params_op_t);
    198 
    199     status = ivdec_api_function(
    200             (iv_obj_t *)mCodecCtx, (void *)&s_ctl_get_vui_params_ip,
    201             (void *)&s_ctl_get_vui_params_op);
    202 
    203     if (status != IV_SUCCESS) {
    204         ALOGW("Error in getting VUI params: 0x%x",
    205                 s_ctl_get_vui_params_op.u4_error_code);
    206         return false;
    207     }
    208 
    209     int32_t primaries = s_ctl_get_vui_params_op.u1_colour_primaries;
    210     int32_t transfer = s_ctl_get_vui_params_op.u1_transfer_characteristics;
    211     int32_t coeffs = s_ctl_get_vui_params_op.u1_matrix_coefficients;
    212     bool fullRange = s_ctl_get_vui_params_op.u1_video_full_range_flag;
    213 
    214     ColorAspects colorAspects;
    215     ColorUtils::convertIsoColorAspectsToCodecAspects(
    216             primaries, transfer, coeffs, fullRange, colorAspects);
    217 
    218     // Update color aspects if necessary.
    219     if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
    220         mBitstreamColorAspects = colorAspects;
    221         status_t err = handleColorAspectsChange();
    222         CHECK(err == OK);
    223     }
    224     return true;
    225 }
    226 
    227 status_t SoftHEVC::resetDecoder() {
    228     ivd_ctl_reset_ip_t s_ctl_ip;
    229     ivd_ctl_reset_op_t s_ctl_op;
    230     IV_API_CALL_STATUS_T status;
    231 
    232     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    233     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
    234     s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
    235     s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
    236 
    237     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
    238             (void *)&s_ctl_op);
    239     if (IV_SUCCESS != status) {
    240         ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
    241         return UNKNOWN_ERROR;
    242     }
    243     mSignalledError = false;
    244 
    245     /* Set number of cores/threads to be used by the codec */
    246     setNumCores();
    247 
    248     mStride = 0;
    249     return OK;
    250 }
    251 
    252 status_t SoftHEVC::setNumCores() {
    253     ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
    254     ivdext_ctl_set_num_cores_op_t s_set_cores_op;
    255     IV_API_CALL_STATUS_T status;
    256     s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    257     s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
    258     s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
    259     s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
    260     s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
    261     ALOGV("Set number of cores to %u", s_set_cores_ip.u4_num_cores);
    262     status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip,
    263             (void *)&s_set_cores_op);
    264     if (IV_SUCCESS != status) {
    265         ALOGE("Error in setting number of cores: 0x%x",
    266                 s_set_cores_op.u4_error_code);
    267         return UNKNOWN_ERROR;
    268     }
    269     return OK;
    270 }
    271 
    272 status_t SoftHEVC::setFlushMode() {
    273     IV_API_CALL_STATUS_T status;
    274     ivd_ctl_flush_ip_t s_video_flush_ip;
    275     ivd_ctl_flush_op_t s_video_flush_op;
    276 
    277     s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    278     s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
    279     s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
    280     s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
    281     ALOGV("Set the decoder in flush mode ");
    282 
    283     /* Set the decoder in Flush mode, subsequent decode() calls will flush */
    284     status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip,
    285             (void *)&s_video_flush_op);
    286 
    287     if (status != IV_SUCCESS) {
    288         ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
    289                 s_video_flush_op.u4_error_code);
    290         return UNKNOWN_ERROR;
    291     }
    292 
    293     mIsInFlush = true;
    294     return OK;
    295 }
    296 
    297 status_t SoftHEVC::initDecoder() {
    298     IV_API_CALL_STATUS_T status;
    299 
    300     mNumCores = GetCPUCoreCount();
    301     mCodecCtx = NULL;
    302 
    303     mStride = outputBufferWidth();
    304 
    305     /* Initialize the decoder */
    306     {
    307         ivdext_create_ip_t s_create_ip;
    308         ivdext_create_op_t s_create_op;
    309 
    310         void *dec_fxns = (void *)ivdec_api_function;
    311 
    312         s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
    313         s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
    314         s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
    315         s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
    316         s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
    317         s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
    318         s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
    319         s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
    320 
    321         status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
    322 
    323         mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
    324         mCodecCtx->pv_fxns = dec_fxns;
    325         mCodecCtx->u4_size = sizeof(iv_obj_t);
    326 
    327         if (status != IV_SUCCESS) {
    328             ALOGE("Error in create: 0x%x",
    329                     s_create_op.s_ivd_create_op_t.u4_error_code);
    330             deInitDecoder();
    331             mCodecCtx = NULL;
    332             return UNKNOWN_ERROR;
    333         }
    334     }
    335 
    336     /* Reset the plugin state */
    337     resetPlugin();
    338 
    339     /* Set the run time (dynamic) parameters */
    340     setParams(mStride);
    341 
    342     /* Set number of cores/threads to be used by the codec */
    343     setNumCores();
    344 
    345     /* Get codec version */
    346     logVersion();
    347 
    348     mFlushNeeded = false;
    349     return OK;
    350 }
    351 
    352 status_t SoftHEVC::deInitDecoder() {
    353     size_t i;
    354     IV_API_CALL_STATUS_T status;
    355 
    356     if (mCodecCtx) {
    357         ivdext_delete_ip_t s_delete_ip;
    358         ivdext_delete_op_t s_delete_op;
    359 
    360         s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
    361         s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
    362 
    363         s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
    364 
    365         status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op);
    366         if (status != IV_SUCCESS) {
    367             ALOGE("Error in delete: 0x%x",
    368                     s_delete_op.s_ivd_delete_op_t.u4_error_code);
    369             return UNKNOWN_ERROR;
    370         }
    371     }
    372 
    373 
    374     mChangingResolution = false;
    375 
    376     return OK;
    377 }
    378 
    379 void SoftHEVC::onReset() {
    380     ALOGV("onReset called");
    381     SoftVideoDecoderOMXComponent::onReset();
    382 
    383     mSignalledError = false;
    384     resetDecoder();
    385     resetPlugin();
    386 }
    387 
    388 bool SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip,
    389         ivd_video_decode_op_t *ps_dec_op,
    390         OMX_BUFFERHEADERTYPE *inHeader,
    391         OMX_BUFFERHEADERTYPE *outHeader,
    392         size_t timeStampIx) {
    393     size_t sizeY = outputBufferWidth() * outputBufferHeight();
    394     size_t sizeUV;
    395 
    396     ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
    397     ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
    398 
    399     ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
    400 
    401     /* When in flush and after EOS with zero byte input,
    402      * inHeader is set to zero. Hence check for non-null */
    403     if (inHeader) {
    404         ps_dec_ip->u4_ts = timeStampIx;
    405         ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
    406                 + inHeader->nOffset;
    407         ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
    408     } else {
    409         ps_dec_ip->u4_ts = 0;
    410         ps_dec_ip->pv_stream_buffer = NULL;
    411         ps_dec_ip->u4_num_Bytes = 0;
    412     }
    413 
    414     sizeUV = sizeY / 4;
    415     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
    416     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
    417     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
    418 
    419     uint8_t *pBuf;
    420     if (outHeader) {
    421         if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
    422             android_errorWriteLog(0x534e4554, "27833616");
    423             return false;
    424         }
    425         pBuf = outHeader->pBuffer;
    426     } else {
    427         // mFlushOutBuffer always has the right size.
    428         pBuf = mFlushOutBuffer;
    429     }
    430 
    431     ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
    432     ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
    433     ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
    434     ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
    435     return true;
    436 }
    437 void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) {
    438     /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
    439     if (kOutputPortIndex == portIndex) {
    440         setFlushMode();
    441 
    442         /* Allocate a picture buffer to flushed data */
    443         uint32_t displayStride = outputBufferWidth();
    444         uint32_t displayHeight = outputBufferHeight();
    445 
    446         uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
    447         mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize);
    448         if (NULL == mFlushOutBuffer) {
    449             ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
    450             return;
    451         }
    452 
    453         while (true) {
    454             ivd_video_decode_ip_t s_dec_ip;
    455             ivd_video_decode_op_t s_dec_op;
    456             IV_API_CALL_STATUS_T status;
    457             size_t sizeY, sizeUV;
    458 
    459             setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
    460 
    461             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
    462                     (void *)&s_dec_op);
    463             if (0 == s_dec_op.u4_output_present) {
    464                 resetPlugin();
    465                 break;
    466             }
    467         }
    468 
    469         if (mFlushOutBuffer) {
    470             free(mFlushOutBuffer);
    471             mFlushOutBuffer = NULL;
    472         }
    473 
    474     }
    475 }
    476 
    477 void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
    478     UNUSED(portIndex);
    479 
    480     if (mSignalledError) {
    481         return;
    482     }
    483     if (mOutputPortSettingsChange != NONE) {
    484         return;
    485     }
    486 
    487     if (NULL == mCodecCtx) {
    488         if (OK != initDecoder()) {
    489             ALOGE("Failed to initialize decoder");
    490             notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    491             mSignalledError = true;
    492             return;
    493         }
    494     }
    495     if (outputBufferWidth() != mStride) {
    496         /* Set the run-time (dynamic) parameters */
    497         mStride = outputBufferWidth();
    498         setParams(mStride);
    499     }
    500 
    501     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
    502     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
    503 
    504     while (!outQueue.empty()) {
    505         BufferInfo *inInfo;
    506         OMX_BUFFERHEADERTYPE *inHeader;
    507 
    508         BufferInfo *outInfo;
    509         OMX_BUFFERHEADERTYPE *outHeader;
    510         size_t timeStampIx;
    511 
    512         inInfo = NULL;
    513         inHeader = NULL;
    514 
    515         if (!mIsInFlush) {
    516             if (!inQueue.empty()) {
    517                 inInfo = *inQueue.begin();
    518                 inHeader = inInfo->mHeader;
    519             } else {
    520                 break;
    521             }
    522         }
    523 
    524         outInfo = *outQueue.begin();
    525         outHeader = outInfo->mHeader;
    526         outHeader->nFlags = 0;
    527         outHeader->nTimeStamp = 0;
    528         outHeader->nOffset = 0;
    529 
    530         if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
    531             mReceivedEOS = true;
    532             if (inHeader->nFilledLen == 0) {
    533                 inQueue.erase(inQueue.begin());
    534                 inInfo->mOwnedByUs = false;
    535                 notifyEmptyBufferDone(inHeader);
    536                 inHeader = NULL;
    537                 setFlushMode();
    538             }
    539         }
    540 
    541         /* Get a free slot in timestamp array to hold input timestamp */
    542         {
    543             size_t i;
    544             timeStampIx = 0;
    545             for (i = 0; i < MAX_TIME_STAMPS; i++) {
    546                 if (!mTimeStampsValid[i]) {
    547                     timeStampIx = i;
    548                     break;
    549                 }
    550             }
    551             if (inHeader != NULL) {
    552                 mTimeStampsValid[timeStampIx] = true;
    553                 mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
    554             }
    555         }
    556 
    557         {
    558             ivd_video_decode_ip_t s_dec_ip;
    559             ivd_video_decode_op_t s_dec_op;
    560             WORD32 timeDelay, timeTaken;
    561             size_t sizeY, sizeUV;
    562 
    563             if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
    564                 ALOGE("Decoder arg setup failed");
    565                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    566                 mSignalledError = true;
    567                 return;
    568             }
    569 
    570             GETTIME(&mTimeStart, NULL);
    571             /* Compute time elapsed between end of previous decode()
    572              * to start of current decode() */
    573             TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
    574 
    575             IV_API_CALL_STATUS_T status;
    576             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    577 
    578             bool unsupportedResolution =
    579                 (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF));
    580 
    581             /* Check for unsupported dimensions */
    582             if (unsupportedResolution) {
    583                 ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight);
    584                 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    585                 mSignalledError = true;
    586                 return;
    587             }
    588 
    589             bool allocationFailed = (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & 0xFF));
    590             if (allocationFailed) {
    591                 ALOGE("Allocation failure in decoder");
    592                 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    593                 mSignalledError = true;
    594                 return;
    595             }
    596 
    597             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
    598 
    599             getVUIParams();
    600 
    601             GETTIME(&mTimeEnd, NULL);
    602             /* Compute time taken for decode() */
    603             TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
    604 
    605             ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
    606                    s_dec_op.u4_num_bytes_consumed);
    607             if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
    608                 mFlushNeeded = true;
    609             }
    610 
    611             if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
    612                 /* If the input did not contain picture data, then ignore
    613                  * the associated timestamp */
    614                 mTimeStampsValid[timeStampIx] = false;
    615             }
    616 
    617             // If the decoder is in the changing resolution mode and there is no output present,
    618             // that means the switching is done and it's ready to reset the decoder and the plugin.
    619             if (mChangingResolution && !s_dec_op.u4_output_present) {
    620                 mChangingResolution = false;
    621                 resetDecoder();
    622                 resetPlugin();
    623                 mStride = outputBufferWidth();
    624                 setParams(mStride);
    625                 continue;
    626             }
    627 
    628             if (resChanged) {
    629                 mChangingResolution = true;
    630                 if (mFlushNeeded) {
    631                     setFlushMode();
    632                 }
    633                 continue;
    634             }
    635 
    636             // Combine the resolution change and coloraspects change in one PortSettingChange event
    637             // if necessary.
    638             if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
    639                 uint32_t width = s_dec_op.u4_pic_wd;
    640                 uint32_t height = s_dec_op.u4_pic_ht;
    641                 bool portWillReset = false;
    642                 handlePortSettingsChange(&portWillReset, width, height);
    643 
    644                 if (portWillReset) {
    645                     resetDecoder();
    646                     return;
    647                 }
    648             } else if (mUpdateColorAspects) {
    649                 notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
    650                     kDescribeColorAspectsIndex, NULL);
    651                 mUpdateColorAspects = false;
    652                 return;
    653             }
    654 
    655             if (s_dec_op.u4_output_present) {
    656                 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
    657 
    658                 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
    659                 mTimeStampsValid[s_dec_op.u4_ts] = false;
    660 
    661                 outInfo->mOwnedByUs = false;
    662                 outQueue.erase(outQueue.begin());
    663                 outInfo = NULL;
    664                 notifyFillBufferDone(outHeader);
    665                 outHeader = NULL;
    666             } else if (mIsInFlush) {
    667                 /* If in flush mode and no output is returned by the codec,
    668                  * then come out of flush mode */
    669                 mIsInFlush = false;
    670 
    671                 /* If EOS was recieved on input port and there is no output
    672                  * from the codec, then signal EOS on output port */
    673                 if (mReceivedEOS) {
    674                     outHeader->nFilledLen = 0;
    675                     outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
    676 
    677                     outInfo->mOwnedByUs = false;
    678                     outQueue.erase(outQueue.begin());
    679                     outInfo = NULL;
    680                     notifyFillBufferDone(outHeader);
    681                     outHeader = NULL;
    682                     resetPlugin();
    683                 }
    684             }
    685         }
    686 
    687         /* If input EOS is seen and decoder is not in flush mode,
    688          * set the decoder in flush mode.
    689          * There can be a case where EOS is sent along with last picture data
    690          * In that case, only after decoding that input data, decoder has to be
    691          * put in flush. This case is handled here  */
    692 
    693         if (mReceivedEOS && !mIsInFlush) {
    694             setFlushMode();
    695         }
    696 
    697         // TODO: Handle more than one picture data
    698         if (inHeader != NULL) {
    699             inInfo->mOwnedByUs = false;
    700             inQueue.erase(inQueue.begin());
    701             inInfo = NULL;
    702             notifyEmptyBufferDone(inHeader);
    703             inHeader = NULL;
    704         }
    705     }
    706 }
    707 
    708 int SoftHEVC::getColorAspectPreference() {
    709     return kPreferBitstream;
    710 }
    711 
    712 }  // namespace android
    713 
    714 android::SoftOMXComponent *createSoftOMXComponent(const char *name,
    715         const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
    716         OMX_COMPONENTTYPE **component) {
    717     android::SoftHEVC *codec = new android::SoftHEVC(name, callbacks, appData, component);
    718     if (codec->init() != android::OK) {
    719         android::sp<android::SoftOMXComponent> release = codec;
    720         return NULL;
    721     }
    722     return codec;
    723 }
    724