PageRenderTime 491ms CodeModel.GetById 141ms app.highlight 183ms RepoModel.GetById 101ms app.codeStats 60ms

/H264Dec/SoftAVC.cpp

http://github.com/mbebenita/Broadway
C++ | 560 lines | 455 code | 84 blank | 21 comment | 72 complexity | a5c56cde4ded20ea1ab3ba97ba1e7010 MD5 | raw file
  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    initPorts();
 81    CHECK_EQ(initDecoder(), (status_t)OK);
 82}
 83
 84SoftAVC::~SoftAVC() {
 85    H264SwDecRelease(mHandle);
 86    mHandle = NULL;
 87
 88    while (mPicToHeaderMap.size() != 0) {
 89        OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.editValueAt(0);
 90        mPicToHeaderMap.removeItemsAt(0);
 91        delete header;
 92        header = NULL;
 93    }
 94    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
 95    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
 96    CHECK(outQueue.empty());
 97    CHECK(inQueue.empty());
 98
 99    delete[] mFirstPicture;
100}
101
102void SoftAVC::initPorts() {
103    OMX_PARAM_PORTDEFINITIONTYPE def;
104    InitOMXParams(&def);
105
106    def.nPortIndex = kInputPortIndex;
107    def.eDir = OMX_DirInput;
108    def.nBufferCountMin = kNumInputBuffers;
109    def.nBufferCountActual = def.nBufferCountMin;
110    def.nBufferSize = 8192;
111    def.bEnabled = OMX_TRUE;
112    def.bPopulated = OMX_FALSE;
113    def.eDomain = OMX_PortDomainVideo;
114    def.bBuffersContiguous = OMX_FALSE;
115    def.nBufferAlignment = 1;
116
117    def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_AVC);
118    def.format.video.pNativeRender = NULL;
119    def.format.video.nFrameWidth = mWidth;
120    def.format.video.nFrameHeight = mHeight;
121    def.format.video.nStride = def.format.video.nFrameWidth;
122    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
123    def.format.video.nBitrate = 0;
124    def.format.video.xFramerate = 0;
125    def.format.video.bFlagErrorConcealment = OMX_FALSE;
126    def.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
127    def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
128    def.format.video.pNativeWindow = NULL;
129
130    addPort(def);
131
132    def.nPortIndex = kOutputPortIndex;
133    def.eDir = OMX_DirOutput;
134    def.nBufferCountMin = kNumOutputBuffers;
135    def.nBufferCountActual = def.nBufferCountMin;
136    def.bEnabled = OMX_TRUE;
137    def.bPopulated = OMX_FALSE;
138    def.eDomain = OMX_PortDomainVideo;
139    def.bBuffersContiguous = OMX_FALSE;
140    def.nBufferAlignment = 2;
141
142    def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
143    def.format.video.pNativeRender = NULL;
144    def.format.video.nFrameWidth = mWidth;
145    def.format.video.nFrameHeight = mHeight;
146    def.format.video.nStride = def.format.video.nFrameWidth;
147    def.format.video.nSliceHeight = def.format.video.nFrameHeight;
148    def.format.video.nBitrate = 0;
149    def.format.video.xFramerate = 0;
150    def.format.video.bFlagErrorConcealment = OMX_FALSE;
151    def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
152    def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
153    def.format.video.pNativeWindow = NULL;
154
155    def.nBufferSize =
156        (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
157
158    addPort(def);
159}
160
161status_t SoftAVC::initDecoder() {
162    // Force decoder to output buffers in display order.
163    if (H264SwDecInit(&mHandle, 0) == H264SWDEC_OK) {
164        return OK;
165    }
166    return UNKNOWN_ERROR;
167}
168
169OMX_ERRORTYPE SoftAVC::internalGetParameter(
170        OMX_INDEXTYPE index, OMX_PTR params) {
171    switch (index) {
172        case OMX_IndexParamVideoPortFormat:
173        {
174            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
175                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
176
177            if (formatParams->nPortIndex > kOutputPortIndex) {
178                return OMX_ErrorUndefined;
179            }
180
181            if (formatParams->nIndex != 0) {
182                return OMX_ErrorNoMore;
183            }
184
185            if (formatParams->nPortIndex == kInputPortIndex) {
186                formatParams->eCompressionFormat = OMX_VIDEO_CodingAVC;
187                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
188                formatParams->xFramerate = 0;
189            } else {
190                CHECK(formatParams->nPortIndex == kOutputPortIndex);
191
192                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
193                formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
194                formatParams->xFramerate = 0;
195            }
196
197            return OMX_ErrorNone;
198        }
199
200        case OMX_IndexParamVideoProfileLevelQuerySupported:
201        {
202            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
203                    (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
204
205            if (profileLevel->nPortIndex != kInputPortIndex) {
206                LOGE("Invalid port index: %ld", profileLevel->nPortIndex);
207                return OMX_ErrorUnsupportedIndex;
208            }
209
210            size_t index = profileLevel->nProfileIndex;
211            size_t nProfileLevels =
212                    sizeof(kProfileLevels) / sizeof(kProfileLevels[0]);
213            if (index >= nProfileLevels) {
214                return OMX_ErrorNoMore;
215            }
216
217            profileLevel->eProfile = kProfileLevels[index].mProfile;
218            profileLevel->eLevel = kProfileLevels[index].mLevel;
219            return OMX_ErrorNone;
220        }
221
222        default:
223            return SimpleSoftOMXComponent::internalGetParameter(index, params);
224    }
225}
226
227OMX_ERRORTYPE SoftAVC::internalSetParameter(
228        OMX_INDEXTYPE index, const OMX_PTR params) {
229    switch (index) {
230        case OMX_IndexParamStandardComponentRole:
231        {
232            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
233                (const OMX_PARAM_COMPONENTROLETYPE *)params;
234
235            if (strncmp((const char *)roleParams->cRole,
236                        "video_decoder.avc",
237                        OMX_MAX_STRINGNAME_SIZE - 1)) {
238                return OMX_ErrorUndefined;
239            }
240
241            return OMX_ErrorNone;
242        }
243
244        case OMX_IndexParamVideoPortFormat:
245        {
246            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
247                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
248
249            if (formatParams->nPortIndex > kOutputPortIndex) {
250                return OMX_ErrorUndefined;
251            }
252
253            if (formatParams->nIndex != 0) {
254                return OMX_ErrorNoMore;
255            }
256
257            return OMX_ErrorNone;
258        }
259
260        default:
261            return SimpleSoftOMXComponent::internalSetParameter(index, params);
262    }
263}
264
265OMX_ERRORTYPE SoftAVC::getConfig(
266        OMX_INDEXTYPE index, OMX_PTR params) {
267    switch (index) {
268        case OMX_IndexConfigCommonOutputCrop:
269        {
270            OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
271
272            if (rectParams->nPortIndex != 1) {
273                return OMX_ErrorUndefined;
274            }
275
276            rectParams->nLeft = mCropLeft;
277            rectParams->nTop = mCropTop;
278            rectParams->nWidth = mCropWidth;
279            rectParams->nHeight = mCropHeight;
280
281            return OMX_ErrorNone;
282        }
283
284        default:
285            return OMX_ErrorUnsupportedIndex;
286    }
287}
288
289void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
290    if (mOutputPortSettingsChange != NONE) {
291        return;
292    }
293
294    if (mEOSStatus == OUTPUT_FRAMES_FLUSHED) {
295        return;
296    }
297
298    List<BufferInfo *> &inQueue = getPortQueue(kInputPortIndex);
299    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
300    H264SwDecRet ret = H264SWDEC_PIC_RDY;
301    status_t err = OK;
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                    LOGE("Decoder failed: %d", ret);
375                    err = ERROR_MALFORMED;
376                }
377            }
378        }
379        inInfo->mOwnedByUs = false;
380        notifyEmptyBufferDone(inHeader);
381
382        if (portSettingsChanged) {
383            portSettingsChanged = false;
384            return;
385        }
386
387        if (mFirstPicture && !outQueue.empty()) {
388            drainOneOutputBuffer(mFirstPictureId, mFirstPicture);
389            delete[] mFirstPicture;
390            mFirstPicture = NULL;
391            mFirstPictureId = -1;
392        }
393
394        while (!outQueue.empty() &&
395                mHeadersDecoded &&
396                H264SwDecNextPicture(mHandle, &decodedPicture, 0)
397                    == H264SWDEC_PIC_RDY) {
398
399            int32_t picId = decodedPicture.picId;
400            uint8_t *data = (uint8_t *) decodedPicture.pOutputPicture;
401            drainOneOutputBuffer(picId, data);
402        }
403
404        if (err != OK) {
405            notify(OMX_EventError, OMX_ErrorUndefined, err, NULL);
406        }
407    }
408}
409
410bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) {
411    if (mWidth != info->picWidth || mHeight != info->picHeight) {
412        mWidth  = info->picWidth;
413        mHeight = info->picHeight;
414        mPictureSize = mWidth * mHeight * 3 / 2;
415        mCropWidth = mWidth;
416        mCropHeight = mHeight;
417        updatePortDefinitions();
418        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
419        mOutputPortSettingsChange = AWAITING_DISABLED;
420        return true;
421    }
422
423    return false;
424}
425
426bool SoftAVC::handleCropRectEvent(const CropParams *crop) {
427    if (mCropLeft != crop->cropLeftOffset ||
428        mCropTop != crop->cropTopOffset ||
429        mCropWidth != crop->cropOutWidth ||
430        mCropHeight != crop->cropOutHeight) {
431        mCropLeft = crop->cropLeftOffset;
432        mCropTop = crop->cropTopOffset;
433        mCropWidth = crop->cropOutWidth;
434        mCropHeight = crop->cropOutHeight;
435
436        notify(OMX_EventPortSettingsChanged, 1,
437                OMX_IndexConfigCommonOutputCrop, NULL);
438
439        return true;
440    }
441    return false;
442}
443
444void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) {
445    CHECK(mFirstPicture == NULL);
446    mFirstPictureId = picId;
447
448    mFirstPicture = new uint8_t[mPictureSize];
449    memcpy(mFirstPicture, data, mPictureSize);
450}
451
452void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) {
453    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
454    BufferInfo *outInfo = *outQueue.begin();
455    outQueue.erase(outQueue.begin());
456    OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
457    OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId);
458    outHeader->nTimeStamp = header->nTimeStamp;
459    outHeader->nFlags = header->nFlags;
460    outHeader->nFilledLen = mPictureSize;
461    memcpy(outHeader->pBuffer + outHeader->nOffset,
462            data, mPictureSize);
463    mPicToHeaderMap.removeItem(picId);
464    delete header;
465    outInfo->mOwnedByUs = false;
466    notifyFillBufferDone(outHeader);
467}
468
469bool SoftAVC::drainAllOutputBuffers() {
470    List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
471    H264SwDecPicture decodedPicture;
472
473    while (!outQueue.empty()) {
474        BufferInfo *outInfo = *outQueue.begin();
475        outQueue.erase(outQueue.begin());
476        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
477        if (mHeadersDecoded &&
478            H264SWDEC_PIC_RDY ==
479                H264SwDecNextPicture(mHandle, &decodedPicture, 1 /* flush */)) {
480
481            int32_t picId = decodedPicture.picId;
482            CHECK(mPicToHeaderMap.indexOfKey(picId) >= 0);
483
484            memcpy(outHeader->pBuffer + outHeader->nOffset,
485                decodedPicture.pOutputPicture,
486                mPictureSize);
487
488            OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId);
489            outHeader->nTimeStamp = header->nTimeStamp;
490            outHeader->nFlags = header->nFlags;
491            outHeader->nFilledLen = mPictureSize;
492            mPicToHeaderMap.removeItem(picId);
493            delete header;
494        } else {
495            outHeader->nTimeStamp = 0;
496            outHeader->nFilledLen = 0;
497            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
498            mEOSStatus = OUTPUT_FRAMES_FLUSHED;
499        }
500
501        outInfo->mOwnedByUs = false;
502        notifyFillBufferDone(outHeader);
503    }
504
505    return true;
506}
507
508void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) {
509    if (portIndex == kInputPortIndex) {
510        mEOSStatus = INPUT_DATA_AVAILABLE;
511    }
512}
513
514void SoftAVC::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
515    switch (mOutputPortSettingsChange) {
516        case NONE:
517            break;
518
519        case AWAITING_DISABLED:
520        {
521            CHECK(!enabled);
522            mOutputPortSettingsChange = AWAITING_ENABLED;
523            break;
524        }
525
526        default:
527        {
528            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
529            CHECK(enabled);
530            mOutputPortSettingsChange = NONE;
531            break;
532        }
533    }
534}
535
536void SoftAVC::updatePortDefinitions() {
537    OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
538    def->format.video.nFrameWidth = mWidth;
539    def->format.video.nFrameHeight = mHeight;
540    def->format.video.nStride = def->format.video.nFrameWidth;
541    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
542
543    def = &editPortInfo(1)->mDef;
544    def->format.video.nFrameWidth = mWidth;
545    def->format.video.nFrameHeight = mHeight;
546    def->format.video.nStride = def->format.video.nFrameWidth;
547    def->format.video.nSliceHeight = def->format.video.nFrameHeight;
548
549    def->nBufferSize =
550        (def->format.video.nFrameWidth
551            * def->format.video.nFrameHeight * 3) / 2;
552}
553
554}  // namespace android
555
556android::SoftOMXComponent *createSoftOMXComponent(
557        const char *name, const OMX_CALLBACKTYPE *callbacks,
558        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
559    return new android::SoftAVC(name, callbacks, appData, component);
560}