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