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