SoftHEVC.cpp revision ff64ea33382081f46d4b1061df00298bbbe3dd65
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "SoftHEVC"
19#include <utils/Log.h>
20
21#include "ihevc_typedefs.h"
22#include "iv.h"
23#include "ivd.h"
24#include "ihevcd_cxa.h"
25#include "SoftHEVC.h"
26
27#include <media/stagefright/foundation/ADebug.h>
28#include <media/stagefright/foundation/AUtils.h>
29#include <media/stagefright/MediaDefs.h>
30#include <OMX_VideoExt.h>
31
32namespace android {
33
34#define componentName                   "video_decoder.hevc"
35#define codingType                      OMX_VIDEO_CodingHEVC
36#define CODEC_MIME_TYPE                 MEDIA_MIMETYPE_VIDEO_HEVC
37
38/** Function and structure definitions to keep code similar for each codec */
39#define ivdec_api_function              ihevcd_cxa_api_function
40#define ivdext_create_ip_t              ihevcd_cxa_create_ip_t
41#define ivdext_create_op_t              ihevcd_cxa_create_op_t
42#define ivdext_delete_ip_t              ihevcd_cxa_delete_ip_t
43#define ivdext_delete_op_t              ihevcd_cxa_delete_op_t
44#define ivdext_ctl_set_num_cores_ip_t   ihevcd_cxa_ctl_set_num_cores_ip_t
45#define ivdext_ctl_set_num_cores_op_t   ihevcd_cxa_ctl_set_num_cores_op_t
46
47#define IVDEXT_CMD_CTL_SET_NUM_CORES    \
48        (IVD_CONTROL_API_COMMAND_TYPE_T)IHEVCD_CXA_CMD_CTL_SET_NUM_CORES
49
50static const CodecProfileLevel kProfileLevels[] = {
51    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel1  },
52    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel2  },
53    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel21 },
54    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel3  },
55    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel31 },
56    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel4  },
57    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel41 },
58    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel5  },
59    { OMX_VIDEO_HEVCProfileMain, OMX_VIDEO_HEVCMainTierLevel51 },
60};
61
62SoftHEVC::SoftHEVC(
63        const char *name,
64        const OMX_CALLBACKTYPE *callbacks,
65        OMX_PTR appData,
66        OMX_COMPONENTTYPE **component)
67    : SoftVideoDecoderOMXComponent(name, componentName, codingType,
68            kProfileLevels, ARRAY_SIZE(kProfileLevels),
69            320 /* width */, 240 /* height */, callbacks,
70            appData, component),
71      mCodecCtx(NULL),
72      mFlushOutBuffer(NULL),
73      mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
74      mIvColorFormat(IV_YUV_420P),
75      mChangingResolution(false),
76      mSignalledError(false),
77      mStride(mWidth) {
78    const size_t kMinCompressionRatio = 4 /* compressionRatio (for Level 4+) */;
79    const size_t kMaxOutputBufferSize = 2048 * 2048 * 3 / 2;
80    // INPUT_BUF_SIZE is given by HEVC codec as minimum input size
81    initPorts(
82            kNumBuffers, max(kMaxOutputBufferSize / kMinCompressionRatio, (size_t)INPUT_BUF_SIZE),
83            kNumBuffers, CODEC_MIME_TYPE, kMinCompressionRatio);
84}
85
86status_t SoftHEVC::init() {
87    return initDecoder();
88}
89
90SoftHEVC::~SoftHEVC() {
91    ALOGV("In SoftHEVC::~SoftHEVC");
92    CHECK_EQ(deInitDecoder(), (status_t)OK);
93}
94
95static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
96    UNUSED(ctxt);
97    return memalign(alignment, size);
98}
99
100static void ivd_aligned_free(void *ctxt, void *buf) {
101    UNUSED(ctxt);
102    free(buf);
103    return;
104}
105
106static size_t GetCPUCoreCount() {
107    long cpuCoreCount = 1;
108#if defined(_SC_NPROCESSORS_ONLN)
109    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
110#else
111    // _SC_NPROC_ONLN must be defined...
112    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
113#endif
114    CHECK(cpuCoreCount >= 1);
115    ALOGV("Number of CPU cores: %ld", cpuCoreCount);
116    return (size_t)cpuCoreCount;
117}
118
119void SoftHEVC::logVersion() {
120    ivd_ctl_getversioninfo_ip_t s_ctl_ip;
121    ivd_ctl_getversioninfo_op_t s_ctl_op;
122    UWORD8 au1_buf[512];
123    IV_API_CALL_STATUS_T status;
124
125    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
126    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
127    s_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
128    s_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
129    s_ctl_ip.pv_version_buffer = au1_buf;
130    s_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);
131
132    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
133            (void *)&s_ctl_op);
134
135    if (status != IV_SUCCESS) {
136        ALOGE("Error in getting version number: 0x%x",
137                s_ctl_op.u4_error_code);
138    } else {
139        ALOGV("Ittiam decoder version number: %s",
140                (char *)s_ctl_ip.pv_version_buffer);
141    }
142    return;
143}
144
145status_t SoftHEVC::setParams(size_t stride) {
146    ivd_ctl_set_config_ip_t s_ctl_ip;
147    ivd_ctl_set_config_op_t s_ctl_op;
148    IV_API_CALL_STATUS_T status;
149    s_ctl_ip.u4_disp_wd = (UWORD32)stride;
150    s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
151
152    s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
153    s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
154    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
155    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
156    s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
157    s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
158
159    ALOGV("Set the run-time (dynamic) parameters stride = %zu", stride);
160    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
161            (void *)&s_ctl_op);
162
163    if (status != IV_SUCCESS) {
164        ALOGE("Error in setting the run-time parameters: 0x%x",
165                s_ctl_op.u4_error_code);
166
167        return UNKNOWN_ERROR;
168    }
169    return OK;
170}
171
172status_t SoftHEVC::resetPlugin() {
173    mIsInFlush = false;
174    mReceivedEOS = false;
175    memset(mTimeStamps, 0, sizeof(mTimeStamps));
176    memset(mTimeStampsValid, 0, sizeof(mTimeStampsValid));
177
178    /* Initialize both start and end times */
179    gettimeofday(&mTimeStart, NULL);
180    gettimeofday(&mTimeEnd, NULL);
181
182    return OK;
183}
184
185status_t SoftHEVC::resetDecoder() {
186    ivd_ctl_reset_ip_t s_ctl_ip;
187    ivd_ctl_reset_op_t s_ctl_op;
188    IV_API_CALL_STATUS_T status;
189
190    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
191    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
192    s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
193    s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);
194
195    status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
196            (void *)&s_ctl_op);
197    if (IV_SUCCESS != status) {
198        ALOGE("Error in reset: 0x%x", s_ctl_op.u4_error_code);
199        return UNKNOWN_ERROR;
200    }
201    mSignalledError = false;
202
203    /* Set number of cores/threads to be used by the codec */
204    setNumCores();
205
206    mStride = 0;
207    return OK;
208}
209
210status_t SoftHEVC::setNumCores() {
211    ivdext_ctl_set_num_cores_ip_t s_set_cores_ip;
212    ivdext_ctl_set_num_cores_op_t s_set_cores_op;
213    IV_API_CALL_STATUS_T status;
214    s_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
215    s_set_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
216    s_set_cores_ip.u4_num_cores = MIN(mNumCores, CODEC_MAX_NUM_CORES);
217    s_set_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
218    s_set_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
219    ALOGV("Set number of cores to %u", s_set_cores_ip.u4_num_cores);
220    status = ivdec_api_function(mCodecCtx, (void *)&s_set_cores_ip,
221            (void *)&s_set_cores_op);
222    if (IV_SUCCESS != status) {
223        ALOGE("Error in setting number of cores: 0x%x",
224                s_set_cores_op.u4_error_code);
225        return UNKNOWN_ERROR;
226    }
227    return OK;
228}
229
230status_t SoftHEVC::setFlushMode() {
231    IV_API_CALL_STATUS_T status;
232    ivd_ctl_flush_ip_t s_video_flush_ip;
233    ivd_ctl_flush_op_t s_video_flush_op;
234
235    s_video_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
236    s_video_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
237    s_video_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
238    s_video_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
239    ALOGV("Set the decoder in flush mode ");
240
241    /* Set the decoder in Flush mode, subsequent decode() calls will flush */
242    status = ivdec_api_function(mCodecCtx, (void *)&s_video_flush_ip,
243            (void *)&s_video_flush_op);
244
245    if (status != IV_SUCCESS) {
246        ALOGE("Error in setting the decoder in flush mode: (%d) 0x%x", status,
247                s_video_flush_op.u4_error_code);
248        return UNKNOWN_ERROR;
249    }
250
251    mIsInFlush = true;
252    return OK;
253}
254
255status_t SoftHEVC::initDecoder() {
256    IV_API_CALL_STATUS_T status;
257
258    mNumCores = GetCPUCoreCount();
259    mCodecCtx = NULL;
260
261    mStride = outputBufferWidth();
262
263    /* Initialize the decoder */
264    {
265        ivdext_create_ip_t s_create_ip;
266        ivdext_create_op_t s_create_op;
267
268        void *dec_fxns = (void *)ivdec_api_function;
269
270        s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
271        s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
272        s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
273        s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
274        s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
275        s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
276        s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
277        s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
278
279        status = ivdec_api_function(mCodecCtx, (void *)&s_create_ip, (void *)&s_create_op);
280
281        mCodecCtx = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
282        mCodecCtx->pv_fxns = dec_fxns;
283        mCodecCtx->u4_size = sizeof(iv_obj_t);
284
285        if (status != IV_SUCCESS) {
286            ALOGE("Error in create: 0x%x",
287                    s_create_op.s_ivd_create_op_t.u4_error_code);
288            deInitDecoder();
289            mCodecCtx = NULL;
290            return UNKNOWN_ERROR;
291        }
292    }
293
294    /* Reset the plugin state */
295    resetPlugin();
296
297    /* Set the run time (dynamic) parameters */
298    setParams(mStride);
299
300    /* Set number of cores/threads to be used by the codec */
301    setNumCores();
302
303    /* Get codec version */
304    logVersion();
305
306    mFlushNeeded = false;
307    return OK;
308}
309
310status_t SoftHEVC::deInitDecoder() {
311    size_t i;
312    IV_API_CALL_STATUS_T status;
313
314    if (mCodecCtx) {
315        ivdext_delete_ip_t s_delete_ip;
316        ivdext_delete_op_t s_delete_op;
317
318        s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
319        s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
320
321        s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
322
323        status = ivdec_api_function(mCodecCtx, (void *)&s_delete_ip, (void *)&s_delete_op);
324        if (status != IV_SUCCESS) {
325            ALOGE("Error in delete: 0x%x",
326                    s_delete_op.s_ivd_delete_op_t.u4_error_code);
327            return UNKNOWN_ERROR;
328        }
329    }
330
331
332    mChangingResolution = false;
333
334    return OK;
335}
336
337void SoftHEVC::onReset() {
338    ALOGV("onReset called");
339    SoftVideoDecoderOMXComponent::onReset();
340
341    mSignalledError = false;
342    resetDecoder();
343    resetPlugin();
344}
345
346bool SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip,
347        ivd_video_decode_op_t *ps_dec_op,
348        OMX_BUFFERHEADERTYPE *inHeader,
349        OMX_BUFFERHEADERTYPE *outHeader,
350        size_t timeStampIx) {
351    size_t sizeY = outputBufferWidth() * outputBufferHeight();
352    size_t sizeUV;
353
354    ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
355    ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
356
357    ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
358
359    /* When in flush and after EOS with zero byte input,
360     * inHeader is set to zero. Hence check for non-null */
361    if (inHeader) {
362        ps_dec_ip->u4_ts = timeStampIx;
363        ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
364                + inHeader->nOffset;
365        ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
366    } else {
367        ps_dec_ip->u4_ts = 0;
368        ps_dec_ip->pv_stream_buffer = NULL;
369        ps_dec_ip->u4_num_Bytes = 0;
370    }
371
372    sizeUV = sizeY / 4;
373    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
374    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
375    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
376
377    uint8_t *pBuf;
378    if (outHeader) {
379        if (outHeader->nAllocLen < sizeY + (sizeUV * 2)) {
380            android_errorWriteLog(0x534e4554, "27833616");
381            return false;
382        }
383        pBuf = outHeader->pBuffer;
384    } else {
385        // mFlushOutBuffer always has the right size.
386        pBuf = mFlushOutBuffer;
387    }
388
389    ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
390    ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
391    ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
392    ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
393    return true;
394}
395void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) {
396    /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
397    if (kOutputPortIndex == portIndex) {
398        setFlushMode();
399
400        /* Allocate a picture buffer to flushed data */
401        uint32_t displayStride = outputBufferWidth();
402        uint32_t displayHeight = outputBufferHeight();
403
404        uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
405        mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize);
406        if (NULL == mFlushOutBuffer) {
407            ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize);
408            return;
409        }
410
411        while (true) {
412            ivd_video_decode_ip_t s_dec_ip;
413            ivd_video_decode_op_t s_dec_op;
414            IV_API_CALL_STATUS_T status;
415            size_t sizeY, sizeUV;
416
417            setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
418
419            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
420                    (void *)&s_dec_op);
421            if (0 == s_dec_op.u4_output_present) {
422                resetPlugin();
423                break;
424            }
425        }
426
427        if (mFlushOutBuffer) {
428            free(mFlushOutBuffer);
429            mFlushOutBuffer = NULL;
430        }
431
432    }
433}
434
435void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
436    UNUSED(portIndex);
437
438    if (mSignalledError) {
439        return;
440    }
441    if (mOutputPortSettingsChange != NONE) {
442        return;
443    }
444
445    if (NULL == mCodecCtx) {
446        if (OK != initDecoder()) {
447            return;
448        }
449    }
450    if (outputBufferWidth() != mStride) {
451        /* Set the run-time (dynamic) parameters */
452        mStride = outputBufferWidth();
453        setParams(mStride);
454    }
455
456    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
457    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
458
459    /* If input EOS is seen and decoder is not in flush mode,
460     * set the decoder in flush mode.
461     * There can be a case where EOS is sent along with last picture data
462     * In that case, only after decoding that input data, decoder has to be
463     * put in flush. This case is handled here  */
464
465    if (mReceivedEOS && !mIsInFlush) {
466        setFlushMode();
467    }
468
469    while (!outQueue.empty()) {
470        BufferInfo *inInfo;
471        OMX_BUFFERHEADERTYPE *inHeader;
472
473        BufferInfo *outInfo;
474        OMX_BUFFERHEADERTYPE *outHeader;
475        size_t timeStampIx;
476
477        inInfo = NULL;
478        inHeader = NULL;
479
480        if (!mIsInFlush) {
481            if (!inQueue.empty()) {
482                inInfo = *inQueue.begin();
483                inHeader = inInfo->mHeader;
484            } else {
485                break;
486            }
487        }
488
489        outInfo = *outQueue.begin();
490        outHeader = outInfo->mHeader;
491        outHeader->nFlags = 0;
492        outHeader->nTimeStamp = 0;
493        outHeader->nOffset = 0;
494
495        if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
496            mReceivedEOS = true;
497            if (inHeader->nFilledLen == 0) {
498                inQueue.erase(inQueue.begin());
499                inInfo->mOwnedByUs = false;
500                notifyEmptyBufferDone(inHeader);
501                inHeader = NULL;
502                setFlushMode();
503            }
504        }
505
506        /* Get a free slot in timestamp array to hold input timestamp */
507        {
508            size_t i;
509            timeStampIx = 0;
510            for (i = 0; i < MAX_TIME_STAMPS; i++) {
511                if (!mTimeStampsValid[i]) {
512                    timeStampIx = i;
513                    break;
514                }
515            }
516            if (inHeader != NULL) {
517                mTimeStampsValid[timeStampIx] = true;
518                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
519            }
520        }
521
522        {
523            ivd_video_decode_ip_t s_dec_ip;
524            ivd_video_decode_op_t s_dec_op;
525            WORD32 timeDelay, timeTaken;
526            size_t sizeY, sizeUV;
527
528            if (!setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx)) {
529                ALOGE("Decoder arg setup failed");
530                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
531                mSignalledError = true;
532                return;
533            }
534
535            GETTIME(&mTimeStart, NULL);
536            /* Compute time elapsed between end of previous decode()
537             * to start of current decode() */
538            TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
539
540            IV_API_CALL_STATUS_T status;
541            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
542
543            bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
544
545            GETTIME(&mTimeEnd, NULL);
546            /* Compute time taken for decode() */
547            TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
548
549            ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
550                   s_dec_op.u4_num_bytes_consumed);
551            if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
552                mFlushNeeded = true;
553            }
554
555            if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
556                /* If the input did not contain picture data, then ignore
557                 * the associated timestamp */
558                mTimeStampsValid[timeStampIx] = false;
559            }
560
561            // If the decoder is in the changing resolution mode and there is no output present,
562            // that means the switching is done and it's ready to reset the decoder and the plugin.
563            if (mChangingResolution && !s_dec_op.u4_output_present) {
564                mChangingResolution = false;
565                resetDecoder();
566                resetPlugin();
567                continue;
568            }
569
570            if (resChanged) {
571                mChangingResolution = true;
572                if (mFlushNeeded) {
573                    setFlushMode();
574                }
575                continue;
576            }
577
578            if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
579                uint32_t width = s_dec_op.u4_pic_wd;
580                uint32_t height = s_dec_op.u4_pic_ht;
581                bool portWillReset = false;
582                handlePortSettingsChange(&portWillReset, width, height);
583
584                if (portWillReset) {
585                    resetDecoder();
586                    return;
587                }
588            }
589
590            if (s_dec_op.u4_output_present) {
591                outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
592
593                outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
594                mTimeStampsValid[s_dec_op.u4_ts] = false;
595
596                outInfo->mOwnedByUs = false;
597                outQueue.erase(outQueue.begin());
598                outInfo = NULL;
599                notifyFillBufferDone(outHeader);
600                outHeader = NULL;
601            } else {
602                /* If in flush mode and no output is returned by the codec,
603                 * then come out of flush mode */
604                mIsInFlush = false;
605
606                /* If EOS was recieved on input port and there is no output
607                 * from the codec, then signal EOS on output port */
608                if (mReceivedEOS) {
609                    outHeader->nFilledLen = 0;
610                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
611
612                    outInfo->mOwnedByUs = false;
613                    outQueue.erase(outQueue.begin());
614                    outInfo = NULL;
615                    notifyFillBufferDone(outHeader);
616                    outHeader = NULL;
617                    resetPlugin();
618                }
619            }
620        }
621
622        // TODO: Handle more than one picture data
623        if (inHeader != NULL) {
624            inInfo->mOwnedByUs = false;
625            inQueue.erase(inQueue.begin());
626            inInfo = NULL;
627            notifyEmptyBufferDone(inHeader);
628            inHeader = NULL;
629        }
630    }
631}
632
633}  // namespace android
634
635android::SoftOMXComponent *createSoftOMXComponent(const char *name,
636        const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
637        OMX_COMPONENTTYPE **component) {
638    android::SoftHEVC *codec = new android::SoftHEVC(name, callbacks, appData, component);
639    if (codec->init() != android::OK) {
640        android::sp<android::SoftOMXComponent> release = codec;
641        return NULL;
642    }
643    return codec;
644}
645