SoftAVC.cpp revision d94e716af0e49d775f0c0c4f36dd2c136ba5f2b2
15bc087c573c70c84c6a39946457590b42d392a33Andreas Huber/*
25bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Copyright (C) 2011 The Android Open Source Project
35bc087c573c70c84c6a39946457590b42d392a33Andreas Huber *
45bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
55bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * you may not use this file except in compliance with the License.
65bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * You may obtain a copy of the License at
75bc087c573c70c84c6a39946457590b42d392a33Andreas Huber *
85bc087c573c70c84c6a39946457590b42d392a33Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
95bc087c573c70c84c6a39946457590b42d392a33Andreas Huber *
105bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * Unless required by applicable law or agreed to in writing, software
115bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
125bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * See the License for the specific language governing permissions and
145bc087c573c70c84c6a39946457590b42d392a33Andreas Huber * limitations under the License.
155bc087c573c70c84c6a39946457590b42d392a33Andreas Huber */
165bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
175bc087c573c70c84c6a39946457590b42d392a33Andreas Huber//#define LOG_NDEBUG 0
185bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#define LOG_TAG "SoftAVC"
195bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <utils/Log.h>
205bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
215bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include "SoftAVC.h"
225bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
235bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <media/stagefright/foundation/ADebug.h>
245bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <media/stagefright/MediaDefs.h>
255bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <media/stagefright/MediaErrors.h>
265bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include <media/IOMX.h>
275bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
285bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
295bc087c573c70c84c6a39946457590b42d392a33Andreas Hubernamespace android {
305bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
315bc087c573c70c84c6a39946457590b42d392a33Andreas Huberstatic const CodecProfileLevel kProfileLevels[] = {
32093024bfa271988655327e0fb761b581afa8bc11Robert Shih    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1  },
335bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
345bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
355bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
368cf4ced8d25e9b1b56b69b544339acc1550e4038osamu fujita    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 },
378cf4ced8d25e9b1b56b69b544339acc1550e4038osamu fujita    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2  },
38b5f25f005bc1d3ae35f45b58c88345e183dc336dAndreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 },
39b5f25f005bc1d3ae35f45b58c88345e183dc336dAndreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 },
40b5f25f005bc1d3ae35f45b58c88345e183dc336dAndreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3  },
41b5f25f005bc1d3ae35f45b58c88345e183dc336dAndreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 },
42b5f25f005bc1d3ae35f45b58c88345e183dc336dAndreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 },
43180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4  },
44180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 },
455bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42 },
465bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel5  },
475bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel51 },
48180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang};
49180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
50180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhangtemplate<class T>
51180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhangstatic void InitOMXParams(T *params) {
525bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    params->nSize = sizeof(T);
535bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    params->nVersion.s.nVersionMajor = 1;
549575c96b6e418914e2ffc6741ecc8d71e3968dbeAndreas Huber    params->nVersion.s.nVersionMinor = 0;
55180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    params->nVersion.s.nRevision = 0;
56180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    params->nVersion.s.nStep = 0;
57180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang}
58180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
59180d1b96ee2312f1056a58e26884a89d25ab62c8Chong ZhangSoftAVC::SoftAVC(
60180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        const char *name,
61180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        const OMX_CALLBACKTYPE *callbacks,
62180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        OMX_PTR appData,
63ced1c2f8f6c422063092f5cc5c675ccdebb2dc10Chong Zhang        OMX_COMPONENTTYPE **component)
649575c96b6e418914e2ffc6741ecc8d71e3968dbeAndreas Huber    : SimpleSoftOMXComponent(name, callbacks, appData, component),
659575c96b6e418914e2ffc6741ecc8d71e3968dbeAndreas Huber      mHandle(NULL),
669575c96b6e418914e2ffc6741ecc8d71e3968dbeAndreas Huber      mInputBufferCount(0),
679575c96b6e418914e2ffc6741ecc8d71e3968dbeAndreas Huber      mWidth(320),
685bc087c573c70c84c6a39946457590b42d392a33Andreas Huber      mHeight(240),
691d15ab58bf8239069ef343de6cb21aabf3ef7d78Lajos Molnar      mPictureSize(mWidth * mHeight * 3 / 2),
7087f2a558dd12043631e12c361abef301bf603140Andreas Huber      mCropLeft(0),
7187f2a558dd12043631e12c361abef301bf603140Andreas Huber      mCropTop(0),
7287f2a558dd12043631e12c361abef301bf603140Andreas Huber      mCropWidth(mWidth),
7387f2a558dd12043631e12c361abef301bf603140Andreas Huber      mCropHeight(mHeight),
7487f2a558dd12043631e12c361abef301bf603140Andreas Huber      mFirstPicture(NULL),
7587f2a558dd12043631e12c361abef301bf603140Andreas Huber      mFirstPictureId(-1),
7687f2a558dd12043631e12c361abef301bf603140Andreas Huber      mPicId(0),
7787f2a558dd12043631e12c361abef301bf603140Andreas Huber      mHeadersDecoded(false),
7887f2a558dd12043631e12c361abef301bf603140Andreas Huber      mEOSStatus(INPUT_DATA_AVAILABLE),
795bc087c573c70c84c6a39946457590b42d392a33Andreas Huber      mOutputPortSettingsChange(NONE),
805bc087c573c70c84c6a39946457590b42d392a33Andreas Huber      mSignalledError(false) {
81180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    initPorts();
82180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    CHECK_EQ(initDecoder(), (status_t)OK);
835bc087c573c70c84c6a39946457590b42d392a33Andreas Huber}
845bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
85eac68baf095aeef54865c28b6888924dc6295cbdAndreas HuberSoftAVC::~SoftAVC() {
86180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    H264SwDecRelease(mHandle);
87180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    mHandle = NULL;
885bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
89180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    while (mPicToHeaderMap.size() != 0) {
908cf4ced8d25e9b1b56b69b544339acc1550e4038osamu fujita        OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.editValueAt(0);
915bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        mPicToHeaderMap.removeItemsAt(0);
9232f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        delete header;
9332f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber        header = NULL;
945bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    }
955bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
96df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
975bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    CHECK(outQueue.empty());
98180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    CHECK(inQueue.empty());
995bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
1005bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    delete[] mFirstPicture;
101fef808d42a9c94b0b5ef3c3d5fb0a090edbc42daWei Jia}
10242e549e4ab54802d788c43e3a04a85b7a1a95e97Andreas Huber
103bfcc8d8ab7c56bc013bd221a29e1ecf3a6390813Andreas Hubervoid SoftAVC::initPorts() {
10442e549e4ab54802d788c43e3a04a85b7a1a95e97Andreas Huber    OMX_PARAM_PORTDEFINITIONTYPE def;
10542e549e4ab54802d788c43e3a04a85b7a1a95e97Andreas Huber    InitOMXParams(&def);
106bfcc8d8ab7c56bc013bd221a29e1ecf3a6390813Andreas Huber
107bfcc8d8ab7c56bc013bd221a29e1ecf3a6390813Andreas Huber    def.nPortIndex = kInputPortIndex;
10829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block    def.eDir = OMX_DirInput;
109180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    def.nBufferCountMin = kNumInputBuffers;
110180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    def.nBufferCountActual = def.nBufferCountMin;
111bfcc8d8ab7c56bc013bd221a29e1ecf3a6390813Andreas Huber    def.nBufferSize = 8192;
112bfcc8d8ab7c56bc013bd221a29e1ecf3a6390813Andreas Huber    def.bEnabled = OMX_TRUE;
113bfcc8d8ab7c56bc013bd221a29e1ecf3a6390813Andreas Huber    def.bPopulated = OMX_FALSE;
11442e549e4ab54802d788c43e3a04a85b7a1a95e97Andreas Huber    def.eDomain = OMX_PortDomainVideo;
11542e549e4ab54802d788c43e3a04a85b7a1a95e97Andreas Huber    def.bBuffersContiguous = OMX_FALSE;
116bfcc8d8ab7c56bc013bd221a29e1ecf3a6390813Andreas Huber    def.nBufferAlignment = 1;
117bfcc8d8ab7c56bc013bd221a29e1ecf3a6390813Andreas Huber
1185bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC);
1195bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    def.format.video.pNativeRender = NULL;
1205bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    def.format.video.nFrameWidth = mWidth;
1215bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    def.format.video.nFrameHeight = mHeight;
1225bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    def.format.video.nStride = def.format.video.nFrameWidth;
123b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
124b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.format.video.nBitrate = 0;
125b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.format.video.xFramerate = 0;
126b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.format.video.bFlagErrorConcealment = OMX_FALSE;
127b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
128b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
129b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.format.video.pNativeWindow = NULL;
130b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber
131b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    addPort(def);
132b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber
133b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.nPortIndex = kOutputPortIndex;
134b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.eDir = OMX_DirOutput;
135b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.nBufferCountMin = kNumOutputBuffers;
136b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.nBufferCountActual = def.nBufferCountMin;
1375bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    def.bEnabled = OMX_TRUE;
138b7c8e91880463ff4981e3e53e98e45d68e2fe374Andreas Huber    def.bPopulated = OMX_FALSE;
139fef808d42a9c94b0b5ef3c3d5fb0a090edbc42daWei Jia    def.eDomain = OMX_PortDomainVideo;
14032f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber    def.bBuffersContiguous = OMX_FALSE;
14132f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber    def.nBufferAlignment = 2;
1425bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
14306528d7f18ad01377357d337eaa3e875a242bd2dAndreas Huber    def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
14406528d7f18ad01377357d337eaa3e875a242bd2dAndreas Huber    def.format.video.pNativeRender = NULL;
14506528d7f18ad01377357d337eaa3e875a242bd2dAndreas Huber    def.format.video.nFrameWidth = mWidth;
14629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block    def.format.video.nFrameHeight = mHeight;
14706528d7f18ad01377357d337eaa3e875a242bd2dAndreas Huber    def.format.video.nStride = def.format.video.nFrameWidth;
14806528d7f18ad01377357d337eaa3e875a242bd2dAndreas Huber    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
149180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    def.format.video.nBitrate = 0;
15006528d7f18ad01377357d337eaa3e875a242bd2dAndreas Huber    def.format.video.xFramerate = 0;
15106528d7f18ad01377357d337eaa3e875a242bd2dAndreas Huber    def.format.video.bFlagErrorConcealment = OMX_FALSE;
1525bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
1535bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
1545bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    def.format.video.pNativeWindow = NULL;
155180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
156180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    def.nBufferSize =
157180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
158180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
159180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    addPort(def);
160180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang}
161180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
162180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhangstatus_t SoftAVC::initDecoder() {
163180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    // Force decoder to output buffers in display order.
164180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    if (H264SwDecInit(&mHandle, 0) == H264SWDEC_OK) {
165180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        return OK;
166180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    }
167180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    return UNKNOWN_ERROR;
1685bc087c573c70c84c6a39946457590b42d392a33Andreas Huber}
1691d15ab58bf8239069ef343de6cb21aabf3ef7d78Lajos Molnar
170eac68baf095aeef54865c28b6888924dc6295cbdAndreas HuberOMX_ERRORTYPE SoftAVC::internalGetParameter(
1715bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        OMX_INDEXTYPE index, OMX_PTR params) {
1725bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    switch (index) {
173180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        case OMX_IndexParamVideoPortFormat:
174180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        {
175180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
176180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
177180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
178180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            if (formatParams->nPortIndex > kOutputPortIndex) {
179180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                return OMX_ErrorUndefined;
180180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            }
181180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
182180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            if (formatParams->nIndex != 0) {
183180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                return OMX_ErrorNoMore;
184180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            }
185180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
186180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            if (formatParams->nPortIndex == kInputPortIndex) {
187180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
188180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
189180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                formatParams->xFramerate = 0;
190180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            } else {
191180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                CHECK(formatParams->nPortIndex == kOutputPortIndex);
192180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
193180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
194180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
195180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                formatParams->xFramerate = 0;
196180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            }
197180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
198180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            return OMX_ErrorNone;
199180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        }
200180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
201180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        case OMX_IndexParamVideoProfileLevelQuerySupported:
202180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        {
203180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
204180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                    (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
205180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
206180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            if (profileLevel->nPortIndex != kInputPortIndex) {
207180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                ALOGE("Invalid port index: %ld", profileLevel->nPortIndex);
208180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                return OMX_ErrorUnsupportedIndex;
209180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            }
210180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
211ab05b4ccb8ea59079d7f773aa0e090029c479badWei Jia            size_t index = profileLevel->nProfileIndex;
212ab05b4ccb8ea59079d7f773aa0e090029c479badWei Jia            size_t nProfileLevels =
213ab05b4ccb8ea59079d7f773aa0e090029c479badWei Jia                    sizeof(kProfileLevels) / sizeof(kProfileLevels[0]);
214ab05b4ccb8ea59079d7f773aa0e090029c479badWei Jia            if (index >= nProfileLevels) {
215180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                return OMX_ErrorNoMore;
216180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            }
2175bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
218180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            profileLevel->eProfile = kProfileLevels[index].mProfile;
219180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            profileLevel->eLevel = kProfileLevels[index].mLevel;
220180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            return OMX_ErrorNone;
221093024bfa271988655327e0fb761b581afa8bc11Robert Shih        }
222180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
2235bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        default:
224093024bfa271988655327e0fb761b581afa8bc11Robert Shih            return SimpleSoftOMXComponent::internalGetParameter(index, params);
2255bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    }
226093024bfa271988655327e0fb761b581afa8bc11Robert Shih}
227093024bfa271988655327e0fb761b581afa8bc11Robert Shih
2285bc087c573c70c84c6a39946457590b42d392a33Andreas HuberOMX_ERRORTYPE SoftAVC::internalSetParameter(
2295bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        OMX_INDEXTYPE index, const OMX_PTR params) {
230093024bfa271988655327e0fb761b581afa8bc11Robert Shih    switch (index) {
231093024bfa271988655327e0fb761b581afa8bc11Robert Shih        case OMX_IndexParamStandardComponentRole:
232093024bfa271988655327e0fb761b581afa8bc11Robert Shih        {
233093024bfa271988655327e0fb761b581afa8bc11Robert Shih            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
234093024bfa271988655327e0fb761b581afa8bc11Robert Shih                (const OMX_PARAM_COMPONENTROLETYPE *)params;
235093024bfa271988655327e0fb761b581afa8bc11Robert Shih
2365bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            if (strncmp((const char *)roleParams->cRole,
2375bc087c573c70c84c6a39946457590b42d392a33Andreas Huber                        "video_decoder.avc",
2385bc087c573c70c84c6a39946457590b42d392a33Andreas Huber                        OMX_MAX_STRINGNAME_SIZE - 1)) {
2395bc087c573c70c84c6a39946457590b42d392a33Andreas Huber                return OMX_ErrorUndefined;
240180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            }
2415bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
2425bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            return OMX_ErrorNone;
2435bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        }
2445bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
2455bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        case OMX_IndexParamVideoPortFormat:
246180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        {
247180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
248180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
249180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
2505bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            if (formatParams->nPortIndex > kOutputPortIndex) {
2515bc087c573c70c84c6a39946457590b42d392a33Andreas Huber                return OMX_ErrorUndefined;
2525bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            }
2535bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
2545bc087c573c70c84c6a39946457590b42d392a33Andreas Huber            if (formatParams->nIndex != 0) {
25587f2a558dd12043631e12c361abef301bf603140Andreas Huber                return OMX_ErrorNoMore;
25687f2a558dd12043631e12c361abef301bf603140Andreas Huber            }
25787f2a558dd12043631e12c361abef301bf603140Andreas Huber
25887f2a558dd12043631e12c361abef301bf603140Andreas Huber            return OMX_ErrorNone;
25987f2a558dd12043631e12c361abef301bf603140Andreas Huber        }
26087f2a558dd12043631e12c361abef301bf603140Andreas Huber
26187f2a558dd12043631e12c361abef301bf603140Andreas Huber        default:
26287f2a558dd12043631e12c361abef301bf603140Andreas Huber            return SimpleSoftOMXComponent::internalSetParameter(index, params);
26387f2a558dd12043631e12c361abef301bf603140Andreas Huber    }
26487f2a558dd12043631e12c361abef301bf603140Andreas Huber}
26587f2a558dd12043631e12c361abef301bf603140Andreas Huber
2665bc087c573c70c84c6a39946457590b42d392a33Andreas HuberOMX_ERRORTYPE SoftAVC::getConfig(
2675bc087c573c70c84c6a39946457590b42d392a33Andreas Huber        OMX_INDEXTYPE index, OMX_PTR params) {
268d5e56231a598b180a1d898bb7dc61b75580e59a4Andreas Huber    switch (index) {
269d5e56231a598b180a1d898bb7dc61b75580e59a4Andreas Huber        case OMX_IndexConfigCommonOutputCrop:
270d5e56231a598b180a1d898bb7dc61b75580e59a4Andreas Huber        {
271d5e56231a598b180a1d898bb7dc61b75580e59a4Andreas Huber            OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
272180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
273180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            if (rectParams->nPortIndex != 1) {
274180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang                return OMX_ErrorUndefined;
275180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            }
276180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
277180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            rectParams->nLeft = mCropLeft;
278180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            rectParams->nTop = mCropTop;
279180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            rectParams->nWidth = mCropWidth;
280180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            rectParams->nHeight = mCropHeight;
281180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
282180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            return OMX_ErrorNone;
283180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        }
284180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
285180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        default:
286180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang            return OMX_ErrorUnsupportedIndex;
287180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    }
288180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang}
289180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang
290180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhangvoid SoftAVC::onQueueFilled(OMX_U32 portIndex) {
291180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang    if (mSignalledError || mOutputPortSettingsChange != NONE) {
292180d1b96ee2312f1056a58e26884a89d25ab62c8Chong Zhang        return;
2935bc087c573c70c84c6a39946457590b42d392a33Andreas Huber    }
2945bc087c573c70c84c6a39946457590b42d392a33Andreas Huber
295    if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
296        return;
297    }
298
299    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
300    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
301    H264SwDecRet ret = H264SWDEC_PIC_RDY;
302    bool portSettingsChanged = false;
303    while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty())
304            && outQueue.size() == kNumOutputBuffers) {
305
306        if (mEOSStatus == INPUT_EOS_SEEN) {
307            drainAllOutputBuffers();
308            return;
309        }
310
311        BufferInfo *inInfo = *inQueue.begin();
312        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
313        ++mPicId;
314
315        OMX_BUFFERHEADERTYPE *header = new OMX_BUFFERHEADERTYPE;
316        memset(header, 0, sizeof(OMX_BUFFERHEADERTYPE));
317        header->nTimeStamp = inHeader->nTimeStamp;
318        header->nFlags = inHeader->nFlags;
319        if (header->nFlags & OMX_BUFFERFLAG_EOS) {
320            mEOSStatus = INPUT_EOS_SEEN;
321        }
322        mPicToHeaderMap.add(mPicId, header);
323        inQueue.erase(inQueue.begin());
324
325        H264SwDecInput inPicture;
326        H264SwDecOutput outPicture;
327        memset(&inPicture, 0, sizeof(inPicture));
328        inPicture.dataLen = inHeader->nFilledLen;
329        inPicture.pStream = inHeader->pBuffer + inHeader->nOffset;
330        inPicture.picId = mPicId;
331        inPicture.intraConcealmentMethod = 1;
332        H264SwDecPicture decodedPicture;
333
334        while (inPicture.dataLen > 0) {
335            ret = H264SwDecDecode(mHandle, &inPicture, &outPicture);
336            if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY ||
337                ret == H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY) {
338                inPicture.dataLen -= (u32)(outPicture.pStrmCurrPos - inPicture.pStream);
339                inPicture.pStream = outPicture.pStrmCurrPos;
340                if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY) {
341                    mHeadersDecoded = true;
342                    H264SwDecInfo decoderInfo;
343                    CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK);
344
345                    if (handlePortSettingChangeEvent(&decoderInfo)) {
346                        portSettingsChanged = true;
347                    }
348
349                    if (decoderInfo.croppingFlag &&
350                        handleCropRectEvent(&decoderInfo.cropParams)) {
351                        portSettingsChanged = true;
352                    }
353                }
354            } else {
355                if (portSettingsChanged) {
356                    if (H264SwDecNextPicture(mHandle, &decodedPicture, 0)
357                        == H264SWDEC_PIC_RDY) {
358
359                        // Save this output buffer; otherwise, it will be
360                        // lost during dynamic port reconfiguration because
361                        // OpenMAX client will delete _all_ output buffers
362                        // in the process.
363                        saveFirstOutputBuffer(
364                            decodedPicture.picId,
365                            (uint8_t *)decodedPicture.pOutputPicture);
366                    }
367                }
368                inPicture.dataLen = 0;
369                if (ret < 0) {
370                    ALOGE("Decoder failed: %d", ret);
371
372                    notify(OMX_EventError, OMX_ErrorUndefined,
373                           ERROR_MALFORMED, NULL);
374
375                    mSignalledError = true;
376                    return;
377                }
378            }
379        }
380        inInfo->mOwnedByUs = false;
381        notifyEmptyBufferDone(inHeader);
382
383        if (portSettingsChanged) {
384            portSettingsChanged = false;
385            return;
386        }
387
388        if (mFirstPicture && !outQueue.empty()) {
389            drainOneOutputBuffer(mFirstPictureId, mFirstPicture);
390            delete[] mFirstPicture;
391            mFirstPicture = NULL;
392            mFirstPictureId = -1;
393        }
394
395        while (!outQueue.empty() &&
396                mHeadersDecoded &&
397                H264SwDecNextPicture(mHandle, &decodedPicture, 0)
398                    == H264SWDEC_PIC_RDY) {
399
400            int32_t picId = decodedPicture.picId;
401            uint8_t *data = (uint8_t *) decodedPicture.pOutputPicture;
402            drainOneOutputBuffer(picId, data);
403        }
404    }
405}
406
407bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) {
408    if (mWidth != info->picWidth || mHeight != info->picHeight) {
409        mWidth  = info->picWidth;
410        mHeight = info->picHeight;
411        mPictureSize = mWidth * mHeight * 3 / 2;
412        mCropWidth = mWidth;
413        mCropHeight = mHeight;
414        updatePortDefinitions();
415        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
416        mOutputPortSettingsChange = AWAITING_DISABLED;
417        return true;
418    }
419
420    return false;
421}
422
423bool SoftAVC::handleCropRectEvent(const CropParams *crop) {
424    if (mCropLeft != crop->cropLeftOffset ||
425        mCropTop != crop->cropTopOffset ||
426        mCropWidth != crop->cropOutWidth ||
427        mCropHeight != crop->cropOutHeight) {
428        mCropLeft = crop->cropLeftOffset;
429        mCropTop = crop->cropTopOffset;
430        mCropWidth = crop->cropOutWidth;
431        mCropHeight = crop->cropOutHeight;
432
433        notify(OMX_EventPortSettingsChanged, 1,
434                OMX_IndexConfigCommonOutputCrop, NULL);
435
436        return true;
437    }
438    return false;
439}
440
441void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) {
442    CHECK(mFirstPicture == NULL);
443    mFirstPictureId = picId;
444
445    mFirstPicture = new uint8_t[mPictureSize];
446    memcpy(mFirstPicture, data, mPictureSize);
447}
448
449void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) {
450    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
451    BufferInfo *outInfo = *outQueue.begin();
452    outQueue.erase(outQueue.begin());
453    OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
454    OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId);
455    outHeader->nTimeStamp = header->nTimeStamp;
456    outHeader->nFlags = header->nFlags;
457    outHeader->nFilledLen = mPictureSize;
458    memcpy(outHeader->pBuffer + outHeader->nOffset,
459            data, mPictureSize);
460    mPicToHeaderMap.removeItem(picId);
461    delete header;
462    outInfo->mOwnedByUs = false;
463    notifyFillBufferDone(outHeader);
464}
465
466bool SoftAVC::drainAllOutputBuffers() {
467    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
468    H264SwDecPicture decodedPicture;
469
470    while (!outQueue.empty()) {
471        BufferInfo *outInfo = *outQueue.begin();
472        outQueue.erase(outQueue.begin());
473        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
474        if (mHeadersDecoded &&
475            H264SWDEC_PIC_RDY ==
476                H264SwDecNextPicture(mHandle, &decodedPicture, 1 /* flush */)) {
477
478            int32_t picId = decodedPicture.picId;
479            CHECK(mPicToHeaderMap.indexOfKey(picId) >= 0);
480
481            memcpy(outHeader->pBuffer + outHeader->nOffset,
482                decodedPicture.pOutputPicture,
483                mPictureSize);
484
485            OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId);
486            outHeader->nTimeStamp = header->nTimeStamp;
487            outHeader->nFlags = header->nFlags;
488            outHeader->nFilledLen = mPictureSize;
489            mPicToHeaderMap.removeItem(picId);
490            delete header;
491        } else {
492            outHeader->nTimeStamp = 0;
493            outHeader->nFilledLen = 0;
494            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
495            mEOSStatus = OUTPUT_FRAMES_FLUSHED;
496        }
497
498        outInfo->mOwnedByUs = false;
499        notifyFillBufferDone(outHeader);
500    }
501
502    return true;
503}
504
505void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) {
506    if (portIndex == kInputPortIndex) {
507        mEOSStatus = INPUT_DATA_AVAILABLE;
508    }
509}
510
511void SoftAVC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
512    switch (mOutputPortSettingsChange) {
513        case NONE:
514            break;
515
516        case AWAITING_DISABLED:
517        {
518            CHECK(!enabled);
519            mOutputPortSettingsChange = AWAITING_ENABLED;
520            break;
521        }
522
523        default:
524        {
525            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
526            CHECK(enabled);
527            mOutputPortSettingsChange = NONE;
528            break;
529        }
530    }
531}
532
533void SoftAVC::onReset() {
534    mSignalledError = false;
535    mOutputPortSettingsChange = NONE;
536}
537
538void SoftAVC::updatePortDefinitions() {
539    OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
540    def->format.video.nFrameWidth = mWidth;
541    def->format.video.nFrameHeight = mHeight;
542    def->format.video.nStride = def->format.video.nFrameWidth;
543    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
544
545    def = &editPortInfo(1)->mDef;
546    def->format.video.nFrameWidth = mWidth;
547    def->format.video.nFrameHeight = mHeight;
548    def->format.video.nStride = def->format.video.nFrameWidth;
549    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
550
551    def->nBufferSize =
552        (def->format.video.nFrameWidth
553            * def->format.video.nFrameHeight * 3) / 2;
554}
555
556}  // namespace android
557
558android::SoftOMXComponent *createSoftOMXComponent(
559        const char *name, const OMX_CALLBACKTYPE *callbacks,
560        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
561    return new android::SoftAVC(name, callbacks, appData, component);
562}
563