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 "SoftVPX"
     19 #include <utils/Log.h>
     20 
     21 #include "SoftVPX.h"
     22 
     23 #include <media/stagefright/foundation/ADebug.h>
     24 #include <media/stagefright/MediaDefs.h>
     25 
     26 #include "vpx/vpx_decoder.h"
     27 #include "vpx/vpx_codec.h"
     28 #include "vpx/vp8dx.h"
     29 
     30 namespace android {
     31 
     32 template<class T>
     33 static void InitOMXParams(T *params) {
     34     params->nSize = sizeof(T);
     35     params->nVersion.s.nVersionMajor = 1;
     36     params->nVersion.s.nVersionMinor = 0;
     37     params->nVersion.s.nRevision = 0;
     38     params->nVersion.s.nStep = 0;
     39 }
     40 
     41 SoftVPX::SoftVPX(
     42         const char *name,
     43         const OMX_CALLBACKTYPE *callbacks,
     44         OMX_PTR appData,
     45         OMX_COMPONENTTYPE **component)
     46     : SimpleSoftOMXComponent(name, callbacks, appData, component),
     47       mCtx(NULL),
     48       mWidth(320),
     49       mHeight(240),
     50       mOutputPortSettingsChange(NONE) {
     51     initPorts();
     52     CHECK_EQ(initDecoder(), (status_t)OK);
     53 }
     54 
     55 SoftVPX::~SoftVPX() {
     56     vpx_codec_destroy((vpx_codec_ctx_t *)mCtx);
     57     delete (vpx_codec_ctx_t *)mCtx;
     58     mCtx = NULL;
     59 }
     60 
     61 void SoftVPX::initPorts() {
     62     OMX_PARAM_PORTDEFINITIONTYPE def;
     63     InitOMXParams(&def);
     64 
     65     def.nPortIndex = 0;
     66     def.eDir = OMX_DirInput;
     67     def.nBufferCountMin = kNumBuffers;
     68     def.nBufferCountActual = def.nBufferCountMin;
     69     def.nBufferSize = 768 * 1024;
     70     def.bEnabled = OMX_TRUE;
     71     def.bPopulated = OMX_FALSE;
     72     def.eDomain = OMX_PortDomainVideo;
     73     def.bBuffersContiguous = OMX_FALSE;
     74     def.nBufferAlignment = 1;
     75 
     76     def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VPX);
     77     def.format.video.pNativeRender = NULL;
     78     def.format.video.nFrameWidth = mWidth;
     79     def.format.video.nFrameHeight = mHeight;
     80     def.format.video.nStride = def.format.video.nFrameWidth;
     81     def.format.video.nSliceHeight = def.format.video.nFrameHeight;
     82     def.format.video.nBitrate = 0;
     83     def.format.video.xFramerate = 0;
     84     def.format.video.bFlagErrorConcealment = OMX_FALSE;
     85     def.format.video.eCompressionFormat = OMX_VIDEO_CodingVPX;
     86     def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
     87     def.format.video.pNativeWindow = NULL;
     88 
     89     addPort(def);
     90 
     91     def.nPortIndex = 1;
     92     def.eDir = OMX_DirOutput;
     93     def.nBufferCountMin = kNumBuffers;
     94     def.nBufferCountActual = def.nBufferCountMin;
     95     def.bEnabled = OMX_TRUE;
     96     def.bPopulated = OMX_FALSE;
     97     def.eDomain = OMX_PortDomainVideo;
     98     def.bBuffersContiguous = OMX_FALSE;
     99     def.nBufferAlignment = 2;
    100 
    101     def.format.video.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
    102     def.format.video.pNativeRender = NULL;
    103     def.format.video.nFrameWidth = mWidth;
    104     def.format.video.nFrameHeight = mHeight;
    105     def.format.video.nStride = def.format.video.nFrameWidth;
    106     def.format.video.nSliceHeight = def.format.video.nFrameHeight;
    107     def.format.video.nBitrate = 0;
    108     def.format.video.xFramerate = 0;
    109     def.format.video.bFlagErrorConcealment = OMX_FALSE;
    110     def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
    111     def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar;
    112     def.format.video.pNativeWindow = NULL;
    113 
    114     def.nBufferSize =
    115         (def.format.video.nFrameWidth * def.format.video.nFrameHeight * 3) / 2;
    116 
    117     addPort(def);
    118 }
    119 
    120 static int GetCPUCoreCount() {
    121     int cpuCoreCount = 1;
    122 #if defined(_SC_NPROCESSORS_ONLN)
    123     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
    124 #else
    125     // _SC_NPROC_ONLN must be defined...
    126     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
    127 #endif
    128     CHECK(cpuCoreCount >= 1);
    129     ALOGV("Number of CPU cores: %d", cpuCoreCount);
    130     return cpuCoreCount;
    131 }
    132 
    133 status_t SoftVPX::initDecoder() {
    134     mCtx = new vpx_codec_ctx_t;
    135     vpx_codec_err_t vpx_err;
    136     vpx_codec_dec_cfg_t cfg;
    137     memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
    138     cfg.threads = GetCPUCoreCount();
    139     if ((vpx_err = vpx_codec_dec_init(
    140                 (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, &cfg, 0))) {
    141         ALOGE("on2 decoder failed to initialize. (%d)", vpx_err);
    142         return UNKNOWN_ERROR;
    143     }
    144 
    145     return OK;
    146 }
    147 
    148 OMX_ERRORTYPE SoftVPX::internalGetParameter(
    149         OMX_INDEXTYPE index, OMX_PTR params) {
    150     switch (index) {
    151         case OMX_IndexParamVideoPortFormat:
    152         {
    153             OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
    154                 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
    155 
    156             if (formatParams->nPortIndex > 1) {
    157                 return OMX_ErrorUndefined;
    158             }
    159 
    160             if (formatParams->nIndex != 0) {
    161                 return OMX_ErrorNoMore;
    162             }
    163 
    164             if (formatParams->nPortIndex == 0) {
    165                 formatParams->eCompressionFormat = OMX_VIDEO_CodingVPX;
    166                 formatParams->eColorFormat = OMX_COLOR_FormatUnused;
    167                 formatParams->xFramerate = 0;
    168             } else {
    169                 CHECK_EQ(formatParams->nPortIndex, 1u);
    170 
    171                 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
    172                 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
    173                 formatParams->xFramerate = 0;
    174             }
    175 
    176             return OMX_ErrorNone;
    177         }
    178 
    179         default:
    180             return SimpleSoftOMXComponent::internalGetParameter(index, params);
    181     }
    182 }
    183 
    184 OMX_ERRORTYPE SoftVPX::internalSetParameter(
    185         OMX_INDEXTYPE index, const OMX_PTR params) {
    186     switch (index) {
    187         case OMX_IndexParamStandardComponentRole:
    188         {
    189             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
    190                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
    191 
    192             if (strncmp((const char *)roleParams->cRole,
    193                         "video_decoder.vpx",
    194                         OMX_MAX_STRINGNAME_SIZE - 1)) {
    195                 return OMX_ErrorUndefined;
    196             }
    197 
    198             return OMX_ErrorNone;
    199         }
    200 
    201         case OMX_IndexParamVideoPortFormat:
    202         {
    203             OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
    204                 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
    205 
    206             if (formatParams->nPortIndex > 1) {
    207                 return OMX_ErrorUndefined;
    208             }
    209 
    210             if (formatParams->nIndex != 0) {
    211                 return OMX_ErrorNoMore;
    212             }
    213 
    214             return OMX_ErrorNone;
    215         }
    216 
    217         default:
    218             return SimpleSoftOMXComponent::internalSetParameter(index, params);
    219     }
    220 }
    221 
    222 void SoftVPX::onQueueFilled(OMX_U32 portIndex) {
    223     if (mOutputPortSettingsChange != NONE) {
    224         return;
    225     }
    226 
    227     List<BufferInfo *> &inQueue = getPortQueue(0);
    228     List<BufferInfo *> &outQueue = getPortQueue(1);
    229 
    230     while (!inQueue.empty() && !outQueue.empty()) {
    231         BufferInfo *inInfo = *inQueue.begin();
    232         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    233 
    234         BufferInfo *outInfo = *outQueue.begin();
    235         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
    236 
    237         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    238             inQueue.erase(inQueue.begin());
    239             inInfo->mOwnedByUs = false;
    240             notifyEmptyBufferDone(inHeader);
    241 
    242             outHeader->nFilledLen = 0;
    243             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    244 
    245             outQueue.erase(outQueue.begin());
    246             outInfo->mOwnedByUs = false;
    247             notifyFillBufferDone(outHeader);
    248             return;
    249         }
    250 
    251         if (vpx_codec_decode(
    252                     (vpx_codec_ctx_t *)mCtx,
    253                     inHeader->pBuffer + inHeader->nOffset,
    254                     inHeader->nFilledLen,
    255                     NULL,
    256                     0)) {
    257             ALOGE("on2 decoder failed to decode frame.");
    258 
    259             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    260             return;
    261         }
    262 
    263         vpx_codec_iter_t iter = NULL;
    264         vpx_image_t *img = vpx_codec_get_frame((vpx_codec_ctx_t *)mCtx, &iter);
    265 
    266         if (img != NULL) {
    267             CHECK_EQ(img->fmt, IMG_FMT_I420);
    268 
    269             int32_t width = img->d_w;
    270             int32_t height = img->d_h;
    271 
    272             if (width != mWidth || height != mHeight) {
    273                 mWidth = width;
    274                 mHeight = height;
    275 
    276                 updatePortDefinitions();
    277 
    278                 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
    279                 mOutputPortSettingsChange = AWAITING_DISABLED;
    280                 return;
    281             }
    282 
    283             outHeader->nOffset = 0;
    284             outHeader->nFilledLen = (width * height * 3) / 2;
    285             outHeader->nFlags = 0;
    286             outHeader->nTimeStamp = inHeader->nTimeStamp;
    287 
    288             const uint8_t *srcLine = (const uint8_t *)img->planes[PLANE_Y];
    289             uint8_t *dst = outHeader->pBuffer;
    290             for (size_t i = 0; i < img->d_h; ++i) {
    291                 memcpy(dst, srcLine, img->d_w);
    292 
    293                 srcLine += img->stride[PLANE_Y];
    294                 dst += img->d_w;
    295             }
    296 
    297             srcLine = (const uint8_t *)img->planes[PLANE_U];
    298             for (size_t i = 0; i < img->d_h / 2; ++i) {
    299                 memcpy(dst, srcLine, img->d_w / 2);
    300 
    301                 srcLine += img->stride[PLANE_U];
    302                 dst += img->d_w / 2;
    303             }
    304 
    305             srcLine = (const uint8_t *)img->planes[PLANE_V];
    306             for (size_t i = 0; i < img->d_h / 2; ++i) {
    307                 memcpy(dst, srcLine, img->d_w / 2);
    308 
    309                 srcLine += img->stride[PLANE_V];
    310                 dst += img->d_w / 2;
    311             }
    312 
    313             outInfo->mOwnedByUs = false;
    314             outQueue.erase(outQueue.begin());
    315             outInfo = NULL;
    316             notifyFillBufferDone(outHeader);
    317             outHeader = NULL;
    318         }
    319 
    320         inInfo->mOwnedByUs = false;
    321         inQueue.erase(inQueue.begin());
    322         inInfo = NULL;
    323         notifyEmptyBufferDone(inHeader);
    324         inHeader = NULL;
    325     }
    326 }
    327 
    328 void SoftVPX::onPortFlushCompleted(OMX_U32 portIndex) {
    329 }
    330 
    331 void SoftVPX::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
    332     if (portIndex != 1) {
    333         return;
    334     }
    335 
    336     switch (mOutputPortSettingsChange) {
    337         case NONE:
    338             break;
    339 
    340         case AWAITING_DISABLED:
    341         {
    342             CHECK(!enabled);
    343             mOutputPortSettingsChange = AWAITING_ENABLED;
    344             break;
    345         }
    346 
    347         default:
    348         {
    349             CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
    350             CHECK(enabled);
    351             mOutputPortSettingsChange = NONE;
    352             break;
    353         }
    354     }
    355 }
    356 
    357 void SoftVPX::updatePortDefinitions() {
    358     OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(0)->mDef;
    359     def->format.video.nFrameWidth = mWidth;
    360     def->format.video.nFrameHeight = mHeight;
    361     def->format.video.nStride = def->format.video.nFrameWidth;
    362     def->format.video.nSliceHeight = def->format.video.nFrameHeight;
    363 
    364     def = &editPortInfo(1)->mDef;
    365     def->format.video.nFrameWidth = mWidth;
    366     def->format.video.nFrameHeight = mHeight;
    367     def->format.video.nStride = def->format.video.nFrameWidth;
    368     def->format.video.nSliceHeight = def->format.video.nFrameHeight;
    369 
    370     def->nBufferSize =
    371         (def->format.video.nFrameWidth
    372             * def->format.video.nFrameHeight * 3) / 2;
    373 }
    374 
    375 }  // namespace android
    376 
    377 android::SoftOMXComponent *createSoftOMXComponent(
    378         const char *name, const OMX_CALLBACKTYPE *callbacks,
    379         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    380     return new android::SoftVPX(name, callbacks, appData, component);
    381 }
    382 
    383