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