SoftHEVC.cpp revision ec62e13719cfbd663fd8b63a110747a2630e582c
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
346void 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    uint8_t *pBuf;
354
355    ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t);
356    ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t);
357
358    ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
359
360    /* When in flush and after EOS with zero byte input,
361     * inHeader is set to zero. Hence check for non-null */
362    if (inHeader) {
363        ps_dec_ip->u4_ts = timeStampIx;
364        ps_dec_ip->pv_stream_buffer = inHeader->pBuffer
365                + inHeader->nOffset;
366        ps_dec_ip->u4_num_Bytes = inHeader->nFilledLen;
367    } else {
368        ps_dec_ip->u4_ts = 0;
369        ps_dec_ip->pv_stream_buffer = NULL;
370        ps_dec_ip->u4_num_Bytes = 0;
371    }
372
373    if (outHeader) {
374        pBuf = outHeader->pBuffer;
375    } else {
376        pBuf = mFlushOutBuffer;
377    }
378
379    sizeUV = sizeY / 4;
380    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[0] = sizeY;
381    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[1] = sizeUV;
382    ps_dec_ip->s_out_buffer.u4_min_out_buf_size[2] = sizeUV;
383
384    ps_dec_ip->s_out_buffer.pu1_bufs[0] = pBuf;
385    ps_dec_ip->s_out_buffer.pu1_bufs[1] = pBuf + sizeY;
386    ps_dec_ip->s_out_buffer.pu1_bufs[2] = pBuf + sizeY + sizeUV;
387    ps_dec_ip->s_out_buffer.u4_num_bufs = 3;
388    return;
389}
390void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) {
391    /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
392    if (kOutputPortIndex == portIndex) {
393        setFlushMode();
394
395        /* Allocate a picture buffer to flushed data */
396        uint32_t displayStride = outputBufferWidth();
397        uint32_t displayHeight = outputBufferHeight();
398
399        uint32_t bufferSize = displayStride * displayHeight * 3 / 2;
400        mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize);
401        if (NULL == mFlushOutBuffer) {
402            ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize);
403            return;
404        }
405
406        while (true) {
407            ivd_video_decode_ip_t s_dec_ip;
408            ivd_video_decode_op_t s_dec_op;
409            IV_API_CALL_STATUS_T status;
410            size_t sizeY, sizeUV;
411
412            setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
413
414            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
415                    (void *)&s_dec_op);
416            if (0 == s_dec_op.u4_output_present) {
417                resetPlugin();
418                break;
419            }
420        }
421
422        if (mFlushOutBuffer) {
423            free(mFlushOutBuffer);
424            mFlushOutBuffer = NULL;
425        }
426
427    }
428}
429
430void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
431    UNUSED(portIndex);
432
433    if (mSignalledError) {
434        return;
435    }
436    if (mOutputPortSettingsChange != NONE) {
437        return;
438    }
439
440    if (NULL == mCodecCtx) {
441        if (OK != initDecoder()) {
442            return;
443        }
444    }
445    if (outputBufferWidth() != mStride) {
446        /* Set the run-time (dynamic) parameters */
447        mStride = outputBufferWidth();
448        setParams(mStride);
449    }
450
451    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
452    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
453
454    /* If input EOS is seen and decoder is not in flush mode,
455     * set the decoder in flush mode.
456     * There can be a case where EOS is sent along with last picture data
457     * In that case, only after decoding that input data, decoder has to be
458     * put in flush. This case is handled here  */
459
460    if (mReceivedEOS && !mIsInFlush) {
461        setFlushMode();
462    }
463
464    while (!outQueue.empty()) {
465        BufferInfo *inInfo;
466        OMX_BUFFERHEADERTYPE *inHeader;
467
468        BufferInfo *outInfo;
469        OMX_BUFFERHEADERTYPE *outHeader;
470        size_t timeStampIx;
471
472        inInfo = NULL;
473        inHeader = NULL;
474
475        if (!mIsInFlush) {
476            if (!inQueue.empty()) {
477                inInfo = *inQueue.begin();
478                inHeader = inInfo->mHeader;
479            } else {
480                break;
481            }
482        }
483
484        outInfo = *outQueue.begin();
485        outHeader = outInfo->mHeader;
486        outHeader->nFlags = 0;
487        outHeader->nTimeStamp = 0;
488        outHeader->nOffset = 0;
489
490        if (inHeader != NULL && (inHeader->nFlags & OMX_BUFFERFLAG_EOS)) {
491            mReceivedEOS = true;
492            if (inHeader->nFilledLen == 0) {
493                inQueue.erase(inQueue.begin());
494                inInfo->mOwnedByUs = false;
495                notifyEmptyBufferDone(inHeader);
496                inHeader = NULL;
497                setFlushMode();
498            }
499        }
500
501        /* Get a free slot in timestamp array to hold input timestamp */
502        {
503            size_t i;
504            timeStampIx = 0;
505            for (i = 0; i < MAX_TIME_STAMPS; i++) {
506                if (!mTimeStampsValid[i]) {
507                    timeStampIx = i;
508                    break;
509                }
510            }
511            if (inHeader != NULL) {
512                mTimeStampsValid[timeStampIx] = true;
513                mTimeStamps[timeStampIx] = inHeader->nTimeStamp;
514            }
515        }
516
517        {
518            ivd_video_decode_ip_t s_dec_ip;
519            ivd_video_decode_op_t s_dec_op;
520            WORD32 timeDelay, timeTaken;
521            size_t sizeY, sizeUV;
522
523            setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
524
525            GETTIME(&mTimeStart, NULL);
526            /* Compute time elapsed between end of previous decode()
527             * to start of current decode() */
528            TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
529
530            IV_API_CALL_STATUS_T status;
531            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
532
533            bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
534
535            GETTIME(&mTimeEnd, NULL);
536            /* Compute time taken for decode() */
537            TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
538
539            ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
540                   s_dec_op.u4_num_bytes_consumed);
541            if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
542                mFlushNeeded = true;
543            }
544
545            if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
546                /* If the input did not contain picture data, then ignore
547                 * the associated timestamp */
548                mTimeStampsValid[timeStampIx] = false;
549            }
550
551            // If the decoder is in the changing resolution mode and there is no output present,
552            // that means the switching is done and it's ready to reset the decoder and the plugin.
553            if (mChangingResolution && !s_dec_op.u4_output_present) {
554                mChangingResolution = false;
555                resetDecoder();
556                resetPlugin();
557                continue;
558            }
559
560            if (resChanged) {
561                mChangingResolution = true;
562                if (mFlushNeeded) {
563                    setFlushMode();
564                }
565                continue;
566            }
567
568            if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
569                uint32_t width = s_dec_op.u4_pic_wd;
570                uint32_t height = s_dec_op.u4_pic_ht;
571                bool portWillReset = false;
572                handlePortSettingsChange(&portWillReset, width, height);
573
574                if (portWillReset) {
575                    resetDecoder();
576                    return;
577                }
578            }
579
580            if (s_dec_op.u4_output_present) {
581                outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
582
583                outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
584                mTimeStampsValid[s_dec_op.u4_ts] = false;
585
586                outInfo->mOwnedByUs = false;
587                outQueue.erase(outQueue.begin());
588                outInfo = NULL;
589                notifyFillBufferDone(outHeader);
590                outHeader = NULL;
591            } else {
592                /* If in flush mode and no output is returned by the codec,
593                 * then come out of flush mode */
594                mIsInFlush = false;
595
596                /* If EOS was recieved on input port and there is no output
597                 * from the codec, then signal EOS on output port */
598                if (mReceivedEOS) {
599                    outHeader->nFilledLen = 0;
600                    outHeader->nFlags |= OMX_BUFFERFLAG_EOS;
601
602                    outInfo->mOwnedByUs = false;
603                    outQueue.erase(outQueue.begin());
604                    outInfo = NULL;
605                    notifyFillBufferDone(outHeader);
606                    outHeader = NULL;
607                    resetPlugin();
608                }
609            }
610        }
611
612        // TODO: Handle more than one picture data
613        if (inHeader != NULL) {
614            inInfo->mOwnedByUs = false;
615            inQueue.erase(inQueue.begin());
616            inInfo = NULL;
617            notifyEmptyBufferDone(inHeader);
618            inHeader = NULL;
619        }
620    }
621}
622
623}  // namespace android
624
625android::SoftOMXComponent *createSoftOMXComponent(const char *name,
626        const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
627        OMX_COMPONENTTYPE **component) {
628    android::SoftHEVC *codec = new android::SoftHEVC(name, callbacks, appData, component);
629    if (codec->init() != android::OK) {
630        android::sp<android::SoftOMXComponent> release = codec;
631        return NULL;
632    }
633    return codec;
634}
635