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 
    107         PortInfo *port = editPortInfo(1);
    108 
    109         OMX_BUFFERHEADERTYPE *outHeader =
    110             port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
    111 
    112         if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
    113             inQueue.erase(inQueue.begin());
    114             inInfo->mOwnedByUs = false;
    115             notifyEmptyBufferDone(inHeader);
    116 
    117             ++mInputBufferCount;
    118 
    119             outHeader->nFilledLen = 0;
    120             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    121 
    122             List<BufferInfo *>::iterator it = outQueue.begin();
    123             while ((*it)->mHeader != outHeader) {
    124                 ++it;
    125             }
    126 
    127             BufferInfo *outInfo = *it;
    128             outInfo->mOwnedByUs = false;
    129             outQueue.erase(it);
    130             outInfo = NULL;
    131 
    132             notifyFillBufferDone(outHeader);
    133             outHeader = NULL;
    134             return;
    135         }
    136 
    137         uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
    138         uint32_t *start_code = (uint32_t *)bitstream;
    139         bool volHeader = *start_code == 0xB0010000;
    140         if (volHeader) {
    141             PVCleanUpVideoDecoder(mHandle);
    142             mInitialized = false;
    143         }
    144 
    145         if (!mInitialized) {
    146             uint8_t *vol_data[1];
    147             int32_t vol_size = 0;
    148 
    149             vol_data[0] = NULL;
    150 
    151             if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) {
    152                 vol_data[0] = bitstream;
    153                 vol_size = inHeader->nFilledLen;
    154             }
    155 
    156             MP4DecodingMode mode =
    157                 (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;
    158 
    159             Bool success = PVInitVideoDecoder(
    160                     mHandle, vol_data, &vol_size, 1,
    161                     outputBufferWidth(), outputBufferHeight(), mode);
    162 
    163             if (!success) {
    164                 ALOGW("PVInitVideoDecoder failed. Unsupported content?");
    165 
    166                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    167                 mSignalledError = true;
    168                 return;
    169             }
    170 
    171             MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
    172             if (mode != actualMode) {
    173                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    174                 mSignalledError = true;
    175                 return;
    176             }
    177 
    178             PVSetPostProcType((VideoDecControls *) mHandle, 0);
    179 
    180             bool hasFrameData = false;
    181             if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
    182                 inInfo->mOwnedByUs = false;
    183                 inQueue.erase(inQueue.begin());
    184                 inInfo = NULL;
    185                 notifyEmptyBufferDone(inHeader);
    186                 inHeader = NULL;
    187             } else if (volHeader) {
    188                 hasFrameData = true;
    189             }
    190 
    191             mInitialized = true;
    192 
    193             if (mode == MPEG4_MODE && handlePortSettingsChange()) {
    194                 return;
    195             }
    196 
    197             if (!hasFrameData) {
    198                 continue;
    199             }
    200         }
    201 
    202         if (!mFramesConfigured) {
    203             PortInfo *port = editPortInfo(1);
    204             OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
    205 
    206             PVSetReferenceYUV(mHandle, outHeader->pBuffer);
    207 
    208             mFramesConfigured = true;
    209         }
    210 
    211         uint32_t useExtTimestamp = (inHeader->nOffset == 0);
    212 
    213         // decoder deals in ms (int32_t), OMX in us (int64_t)
    214         // so use fake timestamp instead
    215         uint32_t timestamp = 0xFFFFFFFF;
    216         if (useExtTimestamp) {
    217             mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp);
    218             timestamp = mPvTime;
    219             mPvTime++;
    220         }
    221 
    222         int32_t bufferSize = inHeader->nFilledLen;
    223         int32_t tmp = bufferSize;
    224 
    225         // The PV decoder is lying to us, sometimes it'll claim to only have
    226         // consumed a subset of the buffer when it clearly consumed all of it.
    227         // ignore whatever it says...
    228         if (PVDecodeVideoFrame(
    229                     mHandle, &bitstream, &timestamp, &tmp,
    230                     &useExtTimestamp,
    231                     outHeader->pBuffer) != PV_TRUE) {
    232             ALOGE("failed to decode video frame.");
    233 
    234             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    235             mSignalledError = true;
    236             return;
    237         }
    238 
    239         // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
    240         // decoder may detect size change after PVDecodeVideoFrame.
    241         if (handlePortSettingsChange()) {
    242             return;
    243         }
    244 
    245         // decoder deals in ms, OMX in us.
    246         outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp);
    247         mPvToOmxTimeMap.removeItem(timestamp);
    248 
    249         inHeader->nOffset += bufferSize;
    250         inHeader->nFilledLen = 0;
    251         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    252             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    253         } else {
    254             outHeader->nFlags = 0;
    255         }
    256 
    257         if (inHeader->nFilledLen == 0) {
    258             inInfo->mOwnedByUs = false;
    259             inQueue.erase(inQueue.begin());
    260             inInfo = NULL;
    261             notifyEmptyBufferDone(inHeader);
    262             inHeader = NULL;
    263         }
    264 
    265         ++mInputBufferCount;
    266 
    267         outHeader->nOffset = 0;
    268         outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
    269 
    270         List<BufferInfo *>::iterator it = outQueue.begin();
    271         while ((*it)->mHeader != outHeader) {
    272             ++it;
    273         }
    274 
    275         BufferInfo *outInfo = *it;
    276         outInfo->mOwnedByUs = false;
    277         outQueue.erase(it);
    278         outInfo = NULL;
    279 
    280         notifyFillBufferDone(outHeader);
    281         outHeader = NULL;
    282 
    283         ++mNumSamplesOutput;
    284     }
    285 }
    286 
    287 bool SoftMPEG4::handlePortSettingsChange() {
    288     uint32_t disp_width, disp_height;
    289     PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height);
    290 
    291     uint32_t buf_width, buf_height;
    292     PVGetBufferDimensions(mHandle, (int32 *)&buf_width, (int32 *)&buf_height);
    293 
    294     CHECK_LE(disp_width, buf_width);
    295     CHECK_LE(disp_height, buf_height);
    296 
    297     ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
    298             disp_width, disp_height, buf_width, buf_height);
    299 
    300     CropSettingsMode cropSettingsMode = kCropUnSet;
    301     if (disp_width != buf_width || disp_height != buf_height) {
    302         cropSettingsMode = kCropSet;
    303 
    304         if (mCropWidth != disp_width || mCropHeight != disp_height) {
    305             mCropLeft = 0;
    306             mCropTop = 0;
    307             mCropWidth = disp_width;
    308             mCropHeight = disp_height;
    309             cropSettingsMode = kCropChanged;
    310         }
    311     }
    312 
    313     bool portWillReset = false;
    314     const bool fakeStride = true;
    315     SoftVideoDecoderOMXComponent::handlePortSettingsChange(
    316             &portWillReset, buf_width, buf_height, cropSettingsMode, fakeStride);
    317     if (portWillReset) {
    318         if (mMode == MODE_H263) {
    319             PVCleanUpVideoDecoder(mHandle);
    320 
    321             uint8_t *vol_data[1];
    322             int32_t vol_size = 0;
    323 
    324             vol_data[0] = NULL;
    325             if (!PVInitVideoDecoder(
    326                     mHandle, vol_data, &vol_size, 1, outputBufferWidth(), outputBufferHeight(),
    327                     H263_MODE)) {
    328                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    329                 mSignalledError = true;
    330                 return true;
    331             }
    332         }
    333 
    334         mFramesConfigured = false;
    335     }
    336 
    337     return portWillReset;
    338 }
    339 
    340 void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
    341     if (portIndex == 0 && mInitialized) {
    342         CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
    343     }
    344 }
    345 
    346 void SoftMPEG4::onReset() {
    347     SoftVideoDecoderOMXComponent::onReset();
    348     mPvToOmxTimeMap.clear();
    349     mSignalledError = false;
    350     mFramesConfigured = false;
    351     if (mInitialized) {
    352         PVCleanUpVideoDecoder(mHandle);
    353         mInitialized = false;
    354     }
    355 }
    356 
    357 void SoftMPEG4::updatePortDefinitions(bool updateCrop, bool updateInputSize) {
    358     SoftVideoDecoderOMXComponent::updatePortDefinitions(updateCrop, updateInputSize);
    359 
    360     /* We have to align our width and height - this should affect stride! */
    361     OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
    362     def->format.video.nStride = align(def->format.video.nStride, 16);
    363     def->format.video.nSliceHeight = align(def->format.video.nSliceHeight, 16);
    364     def->nBufferSize = (def->format.video.nStride * def->format.video.nSliceHeight * 3) / 2;
    365 }
    366 
    367 }  // namespace android
    368 
    369 android::SoftOMXComponent *createSoftOMXComponent(
    370         const char *name, const OMX_CALLBACKTYPE *callbacks,
    371         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    372     using namespace android;
    373     if (!strcmp(name, "OMX.google.h263.decoder")) {
    374         return new android::SoftMPEG4(
    375                 name, "video_decoder.h263", OMX_VIDEO_CodingH263,
    376                 kH263ProfileLevels, ARRAY_SIZE(kH263ProfileLevels),
    377                 callbacks, appData, component);
    378     } else if (!strcmp(name, "OMX.google.mpeg4.decoder")) {
    379         return new android::SoftMPEG4(
    380                 name, "video_decoder.mpeg4", OMX_VIDEO_CodingMPEG4,
    381                 kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels),
    382                 callbacks, appData, component);
    383     } else {
    384         CHECK(!"Unknown component");
    385     }
    386     return NULL;
    387 }
    388 
    389