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 status_t SoftHEVC::resetDecoder() {
    186     ivd_ctl_reset_ip_t s_ctl_ip;
    187     ivd_ctl_reset_op_t s_ctl_op;
    188     IV_API_CALL_STATUS_T status;
    189 
    190     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    191     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
    192     s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
    193     s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
    194 
    195     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
    196             (void *)&s_ctl_op);
    197     if (IV_SUCCESS != status) {
    198         ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
    199         return UNKNOWN_ERROR;
    200     }
    201     mSignalledError = false;
    202 
    203     /* Set number of cores/threads to be used by the codec */
    204     setNumCores();
    205 
    206     mStride = 0;
    207     return OK;
    208 }
    209 
    210 status_t SoftHEVC::setNumCores() {
    211     ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
    212     ivdext_ctl_set_num_cores_op_t s_set_cores_op;
    213     IV_API_CALL_STATUS_T status;
    214     s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    215     s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
    216     s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
    217     s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
    218     s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
    219     ALOGV("Set number of cores to %u", s_set_cores_ip.u4_num_cores);
    220     status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip,
    221             (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 SoftHEVC::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     ALOGV("Set the decoder in flush mode ");
    240 
    241     /* Set the decoder in Flush mode, subsequent decode() calls will flush */
    242     status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip,
    243             (void *)&s_video_flush_op);
    244 
    245     if (status != IV_SUCCESS) {
    246         ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
    247                 s_video_flush_op.u4_error_code);
    248         return UNKNOWN_ERROR;
    249     }
    250 
    251     mIsInFlush = true;
    252     return OK;
    253 }
    254 
    255 status_t SoftHEVC::initDecoder() {
    256     IV_API_CALL_STATUS_T status;
    257 
    258     mNumCores = GetCPUCoreCount();
    259     mCodecCtx = NULL;
    260 
    261     mStride = outputBufferWidth();
    262 
    263     /* Initialize the decoder */
    264     {
    265         ivdext_create_ip_t s_create_ip;
    266         ivdext_create_op_t s_create_op;
    267 
    268         void *dec_fxns = (void *)ivdec_api_function;
    269 
    270         s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
    271         s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
    272         s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
    273         s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
    274         s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
    275         s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
    276         s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
    277         s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
    278 
    279         status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
    280 
    281         mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
    282         mCodecCtx->pv_fxns = dec_fxns;
    283         mCodecCtx->u4_size = sizeof(iv_obj_t);
    284 
    285         if (status != IV_SUCCESS) {
    286             ALOGE("Error in create: 0x%x",
    287                     s_create_op.s_ivd_create_op_t.u4_error_code);
    288             deInitDecoder();
    289             mCodecCtx = NULL;
    290             return UNKNOWN_ERROR;
    291         }
    292     }
    293 
    294     /* Reset the plugin state */
    295     resetPlugin();
    296 
    297     /* Set the run time (dynamic) parameters */
    298     setParams(mStride);
    299 
    300     /* Set number of cores/threads to be used by the codec */
    301     setNumCores();
    302 
    303     /* Get codec version */
    304     logVersion();
    305 
    306     mFlushNeeded = false;
    307     return OK;
    308 }
    309 
    310 status_t SoftHEVC::deInitDecoder() {
    311     size_t i;
    312     IV_API_CALL_STATUS_T status;
    313 
    314     if (mCodecCtx) {
    315         ivdext_delete_ip_t s_delete_ip;
    316         ivdext_delete_op_t s_delete_op;
    317 
    318         s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
    319         s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
    320 
    321         s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
    322 
    323         status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op);
    324         if (status != IV_SUCCESS) {
    325             ALOGE("Error in delete: 0x%x",
    326                     s_delete_op.s_ivd_delete_op_t.u4_error_code);
    327             return UNKNOWN_ERROR;
    328         }
    329     }
    330 
    331 
    332     mChangingResolution = false;
    333 
    334     return OK;
    335 }
    336 
    337 void SoftHEVC::onReset() {
    338     ALOGV("onReset called");
    339     SoftVideoDecoderOMXComponent::onReset();
    340 
    341     mSignalledError = false;
    342     resetDecoder();
    343     resetPlugin();
    344 }
    345 
    346 bool SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip,
    347         ivd_video_decode_op_t *ps_dec_op,
    348         OMX_BUFFERHEADERTYPE *inHeader,
    349         OMX_BUFFERHEADERTYPE *outHeader,
    350         size_t timeStampIx) {
    351     size_t sizeY = outputBufferWidth() * outputBufferHeight();
    352     size_t sizeUV;
    353 
    354     ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
    355     ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
    356 
    357     ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
    358 
    359     /* When in flush and after EOS with zero byte input,
    360      * inHeader is set to zero. Hence check for non-null */
    361     if (inHeader) {
    362         ps_dec_ip->u4_ts = timeStampIx;
    363         ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
    364                 + inHeader->nOffset;
    365         ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
    366     } else {
    367         ps_dec_ip->u4_ts = 0;
    368         ps_dec_ip->pv_stream_buffer = NULL;
    369         ps_dec_ip->u4_num_Bytes = 0;
    370     }
    371 
    372     sizeUV = sizeY / 4;
    373     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
    374     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
    375     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
    376 
    377     uint8_t *pBuf;
    378     if (outHeader) {
    379         if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
    380             android_errorWriteLog(0x534e4554, "27833616");
    381             return false;
    382         }
    383         pBuf = outHeader->pBuffer;
    384     } else {
    385         // mFlushOutBuffer always has the right size.
    386         pBuf = mFlushOutBuffer;
    387     }
    388 
    389     ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
    390     ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
    391     ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
    392     ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
    393     return true;
    394 }
    395 void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) {
    396     /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
    397     if (kOutputPortIndex == portIndex) {
    398         setFlushMode();
    399 
    400         /* Allocate a picture buffer to flushed data */
    401         uint32_t displayStride = outputBufferWidth();
    402         uint32_t displayHeight = outputBufferHeight();
    403 
    404         uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
    405         mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize);
    406         if (NULL == mFlushOutBuffer) {
    407             ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
    408             return;
    409         }
    410 
    411         while (true) {
    412             ivd_video_decode_ip_t s_dec_ip;
    413             ivd_video_decode_op_t s_dec_op;
    414             IV_API_CALL_STATUS_T status;
    415             size_t sizeY, sizeUV;
    416 
    417             setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
    418 
    419             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
    420                     (void *)&s_dec_op);
    421             if (0 == s_dec_op.u4_output_present) {
    422                 resetPlugin();
    423                 break;
    424             }
    425         }
    426 
    427         if (mFlushOutBuffer) {
    428             free(mFlushOutBuffer);
    429             mFlushOutBuffer = NULL;
    430         }
    431 
    432     }
    433 }
    434 
    435 void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
    436     UNUSED(portIndex);
    437 
    438     if (mSignalledError) {
    439         return;
    440     }
    441     if (mOutputPortSettingsChange != NONE) {
    442         return;
    443     }
    444 
    445     if (NULL == mCodecCtx) {
    446         if (OK != initDecoder()) {
    447             ALOGE("Failed to initialize decoder");
    448             notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    449             mSignalledError = true;
    450             return;
    451         }
    452     }
    453     if (outputBufferWidth() != mStride) {
    454         /* Set the run-time (dynamic) parameters */
    455         mStride = outputBufferWidth();
    456         setParams(mStride);
    457     }
    458 
    459     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
    460     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
    461 
    462     while (!outQueue.empty()) {
    463         BufferInfo *inInfo;
    464         OMX_BUFFERHEADERTYPE *inHeader;
    465 
    466         BufferInfo *outInfo;
    467         OMX_BUFFERHEADERTYPE *outHeader;
    468         size_t timeStampIx;
    469 
    470         inInfo = NULL;
    471         inHeader = NULL;
    472 
    473         if (!mIsInFlush) {
    474             if (!inQueue.empty()) {
    475                 inInfo = *inQueue.begin();
    476                 inHeader = inInfo->mHeader;
    477             } else {
    478                 break;
    479             }
    480         }
    481 
    482         outInfo = *outQueue.begin();
    483         outHeader = outInfo->mHeader;
    484         outHeader->nFlags = 0;
    485         outHeader->nTimeStamp = 0;
    486         outHeader->nOffset = 0;
    487 
    488         if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
    489             mReceivedEOS = true;
    490             if (inHeader->nFilledLen == 0) {
    491                 inQueue.erase(inQueue.begin());
    492                 inInfo->mOwnedByUs = false;
    493                 notifyEmptyBufferDone(inHeader);
    494                 inHeader = NULL;
    495                 setFlushMode();
    496             }
    497         }
    498 
    499         /* Get a free slot in timestamp array to hold input timestamp */
    500         {
    501             size_t i;
    502             timeStampIx = 0;
    503             for (i = 0; i < MAX_TIME_STAMPS; i++) {
    504                 if (!mTimeStampsValid[i]) {
    505                     timeStampIx = i;
    506                     break;
    507                 }
    508             }
    509             if (inHeader != NULL) {
    510                 mTimeStampsValid[timeStampIx] = true;
    511                 mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
    512             }
    513         }
    514 
    515         {
    516             ivd_video_decode_ip_t s_dec_ip;
    517             ivd_video_decode_op_t s_dec_op;
    518             WORD32 timeDelay, timeTaken;
    519             size_t sizeY, sizeUV;
    520 
    521             if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
    522                 ALOGE("Decoder arg setup failed");
    523                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    524                 mSignalledError = true;
    525                 return;
    526             }
    527 
    528             GETTIME(&mTimeStart, NULL);
    529             /* Compute time elapsed between end of previous decode()
    530              * to start of current decode() */
    531             TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
    532 
    533             IV_API_CALL_STATUS_T status;
    534             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    535 
    536             bool unsupportedResolution =
    537                 (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_dec_op.u4_error_code & 0xFF));
    538 
    539             /* Check for unsupported dimensions */
    540             if (unsupportedResolution) {
    541                 ALOGE("Unsupported resolution : %dx%d", mWidth, mHeight);
    542                 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    543                 mSignalledError = true;
    544                 return;
    545             }
    546 
    547             bool allocationFailed = (IVD_MEM_ALLOC_FAILED == (s_dec_op.u4_error_code & 0xFF));
    548             if (allocationFailed) {
    549                 ALOGE("Allocation failure in decoder");
    550                 notify(OMX_EventError, OMX_ErrorUnsupportedSetting, 0, NULL);
    551                 mSignalledError = true;
    552                 return;
    553             }
    554 
    555             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
    556 
    557             GETTIME(&mTimeEnd, NULL);
    558             /* Compute time taken for decode() */
    559             TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
    560 
    561             ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
    562                    s_dec_op.u4_num_bytes_consumed);
    563             if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
    564                 mFlushNeeded = true;
    565             }
    566 
    567             if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
    568                 /* If the input did not contain picture data, then ignore
    569                  * the associated timestamp */
    570                 mTimeStampsValid[timeStampIx] = false;
    571             }
    572 
    573             // If the decoder is in the changing resolution mode and there is no output present,
    574             // that means the switching is done and it's ready to reset the decoder and the plugin.
    575             if (mChangingResolution && !s_dec_op.u4_output_present) {
    576                 mChangingResolution = false;
    577                 resetDecoder();
    578                 resetPlugin();
    579                 mStride = outputBufferWidth();
    580                 setParams(mStride);
    581                 continue;
    582             }
    583 
    584             if (resChanged) {
    585                 mChangingResolution = true;
    586                 if (mFlushNeeded) {
    587                     setFlushMode();
    588                 }
    589                 continue;
    590             }
    591 
    592             if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
    593                 uint32_t width = s_dec_op.u4_pic_wd;
    594                 uint32_t height = s_dec_op.u4_pic_ht;
    595                 bool portWillReset = false;
    596                 handlePortSettingsChange(&portWillReset, width, height);
    597 
    598                 if (portWillReset) {
    599                     resetDecoder();
    600                     return;
    601                 }
    602             }
    603 
    604             if (s_dec_op.u4_output_present) {
    605                 outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
    606 
    607                 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
    608                 mTimeStampsValid[s_dec_op.u4_ts] = false;
    609 
    610                 outInfo->mOwnedByUs = false;
    611                 outQueue.erase(outQueue.begin());
    612                 outInfo = NULL;
    613                 notifyFillBufferDone(outHeader);
    614                 outHeader = NULL;
    615             } else if (mIsInFlush) {
    616                 /* If in flush mode and no output is returned by the codec,
    617                  * then come out of flush mode */
    618                 mIsInFlush = false;
    619 
    620                 /* If EOS was recieved on input port and there is no output
    621                  * from the codec, then signal EOS on output port */
    622                 if (mReceivedEOS) {
    623                     outHeader->nFilledLen = 0;
    624                     outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
    625 
    626                     outInfo->mOwnedByUs = false;
    627                     outQueue.erase(outQueue.begin());
    628                     outInfo = NULL;
    629                     notifyFillBufferDone(outHeader);
    630                     outHeader = NULL;
    631                     resetPlugin();
    632                 }
    633             }
    634         }
    635 
    636         /* If input EOS is seen and decoder is not in flush mode,
    637          * set the decoder in flush mode.
    638          * There can be a case where EOS is sent along with last picture data
    639          * In that case, only after decoding that input data, decoder has to be
    640          * put in flush. This case is handled here  */
    641 
    642         if (mReceivedEOS && !mIsInFlush) {
    643             setFlushMode();
    644         }
    645 
    646         // TODO: Handle more than one picture data
    647         if (inHeader != NULL) {
    648             inInfo->mOwnedByUs = false;
    649             inQueue.erase(inQueue.begin());
    650             inInfo = NULL;
    651             notifyEmptyBufferDone(inHeader);
    652             inHeader = NULL;
    653         }
    654     }
    655 }
    656 
    657 }  // namespace android
    658 
    659 android::SoftOMXComponent *createSoftOMXComponent(const char *name,
    660         const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
    661         OMX_COMPONENTTYPE **component) {
    662     android::SoftHEVC *codec = new android::SoftHEVC(name, callbacks, appData, component);
    663     if (codec->init() != android::OK) {
    664         android::sp<android::SoftOMXComponent> release = codec;
    665         return NULL;
    666     }
    667     return codec;
    668 }
    669