SoftHEVC.cpp revision a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5
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
33namespace 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
51static 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
63SoftHEVC::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
88SoftHEVC::~SoftHEVC() {
89    ALOGD("In SoftHEVC::~SoftHEVC");
90    CHECK_EQ(deInitDecoder(), (status_t)OK);
91}
92
93static 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
106void 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
132status_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
159status_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
172status_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
198status_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
218status_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
243status_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
420status_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
449status_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
463void SoftHEVC::onReset() {
464    ALOGD("onReset called");
465    SoftVideoDecoderOMXComponent::onReset();
466
467    resetDecoder();
468    resetPlugin();
469}
470
471OMX_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
481void 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}
525void 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
548void 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
766android::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