SoftAVC.cpp revision 9a8ded7348c5b2302dd27b285b395416bc842c49
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
50template<class T>
51static void InitOMXParams(T *params) {
52    params->nSize = sizeof(T);
53    params->nVersion.s.nVersionMajor = 1;
54    params->nVersion.s.nVersionMinor = 0;
55    params->nVersion.s.nRevision = 0;
56    params->nVersion.s.nStep = 0;
57}
58
59SoftAVC::SoftAVC(
60        const char *name,
61        const OMX_CALLBACKTYPE *callbacks,
62        OMX_PTR appData,
63        OMX_COMPONENTTYPE **component)
64    : SimpleSoftOMXComponent(name, callbacks, appData, component),
65      mHandle(NULL),
66      mInputBufferCount(0),
67      mWidth(320),
68      mHeight(240),
69      mPictureSize(mWidth * mHeight * 3 / 2),
70      mCropLeft(0),
71      mCropTop(0),
72      mCropWidth(mWidth),
73      mCropHeight(mHeight),
74      mFirstPicture(NULL),
75      mFirstPictureId(-1),
76      mPicId(0),
77      mHeadersDecoded(false),
78      mEOSStatus(INPUT_DATA_AVAILABLE),
79      mOutputPortSettingsChange(NONE),
80      mSignalledError(false) {
81    initPorts();
82    CHECK_EQ(initDecoder(), (status_t)OK);
83}
84
85SoftAVC::~SoftAVC() {
86    H264SwDecRelease(mHandle);
87    mHandle = NULL;
88
89    while (mPicToHeaderMap.size() != 0) {
90        OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.editValueAt(0);
91        mPicToHeaderMap.removeItemsAt(0);
92        delete header;
93        header = NULL;
94    }
95    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
96    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
97    CHECK(outQueue.empty());
98    CHECK(inQueue.empty());
99
100    delete[] mFirstPicture;
101}
102
103void SoftAVC::initPorts() {
104    OMX_PARAM_PORTDEFINITIONTYPE def;
105    InitOMXParams(&def);
106
107    def.nPortIndex = kInputPortIndex;
108    def.eDir = OMX_DirInput;
109    def.nBufferCountMin = kNumInputBuffers;
110    def.nBufferCountActual = def.nBufferCountMin;
111    def.nBufferSize = 8192;
112    def.bEnabled = OMX_TRUE;
113    def.bPopulated = OMX_FALSE;
114    def.eDomain = OMX_PortDomainVideo;
115    def.bBuffersContiguous = OMX_FALSE;
116    def.nBufferAlignment = 1;
117
118    def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC);
119    def.format.video.pNativeRender = NULL;
120    def.format.video.nFrameWidth = mWidth;
121    def.format.video.nFrameHeight = mHeight;
122    def.format.video.nStride = def.format.video.nFrameWidth;
123    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
124    def.format.video.nBitrate = 0;
125    def.format.video.xFramerate = 0;
126    def.format.video.bFlagErrorConcealment = OMX_FALSE;
127    def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
128    def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
129    def.format.video.pNativeWindow = NULL;
130
131    addPort(def);
132
133    def.nPortIndex = kOutputPortIndex;
134    def.eDir = OMX_DirOutput;
135    def.nBufferCountMin = kNumOutputBuffers;
136    def.nBufferCountActual = def.nBufferCountMin;
137    def.bEnabled = OMX_TRUE;
138    def.bPopulated = OMX_FALSE;
139    def.eDomain = OMX_PortDomainVideo;
140    def.bBuffersContiguous = OMX_FALSE;
141    def.nBufferAlignment = 2;
142
143    def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
144    def.format.video.pNativeRender = NULL;
145    def.format.video.nFrameWidth = mWidth;
146    def.format.video.nFrameHeight = mHeight;
147    def.format.video.nStride = def.format.video.nFrameWidth;
148    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
149    def.format.video.nBitrate = 0;
150    def.format.video.xFramerate = 0;
151    def.format.video.bFlagErrorConcealment = OMX_FALSE;
152    def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
153    def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
154    def.format.video.pNativeWindow = NULL;
155
156    def.nBufferSize =
157        (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
158
159    addPort(def);
160}
161
162status_t SoftAVC::initDecoder() {
163    // Force decoder to output buffers in display order.
164    if (H264SwDecInit(&mHandle, 0) == H264SWDEC_OK) {
165        return OK;
166    }
167    return UNKNOWN_ERROR;
168}
169
170OMX_ERRORTYPE SoftAVC::internalGetParameter(
171        OMX_INDEXTYPE index, OMX_PTR params) {
172    switch (index) {
173        case OMX_IndexParamVideoPortFormat:
174        {
175            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
176                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
177
178            if (formatParams->nPortIndex > kOutputPortIndex) {
179                return OMX_ErrorUndefined;
180            }
181
182            if (formatParams->nIndex != 0) {
183                return OMX_ErrorNoMore;
184            }
185
186            if (formatParams->nPortIndex == kInputPortIndex) {
187                formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
188                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
189                formatParams->xFramerate = 0;
190            } else {
191                CHECK(formatParams->nPortIndex == kOutputPortIndex);
192
193                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
194                formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
195                formatParams->xFramerate = 0;
196            }
197
198            return OMX_ErrorNone;
199        }
200
201        case OMX_IndexParamVideoProfileLevelQuerySupported:
202        {
203            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
204                    (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
205
206            if (profileLevel->nPortIndex != kInputPortIndex) {
207                ALOGE("Invalid port index: %ld", profileLevel->nPortIndex);
208                return OMX_ErrorUnsupportedIndex;
209            }
210
211            size_t index = profileLevel->nProfileIndex;
212            size_t nProfileLevels =
213                    sizeof(kProfileLevels) / sizeof(kProfileLevels[0]);
214            if (index >= nProfileLevels) {
215                return OMX_ErrorNoMore;
216            }
217
218            profileLevel->eProfile = kProfileLevels[index].mProfile;
219            profileLevel->eLevel = kProfileLevels[index].mLevel;
220            return OMX_ErrorNone;
221        }
222
223        default:
224            return SimpleSoftOMXComponent::internalGetParameter(index, params);
225    }
226}
227
228OMX_ERRORTYPE SoftAVC::internalSetParameter(
229        OMX_INDEXTYPE index, const OMX_PTR params) {
230    switch (index) {
231        case OMX_IndexParamStandardComponentRole:
232        {
233            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
234                (const OMX_PARAM_COMPONENTROLETYPE *)params;
235
236            if (strncmp((const char *)roleParams->cRole,
237                        "video_decoder.avc",
238                        OMX_MAX_STRINGNAME_SIZE - 1)) {
239                return OMX_ErrorUndefined;
240            }
241
242            return OMX_ErrorNone;
243        }
244
245        case OMX_IndexParamVideoPortFormat:
246        {
247            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
248                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
249
250            if (formatParams->nPortIndex > kOutputPortIndex) {
251                return OMX_ErrorUndefined;
252            }
253
254            if (formatParams->nIndex != 0) {
255                return OMX_ErrorNoMore;
256            }
257
258            return OMX_ErrorNone;
259        }
260
261        default:
262            return SimpleSoftOMXComponent::internalSetParameter(index, params);
263    }
264}
265
266OMX_ERRORTYPE SoftAVC::getConfig(
267        OMX_INDEXTYPE index, OMX_PTR params) {
268    switch (index) {
269        case OMX_IndexConfigCommonOutputCrop:
270        {
271            OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
272
273            if (rectParams->nPortIndex != 1) {
274                return OMX_ErrorUndefined;
275            }
276
277            rectParams->nLeft = mCropLeft;
278            rectParams->nTop = mCropTop;
279            rectParams->nWidth = mCropWidth;
280            rectParams->nHeight = mCropHeight;
281
282            return OMX_ErrorNone;
283        }
284
285        default:
286            return OMX_ErrorUnsupportedIndex;
287    }
288}
289
290void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
291    if (mSignalledError || mOutputPortSettingsChange != NONE) {
292        return;
293    }
294
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        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
315            inQueue.erase(inQueue.begin());
316            inInfo->mOwnedByUs = false;
317            notifyEmptyBufferDone(inHeader);
318            mEOSStatus = INPUT_EOS_SEEN;
319            continue;
320        }
321
322        OMX_BUFFERHEADERTYPE *header = new OMX_BUFFERHEADERTYPE;
323        memset(header, 0, sizeof(OMX_BUFFERHEADERTYPE));
324        header->nTimeStamp = inHeader->nTimeStamp;
325        header->nFlags = inHeader->nFlags;
326        mPicToHeaderMap.add(mPicId, header);
327        inQueue.erase(inQueue.begin());
328
329        H264SwDecInput inPicture;
330        H264SwDecOutput outPicture;
331        memset(&inPicture, 0, sizeof(inPicture));
332        inPicture.dataLen = inHeader->nFilledLen;
333        inPicture.pStream = inHeader->pBuffer + inHeader->nOffset;
334        inPicture.picId = mPicId;
335        inPicture.intraConcealmentMethod = 1;
336        H264SwDecPicture decodedPicture;
337
338        while (inPicture.dataLen > 0) {
339            ret = H264SwDecDecode(mHandle, &inPicture, &outPicture);
340            if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY ||
341                ret == H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY) {
342                inPicture.dataLen -= (u32)(outPicture.pStrmCurrPos - inPicture.pStream);
343                inPicture.pStream = outPicture.pStrmCurrPos;
344                if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY) {
345                    mHeadersDecoded = true;
346                    H264SwDecInfo decoderInfo;
347                    CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK);
348
349                    if (handlePortSettingChangeEvent(&decoderInfo)) {
350                        portSettingsChanged = true;
351                    }
352
353                    if (decoderInfo.croppingFlag &&
354                        handleCropRectEvent(&decoderInfo.cropParams)) {
355                        portSettingsChanged = true;
356                    }
357                }
358            } else {
359                if (portSettingsChanged) {
360                    if (H264SwDecNextPicture(mHandle, &decodedPicture, 0)
361                        == H264SWDEC_PIC_RDY) {
362
363                        // Save this output buffer; otherwise, it will be
364                        // lost during dynamic port reconfiguration because
365                        // OpenMAX client will delete _all_ output buffers
366                        // in the process.
367                        saveFirstOutputBuffer(
368                            decodedPicture.picId,
369                            (uint8_t *)decodedPicture.pOutputPicture);
370                    }
371                }
372                inPicture.dataLen = 0;
373                if (ret < 0) {
374                    ALOGE("Decoder failed: %d", ret);
375
376                    notify(OMX_EventError, OMX_ErrorUndefined,
377                           ERROR_MALFORMED, NULL);
378
379                    mSignalledError = true;
380                    return;
381                }
382            }
383        }
384        inInfo->mOwnedByUs = false;
385        notifyEmptyBufferDone(inHeader);
386
387        if (portSettingsChanged) {
388            portSettingsChanged = false;
389            return;
390        }
391
392        if (mFirstPicture && !outQueue.empty()) {
393            drainOneOutputBuffer(mFirstPictureId, mFirstPicture);
394            delete[] mFirstPicture;
395            mFirstPicture = NULL;
396            mFirstPictureId = -1;
397        }
398
399        while (!outQueue.empty() &&
400                mHeadersDecoded &&
401                H264SwDecNextPicture(mHandle, &decodedPicture, 0)
402                    == H264SWDEC_PIC_RDY) {
403
404            int32_t picId = decodedPicture.picId;
405            uint8_t *data = (uint8_t *) decodedPicture.pOutputPicture;
406            drainOneOutputBuffer(picId, data);
407        }
408    }
409}
410
411bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) {
412    if (mWidth != info->picWidth || mHeight != info->picHeight) {
413        mWidth  = info->picWidth;
414        mHeight = info->picHeight;
415        mPictureSize = mWidth * mHeight * 3 / 2;
416        mCropWidth = mWidth;
417        mCropHeight = mHeight;
418        updatePortDefinitions();
419        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
420        mOutputPortSettingsChange = AWAITING_DISABLED;
421        return true;
422    }
423
424    return false;
425}
426
427bool SoftAVC::handleCropRectEvent(const CropParams *crop) {
428    if (mCropLeft != crop->cropLeftOffset ||
429        mCropTop != crop->cropTopOffset ||
430        mCropWidth != crop->cropOutWidth ||
431        mCropHeight != crop->cropOutHeight) {
432        mCropLeft = crop->cropLeftOffset;
433        mCropTop = crop->cropTopOffset;
434        mCropWidth = crop->cropOutWidth;
435        mCropHeight = crop->cropOutHeight;
436
437        notify(OMX_EventPortSettingsChanged, 1,
438                OMX_IndexConfigCommonOutputCrop, NULL);
439
440        return true;
441    }
442    return false;
443}
444
445void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) {
446    CHECK(mFirstPicture == NULL);
447    mFirstPictureId = picId;
448
449    mFirstPicture = new uint8_t[mPictureSize];
450    memcpy(mFirstPicture, data, mPictureSize);
451}
452
453void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) {
454    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
455    BufferInfo *outInfo = *outQueue.begin();
456    outQueue.erase(outQueue.begin());
457    OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
458    OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId);
459    outHeader->nTimeStamp = header->nTimeStamp;
460    outHeader->nFlags = header->nFlags;
461    outHeader->nFilledLen = mPictureSize;
462    memcpy(outHeader->pBuffer + outHeader->nOffset,
463            data, mPictureSize);
464    mPicToHeaderMap.removeItem(picId);
465    delete header;
466    outInfo->mOwnedByUs = false;
467    notifyFillBufferDone(outHeader);
468}
469
470bool SoftAVC::drainAllOutputBuffers() {
471    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
472    H264SwDecPicture decodedPicture;
473
474    while (!outQueue.empty()) {
475        BufferInfo *outInfo = *outQueue.begin();
476        outQueue.erase(outQueue.begin());
477        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
478        if (mHeadersDecoded &&
479            H264SWDEC_PIC_RDY ==
480                H264SwDecNextPicture(mHandle, &decodedPicture, 1 /* flush */)) {
481
482            int32_t picId = decodedPicture.picId;
483            CHECK(mPicToHeaderMap.indexOfKey(picId) >= 0);
484
485            memcpy(outHeader->pBuffer + outHeader->nOffset,
486                decodedPicture.pOutputPicture,
487                mPictureSize);
488
489            OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId);
490            outHeader->nTimeStamp = header->nTimeStamp;
491            outHeader->nFlags = header->nFlags;
492            outHeader->nFilledLen = mPictureSize;
493            mPicToHeaderMap.removeItem(picId);
494            delete header;
495        } else {
496            outHeader->nTimeStamp = 0;
497            outHeader->nFilledLen = 0;
498            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
499            mEOSStatus = OUTPUT_FRAMES_FLUSHED;
500        }
501
502        outInfo->mOwnedByUs = false;
503        notifyFillBufferDone(outHeader);
504    }
505
506    return true;
507}
508
509void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) {
510    if (portIndex == kInputPortIndex) {
511        mEOSStatus = INPUT_DATA_AVAILABLE;
512    }
513}
514
515void SoftAVC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
516    switch (mOutputPortSettingsChange) {
517        case NONE:
518            break;
519
520        case AWAITING_DISABLED:
521        {
522            CHECK(!enabled);
523            mOutputPortSettingsChange = AWAITING_ENABLED;
524            break;
525        }
526
527        default:
528        {
529            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
530            CHECK(enabled);
531            mOutputPortSettingsChange = NONE;
532            break;
533        }
534    }
535}
536
537void SoftAVC::updatePortDefinitions() {
538    OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
539    def->format.video.nFrameWidth = mWidth;
540    def->format.video.nFrameHeight = mHeight;
541    def->format.video.nStride = def->format.video.nFrameWidth;
542    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
543
544    def = &editPortInfo(1)->mDef;
545    def->format.video.nFrameWidth = mWidth;
546    def->format.video.nFrameHeight = mHeight;
547    def->format.video.nStride = def->format.video.nFrameWidth;
548    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
549
550    def->nBufferSize =
551        (def->format.video.nFrameWidth
552            * def->format.video.nFrameHeight * 3) / 2;
553}
554
555}  // namespace android
556
557android::SoftOMXComponent *createSoftOMXComponent(
558        const char *name, const OMX_CALLBACKTYPE *callbacks,
559        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
560    return new android::SoftAVC(name, callbacks, appData, component);
561}
562