Home | History | Annotate | Download | only in dec
      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 "SoftMPEG4"
     19 #include <utils/Log.h>
     20 
     21 #include "SoftMPEG4.h"
     22 
     23 #include <media/stagefright/foundation/ADebug.h>
     24 #include <media/stagefright/foundation/AUtils.h>
     25 #include <media/stagefright/MediaDefs.h>
     26 #include <media/stagefright/MediaErrors.h>
     27 #include <media/IOMX.h>
     28 
     29 #include "mp4dec_api.h"
     30 
     31 namespace android {
     32 
     33 static const CodecProfileLevel kM4VProfileLevels[] = {
     34     { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 },
     35 };
     36 
     37 static const CodecProfileLevel kH263ProfileLevels[] = {
     38     { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 },
     39     { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 },
     40     { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level30 },
     41     { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level45 },
     42 };
     43 
     44 SoftMPEG4::SoftMPEG4(
     45         const char *name,
     46         const char *componentRole,
     47         OMX_VIDEO_CODINGTYPE codingType,
     48         const CodecProfileLevel *profileLevels,
     49         size_t numProfileLevels,
     50         const OMX_CALLBACKTYPE *callbacks,
     51         OMX_PTR appData,
     52         OMX_COMPONENTTYPE **component)
     53     : SoftVideoDecoderOMXComponent(
     54             name, componentRole, codingType, profileLevels, numProfileLevels,
     55             352 /* width */, 288 /* height */, callbacks, appData, component),
     56       mMode(codingType == OMX_VIDEO_CodingH263 ? MODE_H263 : MODE_MPEG4),
     57       mHandle(new tagvideoDecControls),
     58       mInputBufferCount(0),
     59       mSignalledError(false),
     60       mInitialized(false),
     61       mFramesConfigured(false),
     62       mNumSamplesOutput(0),
     63       mPvTime(0) {
     64     initPorts(
     65             kNumInputBuffers,
     66             352 * 288 * 3 / 2 /* minInputBufferSize */,
     67             kNumOutputBuffers,
     68             (mMode == MODE_MPEG4)
     69             ? MEDIA_MIMETYPE_VIDEO_MPEG4 : MEDIA_MIMETYPE_VIDEO_H263);
     70     CHECK_EQ(initDecoder(), (status_t)OK);
     71 }
     72 
     73 SoftMPEG4::~SoftMPEG4() {
     74     if (mInitialized) {
     75         PVCleanUpVideoDecoder(mHandle);
     76     }
     77 
     78     delete mHandle;
     79     mHandle = NULL;
     80 }
     81 
     82 status_t SoftMPEG4::initDecoder() {
     83     memset(mHandle, 0, sizeof(tagvideoDecControls));
     84     return OK;
     85 }
     86 
     87 void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) {
     88     if (mSignalledError || mOutputPortSettingsChange != NONE) {
     89         return;
     90     }
     91 
     92     List<BufferInfo *> &inQueue = getPortQueue(0);
     93     List<BufferInfo *> &outQueue = getPortQueue(1);
     94 
     95     while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
     96         BufferInfo *inInfo = *inQueue.begin();
     97         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
     98         if (inHeader == NULL) {
     99             inQueue.erase(inQueue.begin());
    100             inInfo->mOwnedByUs = false;
    101             continue;
    102         }
    103 
    104         PortInfo *port = editPortInfo(1);
    105 
    106         OMX_BUFFERHEADERTYPE *outHeader =
    107             port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
    108 
    109         if (inHeader->nFilledLen == 0) {
    110             inQueue.erase(inQueue.begin());
    111             inInfo->mOwnedByUs = false;
    112             notifyEmptyBufferDone(inHeader);
    113 
    114             ++mInputBufferCount;
    115 
    116             if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    117                 outHeader->nFilledLen = 0;
    118                 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    119 
    120                 List<BufferInfo *>::iterator it = outQueue.begin();
    121                 while ((*it)->mHeader != outHeader) {
    122                     ++it;
    123                 }
    124 
    125                 BufferInfo *outInfo = *it;
    126                 outInfo->mOwnedByUs = false;
    127                 outQueue.erase(it);
    128                 outInfo = NULL;
    129 
    130                 notifyFillBufferDone(outHeader);
    131                 outHeader = NULL;
    132             }
    133             return;
    134         }
    135 
    136         uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
    137         uint32_t *start_code = (uint32_t *)bitstream;
    138         bool volHeader = *start_code == 0xB0010000;
    139         if (volHeader) {
    140             PVCleanUpVideoDecoder(mHandle);
    141             mInitialized = false;
    142         }
    143 
    144         if (!mInitialized) {
    145             uint8_t *vol_data[1];
    146             int32_t vol_size = 0;
    147 
    148             vol_data[0] = NULL;
    149 
    150             if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) {
    151                 vol_data[0] = bitstream;
    152                 vol_size = inHeader->nFilledLen;
    153             }
    154 
    155             MP4DecodingMode mode =
    156                 (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;
    157 
    158             Bool success = PVInitVideoDecoder(
    159                     mHandle, vol_data, &vol_size, 1,
    160                     outputBufferWidth(), outputBufferHeight(), mode);
    161 
    162             if (!success) {
    163                 ALOGW("PVInitVideoDecoder failed. Unsupported content?");
    164 
    165                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    166                 mSignalledError = true;
    167                 return;
    168             }
    169 
    170             MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
    171             if (mode != actualMode) {
    172                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    173                 mSignalledError = true;
    174                 return;
    175             }
    176 
    177             PVSetPostProcType((VideoDecControls *) mHandle, 0);
    178 
    179             bool hasFrameData = false;
    180             if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
    181                 inInfo->mOwnedByUs = false;
    182                 inQueue.erase(inQueue.begin());
    183                 inInfo = NULL;
    184                 notifyEmptyBufferDone(inHeader);
    185                 inHeader = NULL;
    186             } else if (volHeader) {
    187                 hasFrameData = true;
    188             }
    189 
    190             mInitialized = true;
    191 
    192             if (mode == MPEG4_MODE && handlePortSettingsChange()) {
    193                 return;
    194             }
    195 
    196             if (!hasFrameData) {
    197                 continue;
    198             }
    199         }
    200 
    201         if (!mFramesConfigured) {
    202             PortInfo *port = editPortInfo(1);
    203             OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
    204 
    205             OMX_U32 yFrameSize = sizeof(uint8) * mHandle->size;
    206             if ((outHeader->nAllocLen < yFrameSize) ||
    207                     (outHeader->nAllocLen - yFrameSize < yFrameSize / 2)) {
    208                 ALOGE("Too small output buffer for reference frame: %lu bytes",
    209                         (unsigned long)outHeader->nAllocLen);
    210                 android_errorWriteLog(0x534e4554, "30033990");
    211                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    212                 mSignalledError = true;
    213                 return;
    214             }
    215             PVSetReferenceYUV(mHandle, outHeader->pBuffer);
    216             mFramesConfigured = true;
    217         }
    218 
    219         uint32_t useExtTimestamp = (inHeader->nOffset == 0);
    220 
    221         // decoder deals in ms (int32_t), OMX in us (int64_t)
    222         // so use fake timestamp instead
    223         uint32_t timestamp = 0xFFFFFFFF;
    224         if (useExtTimestamp) {
    225             mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp);
    226             timestamp = mPvTime;
    227             mPvTime++;
    228         }
    229 
    230         int32_t bufferSize = inHeader->nFilledLen;
    231         int32_t tmp = bufferSize;
    232 
    233         OMX_U32 frameSize;
    234         OMX_U64 yFrameSize = (OMX_U64)mWidth * (OMX_U64)mHeight;
    235         if (yFrameSize > ((OMX_U64)UINT32_MAX / 3) * 2) {
    236             ALOGE("Frame size too large");
    237             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    238             mSignalledError = true;
    239             return;
    240         }
    241         frameSize = (OMX_U32)(yFrameSize + (yFrameSize / 2));
    242 
    243         if (outHeader->nAllocLen < frameSize) {
    244             android_errorWriteLog(0x534e4554, "27833616");
    245             ALOGE("Insufficient output buffer size");
    246             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    247             mSignalledError = true;
    248             return;
    249         }
    250 
    251         // Need to check if header contains new info, e.g., width/height, etc.
    252         VopHeaderInfo header_info;
    253         uint8_t *bitstreamTmp = bitstream;
    254         if (PVDecodeVopHeader(
    255                     mHandle, &bitstreamTmp, &timestamp, &tmp,
    256                     &header_info, &useExtTimestamp,
    257                     outHeader->pBuffer) != PV_TRUE) {
    258             ALOGE("failed to decode vop header.");
    259 
    260             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    261             mSignalledError = true;
    262             return;
    263         }
    264         if (handlePortSettingsChange()) {
    265             return;
    266         }
    267 
    268         // The PV decoder is lying to us, sometimes it'll claim to only have
    269         // consumed a subset of the buffer when it clearly consumed all of it.
    270         // ignore whatever it says...
    271         if (PVDecodeVopBody(mHandle, &tmp) != PV_TRUE) {
    272             ALOGE("failed to decode video frame.");
    273 
    274             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    275             mSignalledError = true;
    276             return;
    277         }
    278 
    279         // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
    280         // decoder may detect size change after PVDecodeVideoFrame.
    281         if (handlePortSettingsChange()) {
    282             return;
    283         }
    284 
    285         // decoder deals in ms, OMX in us.
    286         outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp);
    287         mPvToOmxTimeMap.removeItem(timestamp);
    288 
    289         inHeader->nOffset += bufferSize;
    290         inHeader->nFilledLen = 0;
    291         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    292             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    293         } else {
    294             outHeader->nFlags = 0;
    295         }
    296 
    297         if (inHeader->nFilledLen == 0) {
    298             inInfo->mOwnedByUs = false;
    299             inQueue.erase(inQueue.begin());
    300             inInfo = NULL;
    301             notifyEmptyBufferDone(inHeader);
    302             inHeader = NULL;
    303         }
    304 
    305         ++mInputBufferCount;
    306 
    307         outHeader->nOffset = 0;
    308         outHeader->nFilledLen = frameSize;
    309 
    310         List<BufferInfo *>::iterator it = outQueue.begin();
    311         while ((*it)->mHeader != outHeader) {
    312             ++it;
    313         }
    314 
    315         BufferInfo *outInfo = *it;
    316         outInfo->mOwnedByUs = false;
    317         outQueue.erase(it);
    318         outInfo = NULL;
    319 
    320         notifyFillBufferDone(outHeader);
    321         outHeader = NULL;
    322 
    323         ++mNumSamplesOutput;
    324     }
    325 }
    326 
    327 bool SoftMPEG4::handlePortSettingsChange() {
    328     uint32_t disp_width, disp_height;
    329     PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height);
    330 
    331     uint32_t buf_width, buf_height;
    332     PVGetBufferDimensions(mHandle, (int32 *)&buf_width, (int32 *)&buf_height);
    333 
    334     CHECK_LE(disp_width, buf_width);
    335     CHECK_LE(disp_height, buf_height);
    336 
    337     ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
    338             disp_width, disp_height, buf_width, buf_height);
    339 
    340     CropSettingsMode cropSettingsMode = kCropUnSet;
    341     if (disp_width != buf_width || disp_height != buf_height) {
    342         cropSettingsMode = kCropSet;
    343 
    344         if (mCropWidth != disp_width || mCropHeight != disp_height) {
    345             mCropLeft = 0;
    346             mCropTop = 0;
    347             mCropWidth = disp_width;
    348             mCropHeight = disp_height;
    349             cropSettingsMode = kCropChanged;
    350         }
    351     }
    352 
    353     bool portWillReset = false;
    354     const bool fakeStride = true;
    355     SoftVideoDecoderOMXComponent::handlePortSettingsChange(
    356             &portWillReset, buf_width, buf_height, cropSettingsMode, fakeStride);
    357     if (portWillReset) {
    358         if (mMode == MODE_H263) {
    359             PVCleanUpVideoDecoder(mHandle);
    360 
    361             uint8_t *vol_data[1];
    362             int32_t vol_size = 0;
    363 
    364             vol_data[0] = NULL;
    365             if (!PVInitVideoDecoder(
    366                     mHandle, vol_data, &vol_size, 1, outputBufferWidth(), outputBufferHeight(),
    367                     H263_MODE)) {
    368                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    369                 mSignalledError = true;
    370                 return true;
    371             }
    372         }
    373 
    374         mFramesConfigured = false;
    375     }
    376 
    377     return portWillReset;
    378 }
    379 
    380 void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
    381     if (portIndex == 0 && mInitialized) {
    382         CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
    383     }
    384 }
    385 
    386 void SoftMPEG4::onReset() {
    387     SoftVideoDecoderOMXComponent::onReset();
    388     mPvToOmxTimeMap.clear();
    389     mSignalledError = false;
    390     mFramesConfigured = false;
    391     if (mInitialized) {
    392         PVCleanUpVideoDecoder(mHandle);
    393         mInitialized = false;
    394     }
    395 }
    396 
    397 void SoftMPEG4::updatePortDefinitions(bool updateCrop, bool updateInputSize) {
    398     SoftVideoDecoderOMXComponent::updatePortDefinitions(updateCrop, updateInputSize);
    399 
    400     /* We have to align our width and height - this should affect stride! */
    401     OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
    402     def->format.video.nStride = align(def->format.video.nStride, 16);
    403     def->format.video.nSliceHeight = align(def->format.video.nSliceHeight, 16);
    404     def->nBufferSize = (def->format.video.nStride * def->format.video.nSliceHeight * 3) / 2;
    405 }
    406 
    407 }  // namespace android
    408 
    409 android::SoftOMXComponent *createSoftOMXComponent(
    410         const char *name, const OMX_CALLBACKTYPE *callbacks,
    411         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    412     using namespace android;
    413     if (!strcmp(name, "OMX.google.h263.decoder")) {
    414         return new android::SoftMPEG4(
    415                 name, "video_decoder.h263", OMX_VIDEO_CodingH263,
    416                 kH263ProfileLevels, ARRAY_SIZE(kH263ProfileLevels),
    417                 callbacks, appData, component);
    418     } else if (!strcmp(name, "OMX.google.mpeg4.decoder")) {
    419         return new android::SoftMPEG4(
    420                 name, "video_decoder.mpeg4", OMX_VIDEO_CodingMPEG4,
    421                 kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels),
    422                 callbacks, appData, component);
    423     } else {
    424         CHECK(!"Unknown component");
    425     }
    426     return NULL;
    427 }
    428 
    429