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