SoftAVC.cpp revision d94e716af0e49d775f0c0c4f36dd2c136ba5f2b2
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
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