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