Home | History | Annotate | Download | only in h264dec
      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 
     29 namespace android {
     30 
     31 static 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 
     50 SoftAVC::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 
     75 SoftAVC::~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 
     93 status_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 
    101 void 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 
    113     if (mHeadersDecoded) {
    114         // Dequeue any already decoded output frames to free up space
    115         // in the output queue.
    116 
    117         drainAllOutputBuffers(false /* eos */);
    118     }
    119 
    120     H264SwDecRet ret = H264SWDEC_PIC_RDY;
    121     bool portSettingsChanged = false;
    122     while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty())
    123             && outQueue.size() == kNumOutputBuffers) {
    124 
    125         if (mEOSStatus == INPUT_EOS_SEEN) {
    126             drainAllOutputBuffers(true /* eos */);
    127             return;
    128         }
    129 
    130         BufferInfo *inInfo = *inQueue.begin();
    131         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    132         ++mPicId;
    133 
    134         OMX_BUFFERHEADERTYPE *header = new OMX_BUFFERHEADERTYPE;
    135         memset(header, 0, sizeof(OMX_BUFFERHEADERTYPE));
    136         header->nTimeStamp = inHeader->nTimeStamp;
    137         header->nFlags = inHeader->nFlags;
    138         if (header->nFlags & OMX_BUFFERFLAG_EOS) {
    139             mEOSStatus = INPUT_EOS_SEEN;
    140         }
    141         mPicToHeaderMap.add(mPicId, header);
    142         inQueue.erase(inQueue.begin());
    143 
    144         H264SwDecInput inPicture;
    145         H264SwDecOutput outPicture;
    146         memset(&inPicture, 0, sizeof(inPicture));
    147         inPicture.dataLen = inHeader->nFilledLen;
    148         inPicture.pStream = inHeader->pBuffer + inHeader->nOffset;
    149         inPicture.picId = mPicId;
    150         inPicture.intraConcealmentMethod = 1;
    151         H264SwDecPicture decodedPicture;
    152 
    153         while (inPicture.dataLen > 0) {
    154             ret = H264SwDecDecode(mHandle, &inPicture, &outPicture);
    155             if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY ||
    156                 ret == H264SWDEC_PIC_RDY_BUFF_NOT_EMPTY) {
    157                 inPicture.dataLen -= (u32)(outPicture.pStrmCurrPos - inPicture.pStream);
    158                 inPicture.pStream = outPicture.pStrmCurrPos;
    159                 if (ret == H264SWDEC_HDRS_RDY_BUFF_NOT_EMPTY) {
    160                     mHeadersDecoded = true;
    161                     H264SwDecInfo decoderInfo;
    162                     CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK);
    163 
    164                     if (handlePortSettingChangeEvent(&decoderInfo)) {
    165                         portSettingsChanged = true;
    166                     }
    167 
    168                     if (decoderInfo.croppingFlag &&
    169                         handleCropRectEvent(&decoderInfo.cropParams)) {
    170                         portSettingsChanged = true;
    171                     }
    172                 }
    173             } else {
    174                 if (portSettingsChanged) {
    175                     if (H264SwDecNextPicture(mHandle, &decodedPicture, 0)
    176                         == H264SWDEC_PIC_RDY) {
    177 
    178                         // Save this output buffer; otherwise, it will be
    179                         // lost during dynamic port reconfiguration because
    180                         // OpenMAX client will delete _all_ output buffers
    181                         // in the process.
    182                         saveFirstOutputBuffer(
    183                             decodedPicture.picId,
    184                             (uint8_t *)decodedPicture.pOutputPicture);
    185                     }
    186                 }
    187                 inPicture.dataLen = 0;
    188                 if (ret < 0) {
    189                     ALOGE("Decoder failed: %d", ret);
    190 
    191                     notify(OMX_EventError, OMX_ErrorUndefined,
    192                            ERROR_MALFORMED, NULL);
    193 
    194                     mSignalledError = true;
    195                     return;
    196                 }
    197             }
    198         }
    199         inInfo->mOwnedByUs = false;
    200         notifyEmptyBufferDone(inHeader);
    201 
    202         if (portSettingsChanged) {
    203             portSettingsChanged = false;
    204             return;
    205         }
    206 
    207         if (mFirstPicture && !outQueue.empty()) {
    208             drainOneOutputBuffer(mFirstPictureId, mFirstPicture);
    209             delete[] mFirstPicture;
    210             mFirstPicture = NULL;
    211             mFirstPictureId = -1;
    212         }
    213 
    214         drainAllOutputBuffers(false /* eos */);
    215     }
    216 }
    217 
    218 bool 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 
    232 bool 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 
    250 void 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 
    258 void 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 
    275 void SoftAVC::drainAllOutputBuffers(bool eos) {
    276     List<BufferInfo *> &outQueue = getPortQueue(kOutputPortIndex);
    277     H264SwDecPicture decodedPicture;
    278 
    279     if (mHeadersDecoded) {
    280         while (!outQueue.empty()
    281                 && H264SWDEC_PIC_RDY == H264SwDecNextPicture(
    282                     mHandle, &decodedPicture, eos /* flush */)) {
    283             int32_t picId = decodedPicture.picId;
    284             uint8_t *data = (uint8_t *) decodedPicture.pOutputPicture;
    285             drainOneOutputBuffer(picId, data);
    286         }
    287     }
    288 
    289     if (!eos) {
    290         return;
    291     }
    292 
    293     while (!outQueue.empty()) {
    294         BufferInfo *outInfo = *outQueue.begin();
    295         outQueue.erase(outQueue.begin());
    296         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
    297 
    298         outHeader->nTimeStamp = 0;
    299         outHeader->nFilledLen = 0;
    300         outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    301 
    302         outInfo->mOwnedByUs = false;
    303         notifyFillBufferDone(outHeader);
    304 
    305         mEOSStatus = OUTPUT_FRAMES_FLUSHED;
    306     }
    307 }
    308 
    309 void SoftAVC::onPortFlushCompleted(OMX_U32 portIndex) {
    310     if (portIndex == kInputPortIndex) {
    311         mEOSStatus = INPUT_DATA_AVAILABLE;
    312     }
    313 }
    314 
    315 void SoftAVC::onReset() {
    316     SoftVideoDecoderOMXComponent::onReset();
    317     mSignalledError = false;
    318 }
    319 
    320 }  // namespace android
    321 
    322 android::SoftOMXComponent *createSoftOMXComponent(
    323         const char *name, const OMX_CALLBACKTYPE *callbacks,
    324         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    325     return new android::SoftAVC(name, callbacks, appData, component);
    326 }
    327