SoftHEVC.cpp revision f6ef963fecde3b63696028fadce4bcfb5b998db0
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            320 /* width */, 240 /* 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
107void SoftHEVC::logVersion() {
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;
131}
132
133status_t SoftHEVC::setParams(size_t stride) {
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 = (UWORD32)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 = IVD_DECODE_FRAME;
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);
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    mMemRecords = NULL;
254    mFlushOutBuffer = NULL;
255
256    /* Initialize number of ref and reorder modes (for HEVC) */
257    u4_num_reorder_frames = 16;
258    u4_num_ref_frames = 16;
259    u4_share_disp_buf = 0;
260
261    if ((mWidth * mHeight) > (1920 * 1088)) {
262        i4_level = 50;
263    } else if ((mWidth * mHeight) > (1280 * 720)) {
264        i4_level = 40;
265    } else if ((mWidth * mHeight) > (960 * 540)) {
266        i4_level = 31;
267    } else if ((mWidth * mHeight) > (640 * 360)) {
268        i4_level = 30;
269    } else if ((mWidth * mHeight) > (352 * 288)) {
270        i4_level = 21;
271    } else {
272        i4_level = 20;
273    }
274    {
275        iv_num_mem_rec_ip_t s_num_mem_rec_ip;
276        iv_num_mem_rec_op_t s_num_mem_rec_op;
277
278        s_num_mem_rec_ip.u4_size = sizeof(s_num_mem_rec_ip);
279        s_num_mem_rec_op.u4_size = sizeof(s_num_mem_rec_op);
280        s_num_mem_rec_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
281
282        ALOGV("Get number of mem records");
283        status = ivdec_api_function(mCodecCtx, (void*)&s_num_mem_rec_ip,
284                (void*)&s_num_mem_rec_op);
285        if (IV_SUCCESS != status) {
286            ALOGE("Error in getting mem records: 0x%x",
287                    s_num_mem_rec_op.u4_error_code);
288            return UNKNOWN_ERROR;
289        }
290
291        mNumMemRecords = s_num_mem_rec_op.u4_num_mem_rec;
292    }
293
294    mMemRecords = (iv_mem_rec_t*)ivd_aligned_malloc(
295            128, mNumMemRecords * sizeof(iv_mem_rec_t));
296    if (mMemRecords == NULL) {
297        ALOGE("Allocation failure");
298        return NO_MEMORY;
299    }
300
301    memset(mMemRecords, 0, mNumMemRecords * sizeof(iv_mem_rec_t));
302
303    {
304        size_t i;
305        ivdext_fill_mem_rec_ip_t s_fill_mem_ip;
306        ivdext_fill_mem_rec_op_t s_fill_mem_op;
307        iv_mem_rec_t *ps_mem_rec;
308
309        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
310            sizeof(ivdext_fill_mem_rec_ip_t);
311        s_fill_mem_ip.i4_level = i4_level;
312        s_fill_mem_ip.u4_num_reorder_frames = u4_num_reorder_frames;
313        s_fill_mem_ip.u4_num_ref_frames = u4_num_ref_frames;
314        s_fill_mem_ip.u4_share_disp_buf = u4_share_disp_buf;
315        s_fill_mem_ip.u4_num_extra_disp_buf = 0;
316        s_fill_mem_ip.e_output_format = mIvColorFormat;
317
318        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
319        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
320        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth;
321        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight;
322        s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
323            sizeof(ivdext_fill_mem_rec_op_t);
324
325        ps_mem_rec = mMemRecords;
326        for (i = 0; i < mNumMemRecords; i++)
327            ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
328
329        status = ivdec_api_function(mCodecCtx, (void *)&s_fill_mem_ip,
330                (void *)&s_fill_mem_op);
331
332        if (IV_SUCCESS != status) {
333            ALOGE("Error in filling mem records: 0x%x",
334                    s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
335            return UNKNOWN_ERROR;
336        }
337        mNumMemRecords =
338            s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
339
340        ps_mem_rec = mMemRecords;
341
342        for (i = 0; i < mNumMemRecords; i++) {
343            ps_mem_rec->pv_base = ivd_aligned_malloc(
344                    ps_mem_rec->u4_mem_alignment, ps_mem_rec->u4_mem_size);
345            if (ps_mem_rec->pv_base == NULL) {
346                ALOGE("Allocation failure for memory record #%zu of size %u",
347                        i, ps_mem_rec->u4_mem_size);
348                status = IV_FAIL;
349                return NO_MEMORY;
350            }
351
352            ps_mem_rec++;
353        }
354    }
355
356    /* Initialize the decoder */
357    {
358        ivdext_init_ip_t s_init_ip;
359        ivdext_init_op_t s_init_op;
360
361        void *dec_fxns = (void *)ivdec_api_function;
362
363        s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
364        s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
365        s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
366        s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth;
367        s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
368
369        s_init_ip.i4_level = i4_level;
370        s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames;
371        s_init_ip.u4_num_ref_frames = u4_num_ref_frames;
372        s_init_ip.u4_share_disp_buf = u4_share_disp_buf;
373        s_init_ip.u4_num_extra_disp_buf = 0;
374
375        s_init_op.s_ivd_init_op_t.u4_size = sizeof(s_init_op);
376
377        s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = mNumMemRecords;
378        s_init_ip.s_ivd_init_ip_t.e_output_format = mIvColorFormat;
379
380        mCodecCtx = (iv_obj_t*)mMemRecords[0].pv_base;
381        mCodecCtx->pv_fxns = dec_fxns;
382        mCodecCtx->u4_size = sizeof(iv_obj_t);
383
384        ALOGD("Initializing decoder");
385        status = ivdec_api_function(mCodecCtx, (void *)&s_init_ip,
386                (void *)&s_init_op);
387        if (status != IV_SUCCESS) {
388            ALOGE("Error in init: 0x%x",
389                    s_init_op.s_ivd_init_op_t.u4_error_code);
390            return UNKNOWN_ERROR;
391        }
392    }
393
394    /* Reset the plugin state */
395    resetPlugin();
396
397    /* Set the run time (dynamic) parameters */
398    setParams(0);
399
400    /* Set number of cores/threads to be used by the codec */
401    setNumCores();
402
403    /* Get codec version */
404    logVersion();
405
406    /* Allocate internal picture buffer */
407    mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, mStride * mHeight * 3 / 2);
408    if (NULL == mFlushOutBuffer) {
409        ALOGE("Could not allocate flushOutputBuffer of size %zu", mStride * mHeight * 3 / 2);
410        return NO_MEMORY;
411    }
412
413    return OK;
414}
415
416status_t SoftHEVC::deInitDecoder() {
417    size_t i;
418
419    if (mMemRecords) {
420        iv_mem_rec_t *ps_mem_rec;
421
422        ps_mem_rec = mMemRecords;
423        ALOGD("Freeing codec memory");
424        for (i = 0; i < mNumMemRecords; i++) {
425            if(ps_mem_rec->pv_base) {
426                ivd_aligned_free(ps_mem_rec->pv_base);
427            }
428            ps_mem_rec++;
429        }
430        ivd_aligned_free(mMemRecords);
431    }
432
433    if(mFlushOutBuffer) {
434        ivd_aligned_free(mFlushOutBuffer);
435    }
436    return OK;
437}
438
439status_t SoftHEVC::reInitDecoder() {
440    status_t ret;
441
442    deInitDecoder();
443
444    ret = initDecoder();
445    if (OK != ret) {
446        ALOGE("Create failure");
447        deInitDecoder();
448        return NO_MEMORY;
449    }
450    return OK;
451}
452void SoftHEVC::onReset() {
453    ALOGD("onReset called");
454    SoftVideoDecoderOMXComponent::onReset();
455
456    resetDecoder();
457    resetPlugin();
458}
459
460void SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip,
461        ivd_video_decode_op_t *ps_dec_op,
462        OMX_BUFFERHEADERTYPE *inHeader,
463        OMX_BUFFERHEADERTYPE *outHeader,
464        size_t sizeY,
465        size_t timeStampIx) {
466    size_t sizeUV;
467    uint8_t *pBuf;
468
469    ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
470    ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
471
472    ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
473
474    /* When in flush and after EOS with zero byte input,
475     * inHeader is set to zero. Hence check for non-null */
476    if (inHeader) {
477        ps_dec_ip->u4_ts = timeStampIx;
478        ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
479                + inHeader->nOffset;
480        ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
481    } else {
482        ps_dec_ip->u4_ts = 0;
483        ps_dec_ip->pv_stream_buffer = NULL;
484        ps_dec_ip->u4_num_Bytes = 0;
485    }
486
487    if (outHeader) {
488        pBuf = outHeader->pBuffer;
489    } else {
490        pBuf = mFlushOutBuffer;
491    }
492
493    sizeUV = sizeY / 4;
494    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
495    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
496    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
497
498    ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
499    ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
500    ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
501    ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
502    return;
503}
504void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) {
505    ALOGD("onPortFlushCompleted on port %d", portIndex);
506
507    /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
508    if (kOutputPortIndex == portIndex) {
509        setFlushMode();
510
511        while (true) {
512            ivd_video_decode_ip_t s_dec_ip;
513            ivd_video_decode_op_t s_dec_op;
514            IV_API_CALL_STATUS_T status;
515            size_t sizeY, sizeUV;
516
517            setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, mStride * mHeight, 0);
518
519            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
520                    (void *)&s_dec_op);
521            if (0 == s_dec_op.u4_output_present) {
522                resetPlugin();
523                break;
524            }
525        }
526    }
527}
528
529void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
530    IV_API_CALL_STATUS_T status;
531
532    UNUSED(portIndex);
533
534    if (mOutputPortSettingsChange != NONE) {
535        return;
536    }
537
538    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
539    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
540
541    /* If input EOS is seen and decoder is not in flush mode,
542     * set the decoder in flush mode.
543     * There can be a case where EOS is sent along with last picture data
544     * In that case, only after decoding that input data, decoder has to be
545     * put in flush. This case is handled here  */
546
547    if (mReceivedEOS && !mIsInFlush) {
548        setFlushMode();
549    }
550
551    while (outQueue.size() == kNumBuffers) {
552        BufferInfo *inInfo;
553        OMX_BUFFERHEADERTYPE *inHeader;
554
555        BufferInfo *outInfo;
556        OMX_BUFFERHEADERTYPE *outHeader;
557        size_t timeStampIx;
558
559        inInfo = NULL;
560        inHeader = NULL;
561
562        if (!mIsInFlush) {
563            if (!inQueue.empty()) {
564                inInfo = *inQueue.begin();
565                inHeader = inInfo->mHeader;
566            } else {
567                break;
568            }
569        }
570
571        outInfo = *outQueue.begin();
572        outHeader = outInfo->mHeader;
573        outHeader->nFlags = 0;
574        outHeader->nTimeStamp = 0;
575        outHeader->nOffset = 0;
576
577        if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
578            ALOGD("EOS seen on input");
579            mReceivedEOS = true;
580            if (inHeader->nFilledLen == 0) {
581                inQueue.erase(inQueue.begin());
582                inInfo->mOwnedByUs = false;
583                notifyEmptyBufferDone(inHeader);
584                inHeader = NULL;
585                setFlushMode();
586            }
587        }
588
589        /* Get a free slot in timestamp array to hold input timestamp */
590        {
591            size_t i;
592            timeStampIx = 0;
593            for (i = 0; i < MAX_TIME_STAMPS; i++) {
594                if (!mTimeStampsValid[i]) {
595                    timeStampIx = i;
596                    break;
597                }
598            }
599            if (inHeader != NULL) {
600                mTimeStampsValid[timeStampIx] = true;
601                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
602            }
603        }
604
605        {
606            ivd_video_decode_ip_t s_dec_ip;
607            ivd_video_decode_op_t s_dec_op;
608            WORD32 timeDelay, timeTaken;
609            size_t sizeY, sizeUV;
610
611            setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader,
612                          mStride * mHeight, timeStampIx);
613
614            GETTIME(&mTimeStart, NULL);
615            /* Compute time elapsed between end of previous decode()
616             * to start of current decode() */
617            TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
618
619            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
620                    (void *)&s_dec_op);
621
622            GETTIME(&mTimeEnd, NULL);
623            /* Compute time taken for decode() */
624            TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
625
626            ALOGD("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
627                    s_dec_op.u4_num_bytes_consumed);
628
629            /* If width and height are greater than the
630             * the dimensions used during codec create, then
631             * delete the current instance and recreate an instance with
632             * new dimensions */
633
634            if(IHEVCD_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code) {
635                mInitWidth = s_dec_op.u4_pic_wd;
636                mInitHeight = s_dec_op.u4_pic_ht;
637                mStride = mInitWidth;
638                CHECK_EQ(reInitDecoder(), (status_t)OK);
639
640                setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader,
641                              mStride * mHeight, timeStampIx);
642
643                status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
644                        (void *)&s_dec_op);
645            }
646            if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
647                /* If the input did not contain picture data, then ignore
648                 * the associated timestamp */
649                mTimeStampsValid[timeStampIx] = false;
650            }
651
652            /* If valid height and width are decoded,
653             * then look at change in resolution */
654            if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
655                uint32_t width = s_dec_op.u4_pic_wd;
656                uint32_t height = s_dec_op.u4_pic_ht;
657
658                if ((width != mWidth) || (height != mHeight)) {
659                    mWidth = width;
660                    mHeight = height;
661                    mStride = mWidth;
662
663                    updatePortDefinitions();
664
665                    notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
666                    mOutputPortSettingsChange = AWAITING_DISABLED;
667                    return;
668                }
669            }
670
671            if (s_dec_op.u4_output_present) {
672                outHeader->nFilledLen = (mStride * mHeight * 3) / 2;
673
674                outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
675                mTimeStampsValid[s_dec_op.u4_ts] = false;
676
677                outInfo->mOwnedByUs = false;
678                outQueue.erase(outQueue.begin());
679                outInfo = NULL;
680                notifyFillBufferDone(outHeader);
681                outHeader = NULL;
682            } else {
683                /* If in flush mode and no output is returned by the codec,
684                 * then come out of flush mode */
685                mIsInFlush = false;
686
687                /* If EOS was recieved on input port and there is no output
688                 * from the codec, then signal EOS on output port */
689                if (mReceivedEOS) {
690                    outHeader->nFilledLen = 0;
691                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
692
693                    outInfo->mOwnedByUs = false;
694                    outQueue.erase(outQueue.begin());
695                    outInfo = NULL;
696                    notifyFillBufferDone(outHeader);
697                    outHeader = NULL;
698                    resetPlugin();
699                }
700            }
701        }
702
703        // TODO: Handle more than one picture data
704        if (inHeader != NULL) {
705            inInfo->mOwnedByUs = false;
706            inQueue.erase(inQueue.begin());
707            inInfo = NULL;
708            notifyEmptyBufferDone(inHeader);
709            inHeader = NULL;
710        }
711    }
712}
713
714} // namespace android
715
716android::SoftOMXComponent *createSoftOMXComponent(const char *name,
717        const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
718        OMX_COMPONENTTYPE **component) {
719    return new android::SoftHEVC(name, callbacks, appData, component);
720}
721