1bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber/*
2bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * Copyright (C) 2011 The Android Open Source Project
3bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber *
4bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * you may not use this file except in compliance with the License.
6bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * You may obtain a copy of the License at
7bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber *
8bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber *
10bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * Unless required by applicable law or agreed to in writing, software
11bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * See the License for the specific language governing permissions and
14bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * limitations under the License.
15bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber */
16bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
17bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber//#define LOG_NDEBUG 0
18bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#define LOG_TAG "SoftVPX"
19bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include <utils/Log.h>
209486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang#include <utils/misc.h>
219486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang#include "OMX_VideoExt.h"
22bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
23bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include "SoftVPX.h"
24bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
25bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include <media/stagefright/foundation/ADebug.h>
26bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include <media/stagefright/MediaDefs.h>
27bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
28bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
29bbba88cb1bdc34705d1477208990a06904c022e7Andreas Hubernamespace android {
30bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
319486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang// Only need to declare the highest supported profile and level here.
329486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuangstatic const CodecProfileLevel kVP9ProfileLevels[] = {
339486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang    { OMX_VIDEO_VP9Profile0, OMX_VIDEO_VP9Level5  },
349486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang};
359486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang
36bbba88cb1bdc34705d1477208990a06904c022e7Andreas HuberSoftVPX::SoftVPX(
37bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        const char *name,
3894705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        const char *componentRole,
3994705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        OMX_VIDEO_CODINGTYPE codingType,
40bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        const OMX_CALLBACKTYPE *callbacks,
41bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_PTR appData,
42bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_COMPONENTTYPE **component)
437f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar    : SoftVideoDecoderOMXComponent(
4494705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang            name, componentRole, codingType,
459486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang            codingType == OMX_VIDEO_CodingVP8 ? NULL : kVP9ProfileLevels,
469486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang            codingType == OMX_VIDEO_CodingVP8 ?  0 : NELEM(kVP9ProfileLevels),
477f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar            320 /* width */, 240 /* height */, callbacks, appData, component),
4894705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang      mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9),
49d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang      mEOSStatus(INPUT_DATA_AVAILABLE),
5050f939d655a5156157564cb91434f1cce424b2ddhkuang      mCtx(NULL),
51d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang      mFrameParallelMode(false),
52d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang      mTimeStampIdx(0),
5350f939d655a5156157564cb91434f1cce424b2ddhkuang      mImg(NULL) {
54a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar    // arbitrary from avc/hevc as vpx does not specify a min compression ratio
55a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar    const size_t kMinCompressionRatio = mMode == MODE_VP8 ? 2 : 4;
56a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar    const char *mime = mMode == MODE_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 : MEDIA_MIMETYPE_VIDEO_VP9;
57a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar    const size_t kMaxOutputBufferSize = 2048 * 2048 * 3 / 2;
58a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar    initPorts(
59a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar            kNumBuffers, kMaxOutputBufferSize / kMinCompressionRatio /* inputBufferSize */,
60a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar            kNumBuffers, mime, kMinCompressionRatio);
61bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    CHECK_EQ(initDecoder(), (status_t)OK);
62bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
63bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
64bbba88cb1bdc34705d1477208990a06904c022e7Andreas HuberSoftVPX::~SoftVPX() {
65d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    destroyDecoder();
66bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
67bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
68f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dongstatic int GetCPUCoreCount() {
69f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    int cpuCoreCount = 1;
70f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong#if defined(_SC_NPROCESSORS_ONLN)
71f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
72f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong#else
73f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    // _SC_NPROC_ONLN must be defined...
74f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
75f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong#endif
76f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    CHECK(cpuCoreCount >= 1);
773856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("Number of CPU cores: %d", cpuCoreCount);
78f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    return cpuCoreCount;
79f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong}
80f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong
81bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huberstatus_t SoftVPX::initDecoder() {
82bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    mCtx = new vpx_codec_ctx_t;
83bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    vpx_codec_err_t vpx_err;
84f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    vpx_codec_dec_cfg_t cfg;
85d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    vpx_codec_flags_t flags;
86f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
87d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    memset(&flags, 0, sizeof(vpx_codec_flags_t));
88f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    cfg.threads = GetCPUCoreCount();
89d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
90d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (mFrameParallelMode) {
91d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        flags |= VPX_CODEC_USE_FRAME_THREADING;
92d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
93d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
94bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    if ((vpx_err = vpx_codec_dec_init(
9594705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                (vpx_codec_ctx_t *)mCtx,
9694705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                 mMode == MODE_VP8 ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo,
97d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                 &cfg, flags))) {
9829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
99bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        return UNKNOWN_ERROR;
100bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    }
101bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
102bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    return OK;
103bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
104bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
105d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuangstatus_t SoftVPX::destroyDecoder() {
106d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
107d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    delete (vpx_codec_ctx_t *)mCtx;
108d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    mCtx = NULL;
109d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    return OK;
110d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang}
111d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
112d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuangbool SoftVPX::outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset) {
113d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    List<BufferInfo *> &outQueue = getPortQueue(1);
114d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    BufferInfo *outInfo = NULL;
115d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    OMX_BUFFERHEADERTYPE *outHeader = NULL;
116d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    vpx_codec_iter_t iter = NULL;
117d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
118d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (flushDecoder && mFrameParallelMode) {
119d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        // Flush decoder by passing NULL data ptr and 0 size.
120d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        // Ideally, this should never fail.
121d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (vpx_codec_decode((vpx_codec_ctx_t *)mCtx, NULL, 0, NULL, 0)) {
122d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            ALOGE("Failed to flush on2 decoder.");
123d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return false;
124d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
125d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
126d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
127d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (!display) {
128d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (!flushDecoder) {
129d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            ALOGE("Invalid operation.");
130d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return false;
131d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
132d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        // Drop all the decoded frames in decoder.
133d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        while ((mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter))) {
134d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
135d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        return true;
136d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
137d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
138d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    while (!outQueue.empty()) {
139d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (mImg == NULL) {
140d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
141d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            if (mImg == NULL) {
142d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                break;
143d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            }
144d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
145d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        uint32_t width = mImg->d_w;
146d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        uint32_t height = mImg->d_h;
147d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outInfo = *outQueue.begin();
148d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader = outInfo->mHeader;
149252e0d8ae9fae7711800dac01bd851a3ebc23135Johann        CHECK_EQ(mImg->fmt, VPX_IMG_FMT_I420);
150d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        handlePortSettingsChange(portWillReset, width, height);
151d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (*portWillReset) {
152d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return true;
153d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
154d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
155d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nOffset = 0;
156d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nFlags = 0;
1573ecc9db40b1fb9c7f807a5892e5c9625aac1fb06Marco Nelissen        outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
158d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nTimeStamp = *(OMX_TICKS *)mImg->user_priv;
159ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen        if (outHeader->nAllocLen >= outHeader->nFilledLen) {
160ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            uint8_t *dst = outHeader->pBuffer;
161ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            const uint8_t *srcY = (const uint8_t *)mImg->planes[VPX_PLANE_Y];
162ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            const uint8_t *srcU = (const uint8_t *)mImg->planes[VPX_PLANE_U];
163ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            const uint8_t *srcV = (const uint8_t *)mImg->planes[VPX_PLANE_V];
164ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            size_t srcYStride = mImg->stride[VPX_PLANE_Y];
165ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            size_t srcUStride = mImg->stride[VPX_PLANE_U];
166ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            size_t srcVStride = mImg->stride[VPX_PLANE_V];
167ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);
168ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen        } else {
169ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            ALOGE("b/27597103, buffer too small");
170ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            android_errorWriteLog(0x534e4554, "27597103");
171ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            outHeader->nFilledLen = 0;
172ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen        }
173d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
174d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        mImg = NULL;
175d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outInfo->mOwnedByUs = false;
176d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outQueue.erase(outQueue.begin());
177d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outInfo = NULL;
178d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        notifyFillBufferDone(outHeader);
179d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader = NULL;
180d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
181d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
182d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (!eos) {
183d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        return true;
184d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
185d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
186d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (!outQueue.empty()) {
187d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outInfo = *outQueue.begin();
188d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outQueue.erase(outQueue.begin());
189d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader = outInfo->mHeader;
190d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nTimeStamp = 0;
191d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nFilledLen = 0;
192d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nFlags = OMX_BUFFERFLAG_EOS;
193d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outInfo->mOwnedByUs = false;
194d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        notifyFillBufferDone(outHeader);
195d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        mEOSStatus = OUTPUT_FRAMES_FLUSHED;
196d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
197d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    return true;
198d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang}
199d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
20084333e0475bc911adc16417f4ca327c975cf6c36Andreas Hubervoid SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) {
201d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (mOutputPortSettingsChange != NONE || mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
202bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        return;
203bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    }
204bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
205bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    List<BufferInfo *> &inQueue = getPortQueue(0);
206bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    List<BufferInfo *> &outQueue = getPortQueue(1);
207a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar    bool EOSseen = false;
208d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    bool portWillReset = false;
209d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
210d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    while ((mEOSStatus == INPUT_EOS_SEEN || !inQueue.empty())
211d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            && !outQueue.empty()) {
212d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        // Output the pending frames that left from last port reset or decoder flush.
213d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (mEOSStatus == INPUT_EOS_SEEN || mImg != NULL) {
214d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            if (!outputBuffers(
215d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                     mEOSStatus == INPUT_EOS_SEEN, true /* display */,
216d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                     mEOSStatus == INPUT_EOS_SEEN, &portWillReset)) {
217d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                ALOGE("on2 decoder failed to output frame.");
218d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
219d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                return;
220d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            }
221d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            if (portWillReset || mEOSStatus == OUTPUT_FRAMES_FLUSHED ||
222d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                    mEOSStatus == INPUT_EOS_SEEN) {
223d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                return;
224d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            }
2257c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            // Continue as outQueue may be empty now.
2267c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            continue;
227d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
228bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
229bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        BufferInfo *inInfo = *inQueue.begin();
230bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
231d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian
232d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian        // Software VP9 Decoder does not need the Codec Specific Data (CSD)
233d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian        // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if
234d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian        // it was passed.
235d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian        if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
2365a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang            // Only ignore CSD buffer for VP9.
2375a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang            if (mMode == MODE_VP9) {
2385a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                inQueue.erase(inQueue.begin());
2395a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                inInfo->mOwnedByUs = false;
2405a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                notifyEmptyBufferDone(inHeader);
2415a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                continue;
2425a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang            } else {
2435a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                // Tolerate the CSD buffer for VP8. This is a workaround
2445a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                // for b/28689536.
2455a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                ALOGW("WARNING: Got CSD buffer for VP8.");
2465a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang            }
247d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian        }
248d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian
249d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        mTimeStamps[mTimeStampIdx] = inHeader->nTimeStamp;
250bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
251bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
252d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            mEOSStatus = INPUT_EOS_SEEN;
253a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar            EOSseen = true;
254bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        }
255bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
2567c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang        if (inHeader->nFilledLen > 0) {
2577c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            vpx_codec_err_t err = vpx_codec_decode(
2587c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                    (vpx_codec_ctx_t *)mCtx, inHeader->pBuffer + inHeader->nOffset,
2597c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                    inHeader->nFilledLen, &mTimeStamps[mTimeStampIdx], 0);
2607c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            if (err == VPX_CODEC_OK) {
2617c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                inInfo->mOwnedByUs = false;
2627c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                inQueue.erase(inQueue.begin());
2637c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                inInfo = NULL;
2647c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                notifyEmptyBufferDone(inHeader);
2657c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                inHeader = NULL;
2667c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            } else {
2675a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                ALOGE("on2 decoder failed to decode frame. err: %d", err);
2687c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
2697c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                return;
2707c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            }
271bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        }
2727c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang
273d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        mTimeStampIdx = (mTimeStampIdx + 1) % kNumBuffers;
274bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
275d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (!outputBuffers(
276d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                 EOSseen /* flushDecoder */, true /* display */, EOSseen, &portWillReset)) {
277d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            ALOGE("on2 decoder failed to output frame.");
278d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
279d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return;
280d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
281d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (portWillReset) {
282d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return;
283bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        }
284bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    }
285bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
286bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
287d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuangvoid SoftVPX::onPortFlushCompleted(OMX_U32 portIndex) {
288d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (portIndex == kInputPortIndex) {
289d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        bool portWillReset = false;
290d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (!outputBuffers(
291d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                 true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
292d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            ALOGE("Failed to flush decoder.");
293d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
294d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return;
295d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
296d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        mEOSStatus = INPUT_DATA_AVAILABLE;
297d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
298d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang}
299d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
300d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuangvoid SoftVPX::onReset() {
301d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    bool portWillReset = false;
302d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (!outputBuffers(
303d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang             true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
304d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        ALOGW("Failed to flush decoder. Try to hard reset decoder");
305d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        destroyDecoder();
306d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        initDecoder();
307d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
308d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    mEOSStatus = INPUT_DATA_AVAILABLE;
309d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang}
310d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
311bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}  // namespace android
312bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
313bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huberandroid::SoftOMXComponent *createSoftOMXComponent(
314bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        const char *name, const OMX_CALLBACKTYPE *callbacks,
315bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
31694705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    if (!strcmp(name, "OMX.google.vp8.decoder")) {
31794705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        return new android::SoftVPX(
31894705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                name, "video_decoder.vp8", OMX_VIDEO_CodingVP8,
31994705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                callbacks, appData, component);
32094705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    } else if (!strcmp(name, "OMX.google.vp9.decoder")) {
32194705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        return new android::SoftVPX(
32294705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                name, "video_decoder.vp9", OMX_VIDEO_CodingVP9,
32394705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                callbacks, appData, component);
32494705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    } else {
32594705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        CHECK(!"Unknown component");
32694705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    }
327dba83c1cb1bef03bc5d1760c2639d06ff71c0fa7Mark Salyzyn    return NULL;
328bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
329