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 "ithread.h"
     25 #include "ihevcd_cxa.h"
     26 #include "SoftHEVC.h"
     27 
     28 #include <media/stagefright/foundation/ADebug.h>
     29 #include <media/stagefright/foundation/AUtils.h>
     30 #include <media/stagefright/MediaDefs.h>
     31 #include <OMX_VideoExt.h>
     32 
     33 namespace android {
     34 
     35 #define componentName                   "video_decoder.hevc"
     36 #define codingType                      OMX_VIDEO_CodingHEVC
     37 #define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_HEVC
     38 
     39 /** Function and structure definitions to keep code similar for each codec */
     40 #define ivdec_api_function              ihevcd_cxa_api_function
     41 #define ivdext_init_ip_t                ihevcd_cxa_init_ip_t
     42 #define ivdext_init_op_t                ihevcd_cxa_init_op_t
     43 #define ivdext_fill_mem_rec_ip_t        ihevcd_cxa_fill_mem_rec_ip_t
     44 #define ivdext_fill_mem_rec_op_t        ihevcd_cxa_fill_mem_rec_op_t
     45 #define ivdext_ctl_set_num_cores_ip_t   ihevcd_cxa_ctl_set_num_cores_ip_t
     46 #define ivdext_ctl_set_num_cores_op_t   ihevcd_cxa_ctl_set_num_cores_op_t
     47 
     48 #define IVDEXT_CMD_CTL_SET_NUM_CORES    \
     49         (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
     50 
     51 static const CodecProfileLevel kProfileLevels[] = {
     52     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel1  },
     53     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel2  },
     54     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel21 },
     55     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel3  },
     56     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel31 },
     57     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel4  },
     58     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel41 },
     59     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel5  },
     60     { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 },
     61 };
     62 
     63 SoftHEVC::SoftHEVC(
     64         const char *name,
     65         const OMX_CALLBACKTYPE *callbacks,
     66         OMX_PTR appData,
     67         OMX_COMPONENTTYPE **component)
     68     : SoftVideoDecoderOMXComponent(name, componentName, codingType,
     69             kProfileLevels, ARRAY_SIZE(kProfileLevels),
     70             320 /* width */, 240 /* height */, callbacks,
     71             appData, component),
     72       mMemRecords(NULL),
     73       mFlushOutBuffer(NULL),
     74       mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
     75       mIvColorFormat(IV_YUV_420P),
     76       mNewWidth(mWidth),
     77       mNewHeight(mHeight),
     78       mChangingResolution(false) {
     79     const size_t kMinCompressionRatio = 4 /* compressionRatio (for Level 4+) */;
     80     const size_t kMaxOutputBufferSize = 2048 * 2048 * 3 / 2;
     81     // INPUT_BUF_SIZE is given by HEVC codec as minimum input size
     82     initPorts(
     83             kNumBuffers, max(kMaxOutputBufferSize / kMinCompressionRatio, (size_t)INPUT_BUF_SIZE),
     84             kNumBuffers, CODEC_MIME_TYPE, kMinCompressionRatio);
     85     CHECK_EQ(initDecoder(), (status_t)OK);
     86 }
     87 
     88 SoftHEVC::~SoftHEVC() {
     89     ALOGD("In SoftHEVC::~SoftHEVC");
     90     CHECK_EQ(deInitDecoder(), (status_t)OK);
     91 }
     92 
     93 static size_t GetCPUCoreCount() {
     94     long cpuCoreCount = 1;
     95 #if defined(_SC_NPROCESSORS_ONLN)
     96     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
     97 #else
     98     // _SC_NPROC_ONLN must be defined...
     99     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
    100 #endif
    101     CHECK(cpuCoreCount >= 1);
    102     ALOGD("Number of CPU cores: %ld", cpuCoreCount);
    103     return (size_t)cpuCoreCount;
    104 }
    105 
    106 void SoftHEVC::logVersion() {
    107     ivd_ctl_getversioninfo_ip_t s_ctl_ip;
    108     ivd_ctl_getversioninfo_op_t s_ctl_op;
    109     UWORD8 au1_buf[512];
    110     IV_API_CALL_STATUS_T status;
    111 
    112     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    113     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
    114     s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
    115     s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
    116     s_ctl_ip.pv_version_buffer = au1_buf;
    117     s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);
    118 
    119     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
    120             (void *)&s_ctl_op);
    121 
    122     if (status != IV_SUCCESS) {
    123         ALOGE("Error in getting version number: 0x%x",
    124                 s_ctl_op.u4_error_code);
    125     } else {
    126         ALOGD("Ittiam decoder version number: %s",
    127                 (char *)s_ctl_ip.pv_version_buffer);
    128     }
    129     return;
    130 }
    131 
    132 status_t SoftHEVC::setParams(size_t stride) {
    133     ivd_ctl_set_config_ip_t s_ctl_ip;
    134     ivd_ctl_set_config_op_t s_ctl_op;
    135     IV_API_CALL_STATUS_T status;
    136     s_ctl_ip.u4_disp_wd = (UWORD32)stride;
    137     s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
    138 
    139     s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
    140     s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
    141     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    142     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
    143     s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
    144     s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
    145 
    146     ALOGV("Set the run-time (dynamic) parameters stride = %u", stride);
    147     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
    148             (void *)&s_ctl_op);
    149 
    150     if (status != IV_SUCCESS) {
    151         ALOGE("Error in setting the run-time parameters: 0x%x",
    152                 s_ctl_op.u4_error_code);
    153 
    154         return UNKNOWN_ERROR;
    155     }
    156     return OK;
    157 }
    158 
    159 status_t SoftHEVC::resetPlugin() {
    160     mIsInFlush = false;
    161     mReceivedEOS = false;
    162     memset(mTimeStamps, 0, sizeof(mTimeStamps));
    163     memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
    164 
    165     /* Initialize both start and end times */
    166     gettimeofday(&mTimeStart, NULL);
    167     gettimeofday(&mTimeEnd, NULL);
    168 
    169     return OK;
    170 }
    171 
    172 status_t SoftHEVC::resetDecoder() {
    173     ivd_ctl_reset_ip_t s_ctl_ip;
    174     ivd_ctl_reset_op_t s_ctl_op;
    175     IV_API_CALL_STATUS_T status;
    176 
    177     s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    178     s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
    179     s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
    180     s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
    181 
    182     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
    183             (void *)&s_ctl_op);
    184     if (IV_SUCCESS != status) {
    185         ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
    186         return UNKNOWN_ERROR;
    187     }
    188 
    189     /* Set the run-time (dynamic) parameters */
    190     setParams(outputBufferWidth());
    191 
    192     /* Set number of cores/threads to be used by the codec */
    193     setNumCores();
    194 
    195     return OK;
    196 }
    197 
    198 status_t SoftHEVC::setNumCores() {
    199     ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
    200     ivdext_ctl_set_num_cores_op_t s_set_cores_op;
    201     IV_API_CALL_STATUS_T status;
    202     s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    203     s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
    204     s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
    205     s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
    206     s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
    207     ALOGD("Set number of cores to %u", s_set_cores_ip.u4_num_cores);
    208     status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip,
    209             (void *)&s_set_cores_op);
    210     if (IV_SUCCESS != status) {
    211         ALOGE("Error in setting number of cores: 0x%x",
    212                 s_set_cores_op.u4_error_code);
    213         return UNKNOWN_ERROR;
    214     }
    215     return OK;
    216 }
    217 
    218 status_t SoftHEVC::setFlushMode() {
    219     IV_API_CALL_STATUS_T status;
    220     ivd_ctl_flush_ip_t s_video_flush_ip;
    221     ivd_ctl_flush_op_t s_video_flush_op;
    222 
    223     s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    224     s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
    225     s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
    226     s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
    227     ALOGD("Set the decoder in flush mode ");
    228 
    229     /* Set the decoder in Flush mode, subsequent decode() calls will flush */
    230     status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip,
    231             (void *)&s_video_flush_op);
    232 
    233     if (status != IV_SUCCESS) {
    234         ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
    235                 s_video_flush_op.u4_error_code);
    236         return UNKNOWN_ERROR;
    237     }
    238 
    239     mIsInFlush = true;
    240     return OK;
    241 }
    242 
    243 status_t SoftHEVC::initDecoder() {
    244     IV_API_CALL_STATUS_T status;
    245 
    246     UWORD32 u4_num_reorder_frames;
    247     UWORD32 u4_num_ref_frames;
    248     UWORD32 u4_share_disp_buf;
    249     WORD32 i4_level;
    250 
    251     mNumCores = GetCPUCoreCount();
    252 
    253     /* Initialize number of ref and reorder modes (for HEVC) */
    254     u4_num_reorder_frames = 16;
    255     u4_num_ref_frames = 16;
    256     u4_share_disp_buf = 0;
    257 
    258     uint32_t displayStride = outputBufferWidth();
    259     uint32_t displayHeight = outputBufferHeight();
    260     uint32_t displaySizeY = displayStride * displayHeight;
    261 
    262     if (displaySizeY > (1920 * 1088)) {
    263         i4_level = 50;
    264     } else if (displaySizeY > (1280 * 720)) {
    265         i4_level = 40;
    266     } else if (displaySizeY > (960 * 540)) {
    267         i4_level = 31;
    268     } else if (displaySizeY > (640 * 360)) {
    269         i4_level = 30;
    270     } else if (displaySizeY > (352 * 288)) {
    271         i4_level = 21;
    272     } else {
    273         i4_level = 20;
    274     }
    275     {
    276         iv_num_mem_rec_ip_t s_num_mem_rec_ip;
    277         iv_num_mem_rec_op_t s_num_mem_rec_op;
    278 
    279         s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
    280         s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
    281         s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
    282 
    283         ALOGV("Get number of mem records");
    284         status = ivdec_api_function(mCodecCtx, (void*)&s_num_mem_rec_ip,
    285                 (void*)&s_num_mem_rec_op);
    286         if (IV_SUCCESS != status) {
    287             ALOGE("Error in getting mem records: 0x%x",
    288                     s_num_mem_rec_op.u4_error_code);
    289             return UNKNOWN_ERROR;
    290         }
    291 
    292         mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
    293     }
    294 
    295     mMemRecords = (iv_mem_rec_t*)ivd_aligned_malloc(
    296             128, mNumMemRecords * sizeof(iv_mem_rec_t));
    297     if (mMemRecords == NULL) {
    298         ALOGE("Allocation failure");
    299         return NO_MEMORY;
    300     }
    301 
    302     memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
    303 
    304     {
    305         size_t i;
    306         ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
    307         ivdext_fill_mem_rec_op_t s_fill_mem_op;
    308         iv_mem_rec_t *ps_mem_rec;
    309 
    310         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
    311             sizeof(ivdext_fill_mem_rec_ip_t);
    312         s_fill_mem_ip.i4_level = i4_level;
    313         s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames;
    314         s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames;
    315         s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf;
    316         s_fill_mem_ip.u4_num_extra_disp_buf = 0;
    317         s_fill_mem_ip.e_output_format = mIvColorFormat;
    318 
    319         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
    320         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
    321         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride;
    322         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight;
    323         s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
    324             sizeof(ivdext_fill_mem_rec_op_t);
    325 
    326         ps_mem_rec = mMemRecords;
    327         for (i = 0; i < mNumMemRecords; i++)
    328             ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
    329 
    330         status = ivdec_api_function(mCodecCtx, (void *)&s_fill_mem_ip,
    331                 (void *)&s_fill_mem_op);
    332 
    333         if (IV_SUCCESS != status) {
    334             ALOGE("Error in filling mem records: 0x%x",
    335                     s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
    336             return UNKNOWN_ERROR;
    337         }
    338         mNumMemRecords =
    339             s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
    340 
    341         ps_mem_rec = mMemRecords;
    342 
    343         for (i = 0; i < mNumMemRecords; i++) {
    344             ps_mem_rec->pv_base = ivd_aligned_malloc(
    345                     ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
    346             if (ps_mem_rec->pv_base == NULL) {
    347                 ALOGE("Allocation failure for memory record #%zu of size %u",
    348                         i, ps_mem_rec->u4_mem_size);
    349                 status = IV_FAIL;
    350                 return NO_MEMORY;
    351             }
    352 
    353             ps_mem_rec++;
    354         }
    355     }
    356 
    357     /* Initialize the decoder */
    358     {
    359         ivdext_init_ip_t s_init_ip;
    360         ivdext_init_op_t s_init_op;
    361 
    362         void *dec_fxns = (void *)ivdec_api_function;
    363 
    364         s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
    365         s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
    366         s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
    367         s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride;
    368         s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight;
    369 
    370         s_init_ip.i4_level = i4_level;
    371         s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames;
    372         s_init_ip.u4_num_ref_frames = u4_num_ref_frames;
    373         s_init_ip.u4_share_disp_buf = u4_share_disp_buf;
    374         s_init_ip.u4_num_extra_disp_buf = 0;
    375 
    376         s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op);
    377 
    378         s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
    379         s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat;
    380 
    381         mCodecCtx = (iv_obj_t*)mMemRecords[0].pv_base;
    382         mCodecCtx->pv_fxns = dec_fxns;
    383         mCodecCtx->u4_size = sizeof(iv_obj_t);
    384 
    385         ALOGD("Initializing decoder");
    386         status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip,
    387                 (void *)&s_init_op);
    388         if (status != IV_SUCCESS) {
    389             ALOGE("Error in init: 0x%x",
    390                     s_init_op.s_ivd_init_op_t.u4_error_code);
    391             return UNKNOWN_ERROR;
    392         }
    393     }
    394 
    395     /* Reset the plugin state */
    396     resetPlugin();
    397 
    398     /* Set the run time (dynamic) parameters */
    399     setParams(displayStride);
    400 
    401     /* Set number of cores/threads to be used by the codec */
    402     setNumCores();
    403 
    404     /* Get codec version */
    405     logVersion();
    406 
    407     /* Allocate internal picture buffer */
    408     uint32_t bufferSize = displaySizeY * 3 / 2;
    409     mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
    410     if (NULL == mFlushOutBuffer) {
    411         ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize);
    412         return NO_MEMORY;
    413     }
    414 
    415     mInitNeeded = false;
    416     mFlushNeeded = false;
    417     return OK;
    418 }
    419 
    420 status_t SoftHEVC::deInitDecoder() {
    421     size_t i;
    422 
    423     if (mMemRecords) {
    424         iv_mem_rec_t *ps_mem_rec;
    425 
    426         ps_mem_rec = mMemRecords;
    427         ALOGD("Freeing codec memory");
    428         for (i = 0; i < mNumMemRecords; i++) {
    429             if(ps_mem_rec->pv_base) {
    430                 ivd_aligned_free(ps_mem_rec->pv_base);
    431             }
    432             ps_mem_rec++;
    433         }
    434         ivd_aligned_free(mMemRecords);
    435         mMemRecords = NULL;
    436     }
    437 
    438     if(mFlushOutBuffer) {
    439         ivd_aligned_free(mFlushOutBuffer);
    440         mFlushOutBuffer = NULL;
    441     }
    442 
    443     mInitNeeded = true;
    444     mChangingResolution = false;
    445 
    446     return OK;
    447 }
    448 
    449 status_t SoftHEVC::reInitDecoder() {
    450     status_t ret;
    451 
    452     deInitDecoder();
    453 
    454     ret = initDecoder();
    455     if (OK != ret) {
    456         ALOGE("Create failure");
    457         deInitDecoder();
    458         return NO_MEMORY;
    459     }
    460     return OK;
    461 }
    462 
    463 void SoftHEVC::onReset() {
    464     ALOGD("onReset called");
    465     SoftVideoDecoderOMXComponent::onReset();
    466 
    467     resetDecoder();
    468     resetPlugin();
    469 }
    470 
    471 OMX_ERRORTYPE SoftHEVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
    472     const uint32_t oldWidth = mWidth;
    473     const uint32_t oldHeight = mHeight;
    474     OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
    475     if (mWidth != oldWidth || mHeight != oldHeight) {
    476         reInitDecoder();
    477     }
    478     return ret;
    479 }
    480 
    481 void SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip,
    482         ivd_video_decode_op_t *ps_dec_op,
    483         OMX_BUFFERHEADERTYPE *inHeader,
    484         OMX_BUFFERHEADERTYPE *outHeader,
    485         size_t timeStampIx) {
    486     size_t sizeY = outputBufferWidth() * outputBufferHeight();
    487     size_t sizeUV;
    488     uint8_t *pBuf;
    489 
    490     ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
    491     ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
    492 
    493     ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
    494 
    495     /* When in flush and after EOS with zero byte input,
    496      * inHeader is set to zero. Hence check for non-null */
    497     if (inHeader) {
    498         ps_dec_ip->u4_ts = timeStampIx;
    499         ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
    500                 + inHeader->nOffset;
    501         ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
    502     } else {
    503         ps_dec_ip->u4_ts = 0;
    504         ps_dec_ip->pv_stream_buffer = NULL;
    505         ps_dec_ip->u4_num_Bytes = 0;
    506     }
    507 
    508     if (outHeader) {
    509         pBuf = outHeader->pBuffer;
    510     } else {
    511         pBuf = mFlushOutBuffer;
    512     }
    513 
    514     sizeUV = sizeY / 4;
    515     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
    516     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
    517     ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
    518 
    519     ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
    520     ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
    521     ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
    522     ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
    523     return;
    524 }
    525 void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) {
    526     /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
    527     if (kOutputPortIndex == portIndex) {
    528         setFlushMode();
    529 
    530         while (true) {
    531             ivd_video_decode_ip_t s_dec_ip;
    532             ivd_video_decode_op_t s_dec_op;
    533             IV_API_CALL_STATUS_T status;
    534             size_t sizeY, sizeUV;
    535 
    536             setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
    537 
    538             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
    539                     (void *)&s_dec_op);
    540             if (0 == s_dec_op.u4_output_present) {
    541                 resetPlugin();
    542                 break;
    543             }
    544         }
    545     }
    546 }
    547 
    548 void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
    549     UNUSED(portIndex);
    550 
    551     if (mOutputPortSettingsChange != NONE) {
    552         return;
    553     }
    554 
    555     List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
    556     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
    557 
    558     /* If input EOS is seen and decoder is not in flush mode,
    559      * set the decoder in flush mode.
    560      * There can be a case where EOS is sent along with last picture data
    561      * In that case, only after decoding that input data, decoder has to be
    562      * put in flush. This case is handled here  */
    563 
    564     if (mReceivedEOS && !mIsInFlush) {
    565         setFlushMode();
    566     }
    567 
    568     while (!outQueue.empty()) {
    569         BufferInfo *inInfo;
    570         OMX_BUFFERHEADERTYPE *inHeader;
    571 
    572         BufferInfo *outInfo;
    573         OMX_BUFFERHEADERTYPE *outHeader;
    574         size_t timeStampIx;
    575 
    576         inInfo = NULL;
    577         inHeader = NULL;
    578 
    579         if (!mIsInFlush) {
    580             if (!inQueue.empty()) {
    581                 inInfo = *inQueue.begin();
    582                 inHeader = inInfo->mHeader;
    583             } else {
    584                 break;
    585             }
    586         }
    587 
    588         outInfo = *outQueue.begin();
    589         outHeader = outInfo->mHeader;
    590         outHeader->nFlags = 0;
    591         outHeader->nTimeStamp = 0;
    592         outHeader->nOffset = 0;
    593 
    594         if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
    595             ALOGD("EOS seen on input");
    596             mReceivedEOS = true;
    597             if (inHeader->nFilledLen == 0) {
    598                 inQueue.erase(inQueue.begin());
    599                 inInfo->mOwnedByUs = false;
    600                 notifyEmptyBufferDone(inHeader);
    601                 inHeader = NULL;
    602                 setFlushMode();
    603             }
    604         }
    605 
    606         // When there is an init required and the decoder is not in flush mode,
    607         // update output port's definition and reinitialize decoder.
    608         if (mInitNeeded && !mIsInFlush) {
    609             bool portWillReset = false;
    610             handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
    611 
    612             CHECK_EQ(reInitDecoder(), (status_t)OK);
    613             return;
    614         }
    615 
    616         /* Get a free slot in timestamp array to hold input timestamp */
    617         {
    618             size_t i;
    619             timeStampIx = 0;
    620             for (i = 0; i < MAX_TIME_STAMPS; i++) {
    621                 if (!mTimeStampsValid[i]) {
    622                     timeStampIx = i;
    623                     break;
    624                 }
    625             }
    626             if (inHeader != NULL) {
    627                 mTimeStampsValid[timeStampIx] = true;
    628                 mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
    629             }
    630         }
    631 
    632         {
    633             ivd_video_decode_ip_t s_dec_ip;
    634             ivd_video_decode_op_t s_dec_op;
    635             WORD32 timeDelay, timeTaken;
    636             size_t sizeY, sizeUV;
    637 
    638             setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
    639 
    640             GETTIME(&mTimeStart, NULL);
    641             /* Compute time elapsed between end of previous decode()
    642              * to start of current decode() */
    643             TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
    644 
    645             IV_API_CALL_STATUS_T status;
    646             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    647             // FIXME: Compare |status| to IHEVCD_UNSUPPORTED_DIMENSIONS, which is not one of the
    648             // IV_API_CALL_STATUS_T, seems be wrong. But this is what the decoder returns right now.
    649             // The decoder should be fixed so that |u4_error_code| instead of |status| returns
    650             // IHEVCD_UNSUPPORTED_DIMENSIONS.
    651             bool unsupportedDimensions =
    652                 ((IHEVCD_UNSUPPORTED_DIMENSIONS == (IHEVCD_CXA_ERROR_CODES_T)status)
    653                     || (IHEVCD_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code));
    654             bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
    655 
    656             GETTIME(&mTimeEnd, NULL);
    657             /* Compute time taken for decode() */
    658             TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
    659 
    660             ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
    661                    s_dec_op.u4_num_bytes_consumed);
    662             if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
    663                 mFlushNeeded = true;
    664             }
    665 
    666             if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
    667                 /* If the input did not contain picture data, then ignore
    668                  * the associated timestamp */
    669                 mTimeStampsValid[timeStampIx] = false;
    670             }
    671 
    672             // This is needed to handle CTS DecoderTest testCodecResetsHEVCWithoutSurface,
    673             // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
    674             if (unsupportedDimensions && !mFlushNeeded) {
    675                 bool portWillReset = false;
    676                 handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
    677 
    678                 CHECK_EQ(reInitDecoder(), (status_t)OK);
    679 
    680                 setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
    681 
    682                 ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
    683                 return;
    684             }
    685 
    686             // If the decoder is in the changing resolution mode and there is no output present,
    687             // that means the switching is done and it's ready to reset the decoder and the plugin.
    688             if (mChangingResolution && !s_dec_op.u4_output_present) {
    689                 mChangingResolution = false;
    690                 resetDecoder();
    691                 resetPlugin();
    692                 continue;
    693             }
    694 
    695             if (unsupportedDimensions || resChanged) {
    696                 mChangingResolution = true;
    697                 if (mFlushNeeded) {
    698                     setFlushMode();
    699                 }
    700 
    701                 if (unsupportedDimensions) {
    702                     mNewWidth = s_dec_op.u4_pic_wd;
    703                     mNewHeight = s_dec_op.u4_pic_ht;
    704                     mInitNeeded = true;
    705                 }
    706                 continue;
    707             }
    708 
    709             if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
    710                 uint32_t width = s_dec_op.u4_pic_wd;
    711                 uint32_t height = s_dec_op.u4_pic_ht;
    712                 bool portWillReset = false;
    713                 handlePortSettingsChange(&portWillReset, width, height);
    714 
    715                 if (portWillReset) {
    716                     resetDecoder();
    717                     return;
    718                 }
    719             }
    720 
    721             if (s_dec_op.u4_output_present) {
    722                 outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
    723 
    724                 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
    725                 mTimeStampsValid[s_dec_op.u4_ts] = false;
    726 
    727                 outInfo->mOwnedByUs = false;
    728                 outQueue.erase(outQueue.begin());
    729                 outInfo = NULL;
    730                 notifyFillBufferDone(outHeader);
    731                 outHeader = NULL;
    732             } else {
    733                 /* If in flush mode and no output is returned by the codec,
    734                  * then come out of flush mode */
    735                 mIsInFlush = false;
    736 
    737                 /* If EOS was recieved on input port and there is no output
    738                  * from the codec, then signal EOS on output port */
    739                 if (mReceivedEOS) {
    740                     outHeader->nFilledLen = 0;
    741                     outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
    742 
    743                     outInfo->mOwnedByUs = false;
    744                     outQueue.erase(outQueue.begin());
    745                     outInfo = NULL;
    746                     notifyFillBufferDone(outHeader);
    747                     outHeader = NULL;
    748                     resetPlugin();
    749                 }
    750             }
    751         }
    752 
    753         // TODO: Handle more than one picture data
    754         if (inHeader != NULL) {
    755             inInfo->mOwnedByUs = false;
    756             inQueue.erase(inQueue.begin());
    757             inInfo = NULL;
    758             notifyEmptyBufferDone(inHeader);
    759             inHeader = NULL;
    760         }
    761     }
    762 }
    763 
    764 }  // namespace android
    765 
    766 android::SoftOMXComponent *createSoftOMXComponent(const char *name,
    767         const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
    768         OMX_COMPONENTTYPE **component) {
    769     return new android::SoftHEVC(name, callbacks, appData, component);
    770 }
    771