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