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 template<class T>
     52 static void InitOMXParams(T *params) {
     53     params->nSize = sizeof(T);
     54     params->nVersion.s.nVersionMajor = 1;
     55     params->nVersion.s.nVersionMinor = 0;
     56     params->nVersion.s.nRevision = 0;
     57     params->nVersion.s.nStep = 0;
     58 }
     59 
     60 SoftMPEG4::SoftMPEG4(
     61         const char *name,
     62         const OMX_CALLBACKTYPE *callbacks,
     63         OMX_PTR appData,
     64         OMX_COMPONENTTYPE **component)
     65     : SimpleSoftOMXComponent(name, callbacks, appData, component),
     66       mMode(MODE_MPEG4),
     67       mHandle(new tagvideoDecControls),
     68       mInputBufferCount(0),
     69       mWidth(352),
     70       mHeight(288),
     71       mCropLeft(0),
     72       mCropTop(0),
     73       mCropRight(mWidth - 1),
     74       mCropBottom(mHeight - 1),
     75       mSignalledError(false),
     76       mInitialized(false),
     77       mFramesConfigured(false),
     78       mNumSamplesOutput(0),
     79       mOutputPortSettingsChange(NONE) {
     80     if (!strcmp(name, "OMX.google.h263.decoder")) {
     81         mMode = MODE_H263;
     82     } else {
     83         CHECK(!strcmp(name, "OMX.google.mpeg4.decoder"));
     84     }
     85 
     86     initPorts();
     87     CHECK_EQ(initDecoder(), (status_t)OK);
     88 }
     89 
     90 SoftMPEG4::~SoftMPEG4() {
     91     if (mInitialized) {
     92         PVCleanUpVideoDecoder(mHandle);
     93     }
     94 
     95     delete mHandle;
     96     mHandle = NULL;
     97 }
     98 
     99 void SoftMPEG4::initPorts() {
    100     OMX_PARAM_PORTDEFINITIONTYPE def;
    101     InitOMXParams(&def);
    102 
    103     def.nPortIndex = 0;
    104     def.eDir = OMX_DirInput;
    105     def.nBufferCountMin = kNumInputBuffers;
    106     def.nBufferCountActual = def.nBufferCountMin;
    107     def.nBufferSize = 8192;
    108     def.bEnabled = OMX_TRUE;
    109     def.bPopulated = OMX_FALSE;
    110     def.eDomain = OMX_PortDomainVideo;
    111     def.bBuffersContiguous = OMX_FALSE;
    112     def.nBufferAlignment = 1;
    113 
    114     def.format.video.cMIMEType =
    115         (mMode == MODE_MPEG4)
    116             ? const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4)
    117             : const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263);
    118 
    119     def.format.video.pNativeRender = NULL;
    120     def.format.video.nFrameWidth = mWidth;
    121     def.format.video.nFrameHeight = mHeight;
    122     def.format.video.nStride = def.format.video.nFrameWidth;
    123     def.format.video.nSliceHeight = def.format.video.nFrameHeight;
    124     def.format.video.nBitrate = 0;
    125     def.format.video.xFramerate = 0;
    126     def.format.video.bFlagErrorConcealment = OMX_FALSE;
    127 
    128     def.format.video.eCompressionFormat =
    129         mMode == MODE_MPEG4 ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263;
    130 
    131     def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
    132     def.format.video.pNativeWindow = NULL;
    133 
    134     addPort(def);
    135 
    136     def.nPortIndex = 1;
    137     def.eDir = OMX_DirOutput;
    138     def.nBufferCountMin = kNumOutputBuffers;
    139     def.nBufferCountActual = def.nBufferCountMin;
    140     def.bEnabled = OMX_TRUE;
    141     def.bPopulated = OMX_FALSE;
    142     def.eDomain = OMX_PortDomainVideo;
    143     def.bBuffersContiguous = OMX_FALSE;
    144     def.nBufferAlignment = 2;
    145 
    146     def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
    147     def.format.video.pNativeRender = NULL;
    148     def.format.video.nFrameWidth = mWidth;
    149     def.format.video.nFrameHeight = mHeight;
    150     def.format.video.nStride = def.format.video.nFrameWidth;
    151     def.format.video.nSliceHeight = def.format.video.nFrameHeight;
    152     def.format.video.nBitrate = 0;
    153     def.format.video.xFramerate = 0;
    154     def.format.video.bFlagErrorConcealment = OMX_FALSE;
    155     def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
    156     def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
    157     def.format.video.pNativeWindow = NULL;
    158 
    159     def.nBufferSize =
    160         (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
    161 
    162     addPort(def);
    163 }
    164 
    165 status_t SoftMPEG4::initDecoder() {
    166     memset(mHandle, 0, sizeof(tagvideoDecControls));
    167     return OK;
    168 }
    169 
    170 OMX_ERRORTYPE SoftMPEG4::internalGetParameter(
    171         OMX_INDEXTYPE index, OMX_PTR params) {
    172     switch (index) {
    173         case OMX_IndexParamVideoPortFormat:
    174         {
    175             OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
    176                 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
    177 
    178             if (formatParams->nPortIndex > 1) {
    179                 return OMX_ErrorUndefined;
    180             }
    181 
    182             if (formatParams->nIndex != 0) {
    183                 return OMX_ErrorNoMore;
    184             }
    185 
    186             if (formatParams->nPortIndex == 0) {
    187                 formatParams->eCompressionFormat =
    188                     (mMode == MODE_MPEG4)
    189                         ? OMX_VIDEO_CodingMPEG4 : OMX_VIDEO_CodingH263;
    190 
    191                 formatParams->eColorFormat = OMX_COLOR_FormatUnused;
    192                 formatParams->xFramerate = 0;
    193             } else {
    194                 CHECK_EQ(formatParams->nPortIndex, 1u);
    195 
    196                 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
    197                 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
    198                 formatParams->xFramerate = 0;
    199             }
    200 
    201             return OMX_ErrorNone;
    202         }
    203 
    204         case OMX_IndexParamVideoProfileLevelQuerySupported:
    205         {
    206             OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
    207                     (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
    208 
    209             if (profileLevel->nPortIndex != 0) {  // Input port only
    210                 ALOGE("Invalid port index: %ld", profileLevel->nPortIndex);
    211                 return OMX_ErrorUnsupportedIndex;
    212             }
    213 
    214             size_t index = profileLevel->nProfileIndex;
    215             if (mMode == MODE_H263) {
    216                 size_t nProfileLevels =
    217                     sizeof(kH263ProfileLevels) / sizeof(kH263ProfileLevels[0]);
    218                 if (index >= nProfileLevels) {
    219                     return OMX_ErrorNoMore;
    220                 }
    221 
    222                 profileLevel->eProfile = kH263ProfileLevels[index].mProfile;
    223                 profileLevel->eLevel = kH263ProfileLevels[index].mLevel;
    224             } else {
    225                 size_t nProfileLevels =
    226                     sizeof(kM4VProfileLevels) / sizeof(kM4VProfileLevels[0]);
    227                 if (index >= nProfileLevels) {
    228                     return OMX_ErrorNoMore;
    229                 }
    230 
    231                 profileLevel->eProfile = kM4VProfileLevels[index].mProfile;
    232                 profileLevel->eLevel = kM4VProfileLevels[index].mLevel;
    233             }
    234             return OMX_ErrorNone;
    235         }
    236 
    237         default:
    238             return SimpleSoftOMXComponent::internalGetParameter(index, params);
    239     }
    240 }
    241 
    242 OMX_ERRORTYPE SoftMPEG4::internalSetParameter(
    243         OMX_INDEXTYPE index, const OMX_PTR params) {
    244     switch (index) {
    245         case OMX_IndexParamStandardComponentRole:
    246         {
    247             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
    248                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
    249 
    250             if (mMode == MODE_MPEG4) {
    251                 if (strncmp((const char *)roleParams->cRole,
    252                             "video_decoder.mpeg4",
    253                             OMX_MAX_STRINGNAME_SIZE - 1)) {
    254                     return OMX_ErrorUndefined;
    255                 }
    256             } else {
    257                 if (strncmp((const char *)roleParams->cRole,
    258                             "video_decoder.h263",
    259                             OMX_MAX_STRINGNAME_SIZE - 1)) {
    260                     return OMX_ErrorUndefined;
    261                 }
    262             }
    263 
    264             return OMX_ErrorNone;
    265         }
    266 
    267         case OMX_IndexParamVideoPortFormat:
    268         {
    269             OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
    270                 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
    271 
    272             if (formatParams->nPortIndex > 1) {
    273                 return OMX_ErrorUndefined;
    274             }
    275 
    276             if (formatParams->nIndex != 0) {
    277                 return OMX_ErrorNoMore;
    278             }
    279 
    280             return OMX_ErrorNone;
    281         }
    282 
    283         default:
    284             return SimpleSoftOMXComponent::internalSetParameter(index, params);
    285     }
    286 }
    287 
    288 OMX_ERRORTYPE SoftMPEG4::getConfig(
    289         OMX_INDEXTYPE index, OMX_PTR params) {
    290     switch (index) {
    291         case OMX_IndexConfigCommonOutputCrop:
    292         {
    293             OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
    294 
    295             if (rectParams->nPortIndex != 1) {
    296                 return OMX_ErrorUndefined;
    297             }
    298 
    299             rectParams->nLeft = mCropLeft;
    300             rectParams->nTop = mCropTop;
    301             rectParams->nWidth = mCropRight - mCropLeft + 1;
    302             rectParams->nHeight = mCropBottom - mCropTop + 1;
    303 
    304             return OMX_ErrorNone;
    305         }
    306 
    307         default:
    308             return OMX_ErrorUnsupportedIndex;
    309     }
    310 }
    311 
    312 void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) {
    313     if (mSignalledError || mOutputPortSettingsChange != NONE) {
    314         return;
    315     }
    316 
    317     List<BufferInfo *> &inQueue = getPortQueue(0);
    318     List<BufferInfo *> &outQueue = getPortQueue(1);
    319 
    320     while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) {
    321         BufferInfo *inInfo = *inQueue.begin();
    322         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    323 
    324         PortInfo *port = editPortInfo(1);
    325 
    326         OMX_BUFFERHEADERTYPE *outHeader =
    327             port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader;
    328 
    329         if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
    330             inQueue.erase(inQueue.begin());
    331             inInfo->mOwnedByUs = false;
    332             notifyEmptyBufferDone(inHeader);
    333 
    334             ++mInputBufferCount;
    335 
    336             outHeader->nFilledLen = 0;
    337             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    338 
    339             List<BufferInfo *>::iterator it = outQueue.begin();
    340             while ((*it)->mHeader != outHeader) {
    341                 ++it;
    342             }
    343 
    344             BufferInfo *outInfo = *it;
    345             outInfo->mOwnedByUs = false;
    346             outQueue.erase(it);
    347             outInfo = NULL;
    348 
    349             notifyFillBufferDone(outHeader);
    350             outHeader = NULL;
    351             return;
    352         }
    353 
    354         uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset;
    355 
    356         if (!mInitialized) {
    357             uint8_t *vol_data[1];
    358             int32_t vol_size = 0;
    359 
    360             vol_data[0] = NULL;
    361 
    362             if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
    363                 vol_data[0] = bitstream;
    364                 vol_size = inHeader->nFilledLen;
    365             }
    366 
    367             MP4DecodingMode mode =
    368                 (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE;
    369 
    370             Bool success = PVInitVideoDecoder(
    371                     mHandle, vol_data, &vol_size, 1, mWidth, mHeight, mode);
    372 
    373             if (!success) {
    374                 ALOGW("PVInitVideoDecoder failed. Unsupported content?");
    375 
    376                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    377                 mSignalledError = true;
    378                 return;
    379             }
    380 
    381             MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle);
    382             if (mode != actualMode) {
    383                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    384                 mSignalledError = true;
    385                 return;
    386             }
    387 
    388             PVSetPostProcType((VideoDecControls *) mHandle, 0);
    389 
    390             if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
    391                 inInfo->mOwnedByUs = false;
    392                 inQueue.erase(inQueue.begin());
    393                 inInfo = NULL;
    394                 notifyEmptyBufferDone(inHeader);
    395                 inHeader = NULL;
    396             }
    397 
    398             mInitialized = true;
    399 
    400             if (mode == MPEG4_MODE && portSettingsChanged()) {
    401                 return;
    402             }
    403 
    404             continue;
    405         }
    406 
    407         if (!mFramesConfigured) {
    408             PortInfo *port = editPortInfo(1);
    409             OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader;
    410 
    411             PVSetReferenceYUV(mHandle, outHeader->pBuffer);
    412 
    413             mFramesConfigured = true;
    414         }
    415 
    416         uint32_t useExtTimestamp = (inHeader->nOffset == 0);
    417 
    418         // decoder deals in ms, OMX in us.
    419         uint32_t timestamp =
    420             useExtTimestamp ? (inHeader->nTimeStamp + 500) / 1000 : 0xFFFFFFFF;
    421 
    422         int32_t bufferSize = inHeader->nFilledLen;
    423         int32_t tmp = bufferSize;
    424 
    425         // The PV decoder is lying to us, sometimes it'll claim to only have
    426         // consumed a subset of the buffer when it clearly consumed all of it.
    427         // ignore whatever it says...
    428         if (PVDecodeVideoFrame(
    429                     mHandle, &bitstream, &timestamp, &tmp,
    430                     &useExtTimestamp,
    431                     outHeader->pBuffer) != PV_TRUE) {
    432             ALOGE("failed to decode video frame.");
    433 
    434             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    435             mSignalledError = true;
    436             return;
    437         }
    438 
    439         if (portSettingsChanged()) {
    440             return;
    441         }
    442 
    443         // decoder deals in ms, OMX in us.
    444         outHeader->nTimeStamp = timestamp * 1000;
    445 
    446         inHeader->nOffset += bufferSize;
    447         inHeader->nFilledLen = 0;
    448         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    449             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    450         } else {
    451             outHeader->nFlags = 0;
    452         }
    453 
    454         if (inHeader->nFilledLen == 0) {
    455             inInfo->mOwnedByUs = false;
    456             inQueue.erase(inQueue.begin());
    457             inInfo = NULL;
    458             notifyEmptyBufferDone(inHeader);
    459             inHeader = NULL;
    460         }
    461 
    462         ++mInputBufferCount;
    463 
    464         outHeader->nOffset = 0;
    465         outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
    466 
    467         List<BufferInfo *>::iterator it = outQueue.begin();
    468         while ((*it)->mHeader != outHeader) {
    469             ++it;
    470         }
    471 
    472         BufferInfo *outInfo = *it;
    473         outInfo->mOwnedByUs = false;
    474         outQueue.erase(it);
    475         outInfo = NULL;
    476 
    477         notifyFillBufferDone(outHeader);
    478         outHeader = NULL;
    479 
    480         ++mNumSamplesOutput;
    481     }
    482 }
    483 
    484 bool SoftMPEG4::portSettingsChanged() {
    485     int32_t disp_width, disp_height;
    486     PVGetVideoDimensions(mHandle, &disp_width, &disp_height);
    487 
    488     int32_t buf_width, buf_height;
    489     PVGetBufferDimensions(mHandle, &buf_width, &buf_height);
    490 
    491     CHECK_LE(disp_width, buf_width);
    492     CHECK_LE(disp_height, buf_height);
    493 
    494     ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d",
    495             disp_width, disp_height, buf_width, buf_height);
    496 
    497     if (mCropRight != disp_width - 1
    498             || mCropBottom != disp_height - 1) {
    499         mCropLeft = 0;
    500         mCropTop = 0;
    501         mCropRight = disp_width - 1;
    502         mCropBottom = disp_height - 1;
    503 
    504         notify(OMX_EventPortSettingsChanged,
    505                1,
    506                OMX_IndexConfigCommonOutputCrop,
    507                NULL);
    508     }
    509 
    510     if (buf_width != mWidth || buf_height != mHeight) {
    511         mWidth = buf_width;
    512         mHeight = buf_height;
    513 
    514         updatePortDefinitions();
    515 
    516         if (mMode == MODE_H263) {
    517             PVCleanUpVideoDecoder(mHandle);
    518 
    519             uint8_t *vol_data[1];
    520             int32_t vol_size = 0;
    521 
    522             vol_data[0] = NULL;
    523             if (!PVInitVideoDecoder(
    524                     mHandle, vol_data, &vol_size, 1, mWidth, mHeight,
    525                     H263_MODE)) {
    526                 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    527                 mSignalledError = true;
    528                 return true;
    529             }
    530         }
    531 
    532         mFramesConfigured = false;
    533 
    534         notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
    535         mOutputPortSettingsChange = AWAITING_DISABLED;
    536         return true;
    537     }
    538 
    539     return false;
    540 }
    541 
    542 void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) {
    543     if (portIndex == 0 && mInitialized) {
    544         CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE);
    545     }
    546 }
    547 
    548 void SoftMPEG4::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
    549     if (portIndex != 1) {
    550         return;
    551     }
    552 
    553     switch (mOutputPortSettingsChange) {
    554         case NONE:
    555             break;
    556 
    557         case AWAITING_DISABLED:
    558         {
    559             CHECK(!enabled);
    560             mOutputPortSettingsChange = AWAITING_ENABLED;
    561             break;
    562         }
    563 
    564         default:
    565         {
    566             CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
    567             CHECK(enabled);
    568             mOutputPortSettingsChange = NONE;
    569             break;
    570         }
    571     }
    572 }
    573 
    574 void SoftMPEG4::updatePortDefinitions() {
    575     OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
    576     def->format.video.nFrameWidth = mWidth;
    577     def->format.video.nFrameHeight = mHeight;
    578     def->format.video.nStride = def->format.video.nFrameWidth;
    579     def->format.video.nSliceHeight = def->format.video.nFrameHeight;
    580 
    581     def = &editPortInfo(1)->mDef;
    582     def->format.video.nFrameWidth = mWidth;
    583     def->format.video.nFrameHeight = mHeight;
    584     def->format.video.nStride = def->format.video.nFrameWidth;
    585     def->format.video.nSliceHeight = def->format.video.nFrameHeight;
    586 
    587     def->nBufferSize =
    588         (((def->format.video.nFrameWidth + 15) & -16)
    589             * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2;
    590 }
    591 
    592 }  // namespace android
    593 
    594 android::SoftOMXComponent *createSoftOMXComponent(
    595         const char *name, const OMX_CALLBACKTYPE *callbacks,
    596         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    597     return new android::SoftMPEG4(name, callbacks, appData, component);
    598 }
    599 
    600