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