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[] = {
332d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    { OMX_VIDEO_VP9Profile0, OMX_VIDEO_VP9Level5 },
342d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    { OMX_VIDEO_VP9Profile2, OMX_VIDEO_VP9Level5 },
352d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    { OMX_VIDEO_VP9Profile2HDR, OMX_VIDEO_VP9Level5 },
369486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang};
379486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang
38bbba88cb1bdc34705d1477208990a06904c022e7Andreas HuberSoftVPX::SoftVPX(
39bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        const char *name,
4094705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        const char *componentRole,
4194705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        OMX_VIDEO_CODINGTYPE codingType,
42bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        const OMX_CALLBACKTYPE *callbacks,
43bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_PTR appData,
44bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_COMPONENTTYPE **component)
457f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar    : SoftVideoDecoderOMXComponent(
4694705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang            name, componentRole, codingType,
479486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang            codingType == OMX_VIDEO_CodingVP8 ? NULL : kVP9ProfileLevels,
489486e0a16e9ad4d4f6bd5047a3cbb1b3f2008d65Hangyu Kuang            codingType == OMX_VIDEO_CodingVP8 ?  0 : NELEM(kVP9ProfileLevels),
497f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar            320 /* width */, 240 /* height */, callbacks, appData, component),
5094705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang      mMode(codingType == OMX_VIDEO_CodingVP8 ? MODE_VP8 : MODE_VP9),
51d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang      mEOSStatus(INPUT_DATA_AVAILABLE),
5250f939d655a5156157564cb91434f1cce424b2ddhkuang      mCtx(NULL),
53d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang      mFrameParallelMode(false),
54d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang      mTimeStampIdx(0),
5550f939d655a5156157564cb91434f1cce424b2ddhkuang      mImg(NULL) {
56a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar    // arbitrary from avc/hevc as vpx does not specify a min compression ratio
57a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar    const size_t kMinCompressionRatio = mMode == MODE_VP8 ? 2 : 4;
58a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar    const char *mime = mMode == MODE_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 : MEDIA_MIMETYPE_VIDEO_VP9;
59a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar    const size_t kMaxOutputBufferSize = 2048 * 2048 * 3 / 2;
60a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar    initPorts(
61a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar            kNumBuffers, kMaxOutputBufferSize / kMinCompressionRatio /* inputBufferSize */,
62a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar            kNumBuffers, mime, kMinCompressionRatio);
63bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    CHECK_EQ(initDecoder(), (status_t)OK);
64bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
65bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
66bbba88cb1bdc34705d1477208990a06904c022e7Andreas HuberSoftVPX::~SoftVPX() {
67d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    destroyDecoder();
68bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
69bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
70f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dongstatic int GetCPUCoreCount() {
71f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    int cpuCoreCount = 1;
72f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong#if defined(_SC_NPROCESSORS_ONLN)
73f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
74f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong#else
75f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    // _SC_NPROC_ONLN must be defined...
76f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
77f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong#endif
78f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    CHECK(cpuCoreCount >= 1);
793856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("Number of CPU cores: %d", cpuCoreCount);
80f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    return cpuCoreCount;
81f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong}
82f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong
832d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhangbool SoftVPX::supportDescribeHdrStaticInfo() {
842d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang    return true;
852d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang}
862d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang
87bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huberstatus_t SoftVPX::initDecoder() {
88bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    mCtx = new vpx_codec_ctx_t;
89bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    vpx_codec_err_t vpx_err;
90f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    vpx_codec_dec_cfg_t cfg;
91d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    vpx_codec_flags_t flags;
92f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
93d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    memset(&flags, 0, sizeof(vpx_codec_flags_t));
94f3ac3e3c94c14dbf1cdf6a4577f0b3aa8edfad06James Dong    cfg.threads = GetCPUCoreCount();
95d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
96d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (mFrameParallelMode) {
97d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        flags |= VPX_CODEC_USE_FRAME_THREADING;
98d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
99d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
100bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    if ((vpx_err = vpx_codec_dec_init(
10194705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                (vpx_codec_ctx_t *)mCtx,
10294705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                 mMode == MODE_VP8 ? &vpx_codec_vp8_dx_algo : &vpx_codec_vp9_dx_algo,
103d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                 &cfg, flags))) {
10429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
105bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        return UNKNOWN_ERROR;
106bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    }
107bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
108bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    return OK;
109bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
110bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
111d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuangstatus_t SoftVPX::destroyDecoder() {
112d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
113d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    delete (vpx_codec_ctx_t *)mCtx;
114d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    mCtx = NULL;
115d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    return OK;
116d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang}
117d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
118d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuangbool SoftVPX::outputBuffers(bool flushDecoder, bool display, bool eos, bool *portWillReset) {
119d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    List<BufferInfo *> &outQueue = getPortQueue(1);
120d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    BufferInfo *outInfo = NULL;
121d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    OMX_BUFFERHEADERTYPE *outHeader = NULL;
122d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    vpx_codec_iter_t iter = NULL;
123d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
124d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (flushDecoder && mFrameParallelMode) {
125d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        // Flush decoder by passing NULL data ptr and 0 size.
126d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        // Ideally, this should never fail.
127d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (vpx_codec_decode((vpx_codec_ctx_t *)mCtx, NULL, 0, NULL, 0)) {
128d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            ALOGE("Failed to flush on2 decoder.");
129d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return false;
130d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
131d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
132d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
133d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (!display) {
134d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (!flushDecoder) {
135d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            ALOGE("Invalid operation.");
136d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return false;
137d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
138d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        // Drop all the decoded frames in decoder.
139d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        while ((mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter))) {
140d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
141d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        return true;
142d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
143d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
144d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    while (!outQueue.empty()) {
145d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (mImg == NULL) {
146d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            mImg = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
147d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            if (mImg == NULL) {
148d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                break;
149d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            }
150d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
151d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        uint32_t width = mImg->d_w;
152d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        uint32_t height = mImg->d_h;
153d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outInfo = *outQueue.begin();
154d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader = outInfo->mHeader;
1552d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        CHECK(mImg->fmt == VPX_IMG_FMT_I420 || mImg->fmt == VPX_IMG_FMT_I42016);
1562d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        OMX_COLOR_FORMATTYPE outputColorFormat = OMX_COLOR_FormatYUV420Planar;
1572d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        int32_t bpp = 1;
1582d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        if (mImg->fmt == VPX_IMG_FMT_I42016) {
1592d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            outputColorFormat = OMX_COLOR_FormatYUV420Planar16;
1602d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang            bpp = 2;
1612d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        }
1622d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        handlePortSettingsChange(portWillReset, width, height, outputColorFormat);
163d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (*portWillReset) {
164d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return true;
165d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
166d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
167d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nOffset = 0;
168d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nFlags = 0;
1692d2a2967ce29281816b9ddb9434b3c0084e4ce52Chong Zhang        outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * bpp * 3) / 2;
170d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nTimeStamp = *(OMX_TICKS *)mImg->user_priv;
1717cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih        if (outputBufferSafe(outHeader)) {
172ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            uint8_t *dst = outHeader->pBuffer;
173ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            const uint8_t *srcY = (const uint8_t *)mImg->planes[VPX_PLANE_Y];
174ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            const uint8_t *srcU = (const uint8_t *)mImg->planes[VPX_PLANE_U];
175ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            const uint8_t *srcV = (const uint8_t *)mImg->planes[VPX_PLANE_V];
176ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            size_t srcYStride = mImg->stride[VPX_PLANE_Y];
177ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            size_t srcUStride = mImg->stride[VPX_PLANE_U];
178ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            size_t srcVStride = mImg->stride[VPX_PLANE_V];
179ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);
180ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen        } else {
181ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen            outHeader->nFilledLen = 0;
182ca00182c94d2ec1bdc9baeb1385e0cf3de9171d1Marco Nelissen        }
183d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
184d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        mImg = NULL;
185d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outInfo->mOwnedByUs = false;
186d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outQueue.erase(outQueue.begin());
187d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outInfo = NULL;
188d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        notifyFillBufferDone(outHeader);
189d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader = NULL;
190d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
191d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
192d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (!eos) {
193d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        return true;
194d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
195d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
196d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (!outQueue.empty()) {
197d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outInfo = *outQueue.begin();
198d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outQueue.erase(outQueue.begin());
199d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader = outInfo->mHeader;
200d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nTimeStamp = 0;
201d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nFilledLen = 0;
202d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outHeader->nFlags = OMX_BUFFERFLAG_EOS;
203d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        outInfo->mOwnedByUs = false;
204d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        notifyFillBufferDone(outHeader);
205d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        mEOSStatus = OUTPUT_FRAMES_FLUSHED;
206d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
207d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    return true;
208d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang}
209d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
2107cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shihbool SoftVPX::outputBufferSafe(OMX_BUFFERHEADERTYPE *outHeader) {
2117cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih    uint32_t width = outputBufferWidth();
2127cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih    uint32_t height = outputBufferHeight();
2137cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih    uint64_t nFilledLen = width;
2147cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih    nFilledLen *= height;
2157cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih    if (nFilledLen > UINT32_MAX / 3) {
216a2c2d1503ccc47b508f726652c714863320cb89bLajos Molnar        ALOGE("b/29421675, nFilledLen overflow %llu w %u h %u",
217a2c2d1503ccc47b508f726652c714863320cb89bLajos Molnar                (unsigned long long)nFilledLen, width, height);
2187cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih        android_errorWriteLog(0x534e4554, "29421675");
2197cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih        return false;
2207cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih    } else if (outHeader->nAllocLen < outHeader->nFilledLen) {
2217cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih        ALOGE("b/27597103, buffer too small");
2227cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih        android_errorWriteLog(0x534e4554, "27597103");
2237cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih        return false;
2247cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih    }
2257cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih
2267cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih    return true;
2277cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih}
2287cfc18e680fc295d1975c8da183f0d9df4cab803Robert Shih
22984333e0475bc911adc16417f4ca327c975cf6c36Andreas Hubervoid SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) {
230d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (mOutputPortSettingsChange != NONE || mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
231bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        return;
232bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    }
233bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
234bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    List<BufferInfo *> &inQueue = getPortQueue(0);
235bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    List<BufferInfo *> &outQueue = getPortQueue(1);
236a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar    bool EOSseen = false;
237d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    bool portWillReset = false;
238d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
239d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    while ((mEOSStatus == INPUT_EOS_SEEN || !inQueue.empty())
240d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            && !outQueue.empty()) {
241d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        // Output the pending frames that left from last port reset or decoder flush.
242d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (mEOSStatus == INPUT_EOS_SEEN || mImg != NULL) {
243d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            if (!outputBuffers(
244d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                     mEOSStatus == INPUT_EOS_SEEN, true /* display */,
245d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                     mEOSStatus == INPUT_EOS_SEEN, &portWillReset)) {
246d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                ALOGE("on2 decoder failed to output frame.");
247d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
248d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                return;
249d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            }
250d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            if (portWillReset || mEOSStatus == OUTPUT_FRAMES_FLUSHED ||
251d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                    mEOSStatus == INPUT_EOS_SEEN) {
252d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                return;
253d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            }
2547c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            // Continue as outQueue may be empty now.
2557c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            continue;
256d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
257bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
258bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        BufferInfo *inInfo = *inQueue.begin();
259bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
260d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian
261d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian        // Software VP9 Decoder does not need the Codec Specific Data (CSD)
262d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian        // (specified in http://www.webmproject.org/vp9/profiles/). Ignore it if
263d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian        // it was passed.
264d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian        if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
2655a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang            // Only ignore CSD buffer for VP9.
2665a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang            if (mMode == MODE_VP9) {
2675a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                inQueue.erase(inQueue.begin());
2685a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                inInfo->mOwnedByUs = false;
2695a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                notifyEmptyBufferDone(inHeader);
2705a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                continue;
2715a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang            } else {
2725a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                // Tolerate the CSD buffer for VP8. This is a workaround
2735a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                // for b/28689536.
2745a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                ALOGW("WARNING: Got CSD buffer for VP8.");
2755a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang            }
276d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian        }
277d0d32c0d39b56d7e85fcaa61f3245ac7bbb1f9ebVignesh Venkatasubramanian
278d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        mTimeStamps[mTimeStampIdx] = inHeader->nTimeStamp;
279bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
280bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
281d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            mEOSStatus = INPUT_EOS_SEEN;
282a02eae5e911f3bdc3f84f39c0ef223261b646128Lajos Molnar            EOSseen = true;
283bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        }
284bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
2857c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang        if (inHeader->nFilledLen > 0) {
2867c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            vpx_codec_err_t err = vpx_codec_decode(
2877c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                    (vpx_codec_ctx_t *)mCtx, inHeader->pBuffer + inHeader->nOffset,
2887c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                    inHeader->nFilledLen, &mTimeStamps[mTimeStampIdx], 0);
2897c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            if (err == VPX_CODEC_OK) {
2907c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                inInfo->mOwnedByUs = false;
2917c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                inQueue.erase(inQueue.begin());
2927c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                inInfo = NULL;
2937c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                notifyEmptyBufferDone(inHeader);
2947c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                inHeader = NULL;
2957c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            } else {
2965a25d9382cc96f56c6f178c11313eb26ad7000ccHangyu Kuang                ALOGE("on2 decoder failed to decode frame. err: %d", err);
2977c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
2987c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang                return;
2997c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang            }
300bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        }
3017c98ddc18d699660bf89df598fb2c13870e85aaeHangyu Kuang
302d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        mTimeStampIdx = (mTimeStampIdx + 1) % kNumBuffers;
303bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
304d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (!outputBuffers(
305d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                 EOSseen /* flushDecoder */, true /* display */, EOSseen, &portWillReset)) {
306d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            ALOGE("on2 decoder failed to output frame.");
307d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
308d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return;
309d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
310d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (portWillReset) {
311d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return;
312bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        }
313bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber    }
314bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
315bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
316d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuangvoid SoftVPX::onPortFlushCompleted(OMX_U32 portIndex) {
317d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (portIndex == kInputPortIndex) {
318d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        bool portWillReset = false;
319d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        if (!outputBuffers(
320d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang                 true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
321d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            ALOGE("Failed to flush decoder.");
322d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
323d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang            return;
324d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        }
325d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        mEOSStatus = INPUT_DATA_AVAILABLE;
326d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
327d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang}
328d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
329d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuangvoid SoftVPX::onReset() {
330d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    bool portWillReset = false;
331d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    if (!outputBuffers(
332d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang             true /* flushDecoder */, false /* display */, false /* eos */, &portWillReset)) {
333d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        ALOGW("Failed to flush decoder. Try to hard reset decoder");
334d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        destroyDecoder();
335d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang        initDecoder();
336d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    }
337d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang    mEOSStatus = INPUT_DATA_AVAILABLE;
338d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang}
339d42b90c5183fbd9d6a28d9baee613fddbf8131d6hkuang
340bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}  // namespace android
341bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber
342bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huberandroid::SoftOMXComponent *createSoftOMXComponent(
343bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        const char *name, const OMX_CALLBACKTYPE *callbacks,
344bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
34594705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    if (!strcmp(name, "OMX.google.vp8.decoder")) {
34694705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        return new android::SoftVPX(
34794705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                name, "video_decoder.vp8", OMX_VIDEO_CodingVP8,
34894705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                callbacks, appData, component);
34994705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    } else if (!strcmp(name, "OMX.google.vp9.decoder")) {
35094705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        return new android::SoftVPX(
35194705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                name, "video_decoder.vp9", OMX_VIDEO_CodingVP9,
35294705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang                callbacks, appData, component);
35394705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    } else {
35494705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang        CHECK(!"Unknown component");
35594705aff3c9eef58cbb72ec6fe5d2dcfd9481646hkuang    }
356dba83c1cb1bef03bc5d1760c2639d06ff71c0fa7Mark Salyzyn    return NULL;
357bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber}
358