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