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