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