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