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/MediaDefs.h>
     25 #include <media/stagefright/MediaErrors.h>
     26 #include <media/IOMX.h>
     27 
     28 #include "mp4dec_api.h"
     29 
     30 namespace android {
     31 
     32 static const CodecProfileLevel kM4VProfileLevels[] = {
     33     { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 },
     34     { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b },
     35     { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 },
     36     { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 },
     37     { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 },
     38 };
     39 
     40 static const CodecProfileLevel kH263ProfileLevels[] = {
     41     { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10 },
     42     { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level20 },
     43     { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 },
     44     { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 },
     45     { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level10 },
     46     { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level20 },
     47     { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level30 },
     48     { OMX_VIDEO_H263ProfileISWV2,    OMX_VIDEO_H263Level45 },
     49 };
     50 
     51 SoftMPEG4::SoftMPEG4(
     52         const char *name,
     53         const char *componentRole,
     54         OMX_VIDEO_CODINGTYPE codingType,
     55         const CodecProfileLevel *profileLevels,
     56         size_t numProfileLevels,
     57         const OMX_CALLBACKTYPE *callbacks,
     58         OMX_PTR appData,
     59         OMX_COMPONENTTYPE **component)
     60     : SoftVideoDecoderOMXComponent(
     61             name, componentRole, codingType, profileLevels, numProfileLevels,
     62             352 /* width */, 288 /* height */, callbacks, appData, component),
     63       mMode(codingType == OMX_VIDEO_CodingH263 ? MODE_H263 : MODE_MPEG4),
     64       mHandle(new tagvideoDecControls),
     65       mInputBufferCount(0),
     66       mSignalledError(false),
     67       mInitialized(false),
     68       mFramesConfigured(false),
     69       mNumSamplesOutput(0),
     70       mPvTime(0) {
     71     initPorts(
     72             kNumInputBuffers,
     73             8192 /* inputBufferSize */,
     74             kNumOutputBuffers,
     75             (mMode == MODE_MPEG4)
     76             ? MEDIA_MIMETYPE_VIDEO_MPEG4 : MEDIA_MIMETYPE_VIDEO_H263);
     77     CHECK_EQ(initDecoder(), (status_t)OK);
     78 }
     79 
     80 SoftMPEG4::~SoftMPEG4() {
     81     if (mInitialized) {
     82         PVCleanUpVideoDecoder(mHandle);
     83     }
     84 
     85     delete mHandle;
     86     mHandle = NULL;
     87 }
     88 
     89 status_t SoftMPEG4::initDecoder() {
     90     memset(mHandle, 0, sizeof(tagvideoDecControls));
     91     return OK;
     92 }
     93 
     94 void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) {
     95     if (mSignalledError || mOutputPortSettingsChange != NONE) {
     96         return;
     97     }
     98 
     99     List<BufferInfo *> &inQueue = getPortQueue(0);
    100     List<BufferInfo *> &outQueue = getPortQueue(1);
    101 
    102     while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
    103         BufferInfo *inInfo = *inQueue.begin();
    104         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    105 
    106         PortInfo *port = editPortInfo(1);
    107 
    108         OMX_BUFFERHEADERTYPE *outHeader =
    109             port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
    110 
    111         if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
    112             inQueue.erase(inQueue.begin());
    113             inInfo->mOwnedByUs = false;
    114             notifyEmptyBufferDone(inHeader);
    115 
    116             ++mInputBufferCount;
    117 
    118             outHeader->nFilledLen = 0;
    119             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    120 
    121             List<BufferInfo *>::iterator it = outQueue.begin();
    122             while ((*it)->mHeader != outHeader) {
    123                 ++it;
    124             }
    125 
    126             BufferInfo *outInfo = *it;
    127             outInfo->mOwnedByUs = false;
    128             outQueue.erase(it);
    129             outInfo = NULL;
    130 
    131             notifyFillBufferDone(outHeader);
    132             outHeader = NULL;
    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             PVSetReferenceYUV(mHandle, outHeader->pBuffer);
    206 
    207             mFramesConfigured = true;
    208         }
    209 
    210         uint32_t useExtTimestamp = (inHeader->nOffset == 0);
    211 
    212         // decoder deals in ms (int32_t), OMX in us (int64_t)
    213         // so use fake timestamp instead
    214         uint32_t timestamp = 0xFFFFFFFF;
    215         if (useExtTimestamp) {
    216             mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp);
    217             timestamp = mPvTime;
    218             mPvTime++;
    219         }
    220 
    221         int32_t bufferSize = inHeader->nFilledLen;
    222         int32_t tmp = bufferSize;
    223 
    224         // The PV decoder is lying to us, sometimes it'll claim to only have
    225         // consumed a subset of the buffer when it clearly consumed all of it.
    226         // ignore whatever it says...
    227         if (PVDecodeVideoFrame(
    228                     mHandle, &bitstream, &timestamp, &tmp,
    229                     &useExtTimestamp,
    230                     outHeader->pBuffer) != PV_TRUE) {
    231             ALOGE("failed to decode video frame.");
    232 
    233             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    234             mSignalledError = true;
    235             return;
    236         }
    237 
    238         // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
    239         // decoder may detect size change after PVDecodeVideoFrame.
    240         if (handlePortSettingsChange()) {
    241             return;
    242         }
    243 
    244         // decoder deals in ms, OMX in us.
    245         outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp);
    246         mPvToOmxTimeMap.removeItem(timestamp);
    247 
    248         inHeader->nOffset += bufferSize;
    249         inHeader->nFilledLen = 0;
    250         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    251             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    252         } else {
    253             outHeader->nFlags = 0;
    254         }
    255 
    256         if (inHeader->nFilledLen == 0) {
    257             inInfo->mOwnedByUs = false;
    258             inQueue.erase(inQueue.begin());
    259             inInfo = NULL;
    260             notifyEmptyBufferDone(inHeader);
    261             inHeader = NULL;
    262         }
    263 
    264         ++mInputBufferCount;
    265 
    266         outHeader->nOffset = 0;
    267         outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
    268 
    269         List<BufferInfo *>::iterator it = outQueue.begin();
    270         while ((*it)->mHeader != outHeader) {
    271             ++it;
    272         }
    273 
    274         BufferInfo *outInfo = *it;
    275         outInfo->mOwnedByUs = false;
    276         outQueue.erase(it);
    277         outInfo = NULL;
    278 
    279         notifyFillBufferDone(outHeader);
    280         outHeader = NULL;
    281 
    282         ++mNumSamplesOutput;
    283     }
    284 }
    285 
    286 bool SoftMPEG4::handlePortSettingsChange() {
    287     uint32_t disp_width, disp_height;
    288     PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height);
    289 
    290     uint32_t buf_width, buf_height;
    291     PVGetBufferDimensions(mHandle, (int32 *)&buf_width, (int32 *)&buf_height);
    292 
    293     CHECK_LE(disp_width, buf_width);
    294     CHECK_LE(disp_height, buf_height);
    295 
    296     ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
    297             disp_width, disp_height, buf_width, buf_height);
    298 
    299     CropSettingsMode cropSettingsMode = kCropUnSet;
    300     if (disp_width != buf_width || disp_height != buf_height) {
    301         cropSettingsMode = kCropSet;
    302 
    303         if (mCropWidth != disp_width || mCropHeight != disp_height) {
    304             mCropLeft = 0;
    305             mCropTop = 0;
    306             mCropWidth = disp_width;
    307             mCropHeight = disp_height;
    308             cropSettingsMode = kCropChanged;
    309         }
    310     }
    311 
    312     bool portWillReset = false;
    313     const bool fakeStride = true;
    314     SoftVideoDecoderOMXComponent::handlePortSettingsChange(
    315             &portWillReset, buf_width, buf_height, cropSettingsMode, fakeStride);
    316     if (portWillReset) {
    317         if (mMode == MODE_H263) {
    318             PVCleanUpVideoDecoder(mHandle);
    319 
    320             uint8_t *vol_data[1];
    321             int32_t vol_size = 0;
    322 
    323             vol_data[0] = NULL;
    324             if (!PVInitVideoDecoder(
    325                     mHandle, vol_data, &vol_size, 1, outputBufferWidth(), outputBufferHeight(),
    326                     H263_MODE)) {
    327                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    328                 mSignalledError = true;
    329                 return true;
    330             }
    331         }
    332 
    333         mFramesConfigured = false;
    334     }
    335 
    336     return portWillReset;
    337 }
    338 
    339 void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
    340     if (portIndex == 0 && mInitialized) {
    341         CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
    342     }
    343 }
    344 
    345 void SoftMPEG4::onReset() {
    346     SoftVideoDecoderOMXComponent::onReset();
    347     mPvToOmxTimeMap.clear();
    348     mSignalledError = false;
    349     mFramesConfigured = false;
    350     if (mInitialized) {
    351         PVCleanUpVideoDecoder(mHandle);
    352         mInitialized = false;
    353     }
    354 }
    355 
    356 void SoftMPEG4::updatePortDefinitions() {
    357     SoftVideoDecoderOMXComponent::updatePortDefinitions();
    358 
    359     /* We have to align our width and height - this should affect stride! */
    360     OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
    361     def->nBufferSize =
    362         (((def->format.video.nFrameWidth + 15) & -16)
    363             * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2;
    364 }
    365 
    366 }  // namespace android
    367 
    368 android::SoftOMXComponent *createSoftOMXComponent(
    369         const char *name, const OMX_CALLBACKTYPE *callbacks,
    370         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    371     using namespace android;
    372     if (!strcmp(name, "OMX.google.h263.decoder")) {
    373         return new android::SoftMPEG4(
    374                 name, "video_decoder.h263", OMX_VIDEO_CodingH263,
    375                 kH263ProfileLevels, ARRAY_SIZE(kH263ProfileLevels),
    376                 callbacks, appData, component);
    377     } else if (!strcmp(name, "OMX.google.mpeg4.decoder")) {
    378         return new android::SoftMPEG4(
    379                 name, "video_decoder.mpeg4", OMX_VIDEO_CodingMPEG4,
    380                 kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels),
    381                 callbacks, appData, component);
    382     } else {
    383         CHECK(!"Unknown component");
    384     }
    385 }
    386 
    387