SoftAVC.cpp revision 7f616d3cc5366a4b8af20d3d0c768e3de1df0666
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "SoftAVC"
19#include <utils/Log.h>
20
21#include "SoftAVC.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/MediaDefs.h>
25#include <media/stagefright/MediaErrors.h>
26#include <media/IOMX.h>
27
28
29namespace android {
30
31static const CodecProfileLevel kProfileLevels[] = {
32    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1  },
33    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel1b },
34    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel11 },
35    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel12 },
36    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel13 },
37    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel2  },
38    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel21 },
39    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel22 },
40    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel3  },
41    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel31 },
42    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel32 },
43    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel4  },
44    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41 },
45    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel42 },
46    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel5  },
47    { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel51 },
48};
49
50SoftAVC::SoftAVC(
51        const char *name,
52        const OMX_CALLBACKTYPE *callbacks,
53        OMX_PTR appData,
54        OMX_COMPONENTTYPE **component)
55    : SoftVideoDecoderOMXComponent(
56            name, "video_decoder.avc", OMX_VIDEO_CodingAVC,
57            kProfileLevels, ARRAY_SIZE(kProfileLevels),
58            320 /* width */, 240 /* height */, callbacks, appData, component),
59      mHandle(NULL),
60      mInputBufferCount(0),
61      mPictureSize(mWidth * mHeight * 3 / 2),
62      mFirstPicture(NULL),
63      mFirstPictureId(-1),
64      mPicId(0),
65      mHeadersDecoded(false),
66      mEOSStatus(INPUT_DATA_AVAILABLE),
67      mSignalledError(false) {
68    initPorts(
69            kNumInputBuffers, 8192 /* inputBufferSize */,
70            kNumOutputBuffers, MEDIA_MIMETYPE_VIDEO_AVC);
71
72    CHECK_EQ(initDecoder(), (status_t)OK);
73}
74
75SoftAVC::~SoftAVC() {
76    H264SwDecRelease(mHandle);
77    mHandle = NULL;
78
79    while (mPicToHeaderMap.size() != 0) {
80        OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.editValueAt(0);
81        mPicToHeaderMap.removeItemsAt(0);
82        delete header;
83        header = NULL;
84    }
85    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
86    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
87    CHECK(outQueue.empty());
88    CHECK(inQueue.empty());
89
90    delete[] mFirstPicture;
91}
92
93status_t SoftAVC::initDecoder() {
94    // Force decoder to output buffers in display order.
95    if (H264SwDecInit(&mHandle, 0) == H264SWDEC_OK) {
96        return OK;
97    }
98    return UNKNOWN_ERROR;
99}
100
101void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
102    if (mSignalledError || mOutputPortSettingsChange != NONE) {
103        return;
104    }
105
106    if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
107        return;
108    }
109
110    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
111    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
112    H264SwDecRet ret = H264SWDEC_PIC_RDY;
113    bool portSettingsChanged = false;
114    while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty())
115            && outQueue.size() == kNumOutputBuffers) {
116
117        if (mEOSStatus == INPUT_EOS_SEEN) {
118            drainAllOutputBuffers();
119            return;
120        }
121
122        BufferInfo *inInfo = *inQueue.begin();
123        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
124        ++mPicId;
125
126        OMX_BUFFERHEADERTYPE *header = new OMX_BUFFERHEADERTYPE;
127        memset(header, 0, sizeof(OMX_BUFFERHEADERTYPE));
128        header->nTimeStamp = inHeader->nTimeStamp;
129        header->nFlags = inHeader->nFlags;
130        if (header->nFlags & OMX_BUFFERFLAG_EOS) {
131            mEOSStatus = INPUT_EOS_SEEN;
132        }
133        mPicToHeaderMap.add(mPicId, header);
134        inQueue.erase(inQueue.begin());
135
136        H264SwDecInput inPicture;
137        H264SwDecOutput outPicture;
138        memset(&inPicture, 0, sizeof(inPicture));
139        inPicture.dataLen = inHeader->nFilledLen;
140        inPicture.pStream = inHeader->pBuffer + inHeader->nOffset;
141        inPicture.picId = mPicId;
142        inPicture.intraConcealmentMethod = 1;
143        H264SwDecPicture decodedPicture;
144
145        while (inPicture.dataLen > 0) {
146            ret = H264SwDecDecode(mHandle, &inPicture, &outPicture);
147            if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY ||
148                ret == H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY) {
149                inPicture.dataLen -= (u32)(outPicture.pStrmCurrPos - inPicture.pStream);
150                inPicture.pStream = outPicture.pStrmCurrPos;
151                if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY) {
152                    mHeadersDecoded = true;
153                    H264SwDecInfo decoderInfo;
154                    CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK);
155
156                    if (handlePortSettingChangeEvent(&decoderInfo)) {
157                        portSettingsChanged = true;
158                    }
159
160                    if (decoderInfo.croppingFlag &&
161                        handleCropRectEvent(&decoderInfo.cropParams)) {
162                        portSettingsChanged = true;
163                    }
164                }
165            } else {
166                if (portSettingsChanged) {
167                    if (H264SwDecNextPicture(mHandle, &decodedPicture, 0)
168                        == H264SWDEC_PIC_RDY) {
169
170                        // Save this output buffer; otherwise, it will be
171                        // lost during dynamic port reconfiguration because
172                        // OpenMAX client will delete _all_ output buffers
173                        // in the process.
174                        saveFirstOutputBuffer(
175                            decodedPicture.picId,
176                            (uint8_t *)decodedPicture.pOutputPicture);
177                    }
178                }
179                inPicture.dataLen = 0;
180                if (ret < 0) {
181                    ALOGE("Decoder failed: %d", ret);
182
183                    notify(OMX_EventError, OMX_ErrorUndefined,
184                           ERROR_MALFORMED, NULL);
185
186                    mSignalledError = true;
187                    return;
188                }
189            }
190        }
191        inInfo->mOwnedByUs = false;
192        notifyEmptyBufferDone(inHeader);
193
194        if (portSettingsChanged) {
195            portSettingsChanged = false;
196            return;
197        }
198
199        if (mFirstPicture && !outQueue.empty()) {
200            drainOneOutputBuffer(mFirstPictureId, mFirstPicture);
201            delete[] mFirstPicture;
202            mFirstPicture = NULL;
203            mFirstPictureId = -1;
204        }
205
206        while (!outQueue.empty() &&
207                mHeadersDecoded &&
208                H264SwDecNextPicture(mHandle, &decodedPicture, 0)
209                    == H264SWDEC_PIC_RDY) {
210
211            int32_t picId = decodedPicture.picId;
212            uint8_t *data = (uint8_t *) decodedPicture.pOutputPicture;
213            drainOneOutputBuffer(picId, data);
214        }
215    }
216}
217
218bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) {
219    if (mWidth != info->picWidth || mHeight != info->picHeight) {
220        mWidth  = info->picWidth;
221        mHeight = info->picHeight;
222        mPictureSize = mWidth * mHeight * 3 / 2;
223        updatePortDefinitions();
224        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
225        mOutputPortSettingsChange = AWAITING_DISABLED;
226        return true;
227    }
228
229    return false;
230}
231
232bool SoftAVC::handleCropRectEvent(const CropParams *crop) {
233    if (mCropLeft != crop->cropLeftOffset ||
234        mCropTop != crop->cropTopOffset ||
235        mCropWidth != crop->cropOutWidth ||
236        mCropHeight != crop->cropOutHeight) {
237        mCropLeft = crop->cropLeftOffset;
238        mCropTop = crop->cropTopOffset;
239        mCropWidth = crop->cropOutWidth;
240        mCropHeight = crop->cropOutHeight;
241
242        notify(OMX_EventPortSettingsChanged, 1,
243                OMX_IndexConfigCommonOutputCrop, NULL);
244
245        return true;
246    }
247    return false;
248}
249
250void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) {
251    CHECK(mFirstPicture == NULL);
252    mFirstPictureId = picId;
253
254    mFirstPicture = new uint8_t[mPictureSize];
255    memcpy(mFirstPicture, data, mPictureSize);
256}
257
258void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) {
259    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
260    BufferInfo *outInfo = *outQueue.begin();
261    outQueue.erase(outQueue.begin());
262    OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
263    OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId);
264    outHeader->nTimeStamp = header->nTimeStamp;
265    outHeader->nFlags = header->nFlags;
266    outHeader->nFilledLen = mPictureSize;
267    memcpy(outHeader->pBuffer + outHeader->nOffset,
268            data, mPictureSize);
269    mPicToHeaderMap.removeItem(picId);
270    delete header;
271    outInfo->mOwnedByUs = false;
272    notifyFillBufferDone(outHeader);
273}
274
275bool SoftAVC::drainAllOutputBuffers() {
276    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
277    H264SwDecPicture decodedPicture;
278
279    while (!outQueue.empty()) {
280        BufferInfo *outInfo = *outQueue.begin();
281        outQueue.erase(outQueue.begin());
282        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
283        if (mHeadersDecoded &&
284            H264SWDEC_PIC_RDY ==
285                H264SwDecNextPicture(mHandle, &decodedPicture, 1 /* flush */)) {
286
287            int32_t picId = decodedPicture.picId;
288            CHECK(mPicToHeaderMap.indexOfKey(picId) >= 0);
289
290            memcpy(outHeader->pBuffer + outHeader->nOffset,
291                decodedPicture.pOutputPicture,
292                mPictureSize);
293
294            OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId);
295            outHeader->nTimeStamp = header->nTimeStamp;
296            outHeader->nFlags = header->nFlags;
297            outHeader->nFilledLen = mPictureSize;
298            mPicToHeaderMap.removeItem(picId);
299            delete header;
300        } else {
301            outHeader->nTimeStamp = 0;
302            outHeader->nFilledLen = 0;
303            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
304            mEOSStatus = OUTPUT_FRAMES_FLUSHED;
305        }
306
307        outInfo->mOwnedByUs = false;
308        notifyFillBufferDone(outHeader);
309    }
310
311    return true;
312}
313
314void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) {
315    if (portIndex == kInputPortIndex) {
316        mEOSStatus = INPUT_DATA_AVAILABLE;
317    }
318}
319
320void SoftAVC::onReset() {
321    SoftVideoDecoderOMXComponent::onReset();
322    mSignalledError = false;
323}
324
325}  // namespace android
326
327android::SoftOMXComponent *createSoftOMXComponent(
328        const char *name, const OMX_CALLBACKTYPE *callbacks,
329        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
330    return new android::SoftAVC(name, callbacks, appData, component);
331}
332