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