Home | History | Annotate | Download | only in omx
      1 /*
      2  * Copyright 2014 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 #include <inttypes.h>
     18 
     19 //#define LOG_NDEBUG 0
     20 #define LOG_TAG "SoftVideoEncoderOMXComponent"
     21 #include <utils/Log.h>
     22 #include <utils/misc.h>
     23 
     24 #include "include/SoftVideoEncoderOMXComponent.h"
     25 
     26 #include <hardware/gralloc.h>
     27 #include <media/hardware/HardwareAPI.h>
     28 #include <media/stagefright/foundation/ADebug.h>
     29 #include <media/stagefright/foundation/ALooper.h>
     30 #include <media/stagefright/foundation/AMessage.h>
     31 #include <media/stagefright/foundation/AUtils.h>
     32 #include <media/stagefright/MediaDefs.h>
     33 
     34 #include <ui/GraphicBuffer.h>
     35 #include <ui/GraphicBufferMapper.h>
     36 
     37 #include <OMX_IndexExt.h>
     38 
     39 namespace android {
     40 
     41 const static OMX_COLOR_FORMATTYPE kSupportedColorFormats[] = {
     42     OMX_COLOR_FormatYUV420Planar,
     43     OMX_COLOR_FormatYUV420SemiPlanar,
     44     OMX_COLOR_FormatAndroidOpaque
     45 };
     46 
     47 template<class T>
     48 static void InitOMXParams(T *params) {
     49     params->nSize = sizeof(T);
     50     params->nVersion.s.nVersionMajor = 1;
     51     params->nVersion.s.nVersionMinor = 0;
     52     params->nVersion.s.nRevision = 0;
     53     params->nVersion.s.nStep = 0;
     54 }
     55 
     56 SoftVideoEncoderOMXComponent::SoftVideoEncoderOMXComponent(
     57         const char *name,
     58         const char *componentRole,
     59         OMX_VIDEO_CODINGTYPE codingType,
     60         const CodecProfileLevel *profileLevels,
     61         size_t numProfileLevels,
     62         int32_t width,
     63         int32_t height,
     64         const OMX_CALLBACKTYPE *callbacks,
     65         OMX_PTR appData,
     66         OMX_COMPONENTTYPE **component)
     67     : SimpleSoftOMXComponent(name, callbacks, appData, component),
     68       mInputDataIsMeta(false),
     69       mWidth(width),
     70       mHeight(height),
     71       mBitrate(192000),
     72       mFramerate(30 << 16), // Q16 format
     73       mColorFormat(OMX_COLOR_FormatYUV420Planar),
     74       mGrallocModule(NULL),
     75       mMinOutputBufferSize(384), // arbitrary, using one uncompressed macroblock
     76       mMinCompressionRatio(1),   // max output size is normally the input size
     77       mComponentRole(componentRole),
     78       mCodingType(codingType),
     79       mProfileLevels(profileLevels),
     80       mNumProfileLevels(numProfileLevels) {
     81 }
     82 
     83 void SoftVideoEncoderOMXComponent::initPorts(
     84         OMX_U32 numInputBuffers, OMX_U32 numOutputBuffers, OMX_U32 outputBufferSize,
     85         const char *mime, OMX_U32 minCompressionRatio) {
     86     OMX_PARAM_PORTDEFINITIONTYPE def;
     87 
     88     mMinOutputBufferSize = outputBufferSize;
     89     mMinCompressionRatio = minCompressionRatio;
     90 
     91     InitOMXParams(&def);
     92 
     93     def.nPortIndex = kInputPortIndex;
     94     def.eDir = OMX_DirInput;
     95     def.nBufferCountMin = numInputBuffers;
     96     def.nBufferCountActual = def.nBufferCountMin;
     97     def.bEnabled = OMX_TRUE;
     98     def.bPopulated = OMX_FALSE;
     99     def.eDomain = OMX_PortDomainVideo;
    100     def.bBuffersContiguous = OMX_FALSE;
    101     def.format.video.pNativeRender = NULL;
    102     def.format.video.nFrameWidth = mWidth;
    103     def.format.video.nFrameHeight = mHeight;
    104     def.format.video.nStride = def.format.video.nFrameWidth;
    105     def.format.video.nSliceHeight = def.format.video.nFrameHeight;
    106     def.format.video.nBitrate = 0;
    107     // frameRate is in Q16 format.
    108     def.format.video.xFramerate = mFramerate;
    109     def.format.video.bFlagErrorConcealment = OMX_FALSE;
    110     def.nBufferAlignment = kInputBufferAlignment;
    111     def.format.video.cMIMEType = const_cast<char *>("video/raw");
    112     def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
    113     def.format.video.eColorFormat = mColorFormat;
    114     def.format.video.pNativeWindow = NULL;
    115     // buffersize set in updatePortParams
    116 
    117     addPort(def);
    118 
    119     InitOMXParams(&def);
    120 
    121     def.nPortIndex = kOutputPortIndex;
    122     def.eDir = OMX_DirOutput;
    123     def.nBufferCountMin = numOutputBuffers;
    124     def.nBufferCountActual = def.nBufferCountMin;
    125     def.bEnabled = OMX_TRUE;
    126     def.bPopulated = OMX_FALSE;
    127     def.eDomain = OMX_PortDomainVideo;
    128     def.bBuffersContiguous = OMX_FALSE;
    129     def.format.video.pNativeRender = NULL;
    130     def.format.video.nFrameWidth = mWidth;
    131     def.format.video.nFrameHeight = mHeight;
    132     def.format.video.nStride = 0;
    133     def.format.video.nSliceHeight = 0;
    134     def.format.video.nBitrate = mBitrate;
    135     def.format.video.xFramerate = 0 << 16;
    136     def.format.video.bFlagErrorConcealment = OMX_FALSE;
    137     def.nBufferAlignment = kOutputBufferAlignment;
    138     def.format.video.cMIMEType = const_cast<char *>(mime);
    139     def.format.video.eCompressionFormat = mCodingType;
    140     def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
    141     def.format.video.pNativeWindow = NULL;
    142     // buffersize set in updatePortParams
    143 
    144     addPort(def);
    145 
    146     updatePortParams();
    147 }
    148 
    149 void SoftVideoEncoderOMXComponent::updatePortParams() {
    150     OMX_PARAM_PORTDEFINITIONTYPE *inDef = &editPortInfo(kInputPortIndex)->mDef;
    151     inDef->format.video.nFrameWidth = mWidth;
    152     inDef->format.video.nFrameHeight = mHeight;
    153     inDef->format.video.nStride = inDef->format.video.nFrameWidth;
    154     inDef->format.video.nSliceHeight = inDef->format.video.nFrameHeight;
    155     inDef->format.video.xFramerate = mFramerate;
    156     inDef->format.video.eColorFormat = mColorFormat;
    157     uint32_t rawBufferSize =
    158         inDef->format.video.nStride * inDef->format.video.nSliceHeight * 3 / 2;
    159     if (inDef->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
    160         inDef->nBufferSize = max(sizeof(VideoNativeMetadata), sizeof(VideoGrallocMetadata));
    161     } else {
    162         inDef->nBufferSize = rawBufferSize;
    163     }
    164 
    165     OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
    166     outDef->format.video.nFrameWidth = mWidth;
    167     outDef->format.video.nFrameHeight = mHeight;
    168     outDef->format.video.nBitrate = mBitrate;
    169 
    170     outDef->nBufferSize = max(mMinOutputBufferSize, rawBufferSize / mMinCompressionRatio);
    171 }
    172 
    173 OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalSetPortParams(
    174         const OMX_PARAM_PORTDEFINITIONTYPE *port) {
    175     if (port->nPortIndex == kInputPortIndex) {
    176         mWidth = port->format.video.nFrameWidth;
    177         mHeight = port->format.video.nFrameHeight;
    178 
    179         // xFramerate comes in Q16 format, in frames per second unit
    180         mFramerate = port->format.video.xFramerate;
    181 
    182         if (port->format.video.eCompressionFormat != OMX_VIDEO_CodingUnused
    183                 || (port->format.video.eColorFormat != OMX_COLOR_FormatYUV420Planar
    184                         && port->format.video.eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar
    185                         && port->format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque)) {
    186             return OMX_ErrorUnsupportedSetting;
    187         }
    188 
    189         mColorFormat = port->format.video.eColorFormat;
    190     } else if (port->nPortIndex == kOutputPortIndex) {
    191         if (port->format.video.eCompressionFormat != mCodingType
    192                 || port->format.video.eColorFormat != OMX_COLOR_FormatUnused) {
    193             return OMX_ErrorUnsupportedSetting;
    194         }
    195 
    196         mBitrate = port->format.video.nBitrate;
    197     } else {
    198         return OMX_ErrorBadPortIndex;
    199     }
    200 
    201     updatePortParams();
    202     return OMX_ErrorNone;
    203 }
    204 
    205 OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalSetParameter(
    206         OMX_INDEXTYPE index, const OMX_PTR param) {
    207     // can include extension index OMX_INDEXEXTTYPE
    208     const int32_t indexFull = index;
    209 
    210     switch (indexFull) {
    211         case OMX_IndexParamVideoErrorCorrection:
    212         {
    213             return OMX_ErrorNotImplemented;
    214         }
    215 
    216         case OMX_IndexParamStandardComponentRole:
    217         {
    218             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
    219                 (const OMX_PARAM_COMPONENTROLETYPE *)param;
    220 
    221             if (strncmp((const char *)roleParams->cRole,
    222                         mComponentRole,
    223                         OMX_MAX_STRINGNAME_SIZE - 1)) {
    224                 return OMX_ErrorUnsupportedSetting;
    225             }
    226 
    227             return OMX_ErrorNone;
    228         }
    229 
    230         case OMX_IndexParamPortDefinition:
    231         {
    232             OMX_ERRORTYPE err = internalSetPortParams((const OMX_PARAM_PORTDEFINITIONTYPE *)param);
    233 
    234             if (err != OMX_ErrorNone) {
    235                 return err;
    236             }
    237 
    238             return SimpleSoftOMXComponent::internalSetParameter(index, param);
    239         }
    240 
    241         case OMX_IndexParamVideoPortFormat:
    242         {
    243             const OMX_VIDEO_PARAM_PORTFORMATTYPE* format =
    244                 (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param;
    245 
    246             if (format->nPortIndex == kInputPortIndex) {
    247                 if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar ||
    248                     format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
    249                     format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
    250                     mColorFormat = format->eColorFormat;
    251 
    252                     updatePortParams();
    253                     return OMX_ErrorNone;
    254                 } else {
    255                     ALOGE("Unsupported color format %i", format->eColorFormat);
    256                     return OMX_ErrorUnsupportedSetting;
    257                 }
    258             } else if (format->nPortIndex == kOutputPortIndex) {
    259                 if (format->eCompressionFormat == mCodingType) {
    260                     return OMX_ErrorNone;
    261                 } else {
    262                     return OMX_ErrorUnsupportedSetting;
    263                 }
    264             } else {
    265                 return OMX_ErrorBadPortIndex;
    266             }
    267         }
    268 
    269         case kStoreMetaDataExtensionIndex:
    270         {
    271             // storeMetaDataInBuffers
    272             const StoreMetaDataInBuffersParams *storeParam =
    273                 (const StoreMetaDataInBuffersParams *)param;
    274 
    275             if (storeParam->nPortIndex == kOutputPortIndex) {
    276                 return storeParam->bStoreMetaData ? OMX_ErrorUnsupportedSetting : OMX_ErrorNone;
    277             } else if (storeParam->nPortIndex != kInputPortIndex) {
    278                 return OMX_ErrorBadPortIndex;
    279             }
    280 
    281             mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE);
    282             if (mInputDataIsMeta) {
    283                 mColorFormat = OMX_COLOR_FormatAndroidOpaque;
    284             } else if (mColorFormat == OMX_COLOR_FormatAndroidOpaque) {
    285                 mColorFormat = OMX_COLOR_FormatYUV420Planar;
    286             }
    287             updatePortParams();
    288             return OMX_ErrorNone;
    289         }
    290 
    291         default:
    292             return SimpleSoftOMXComponent::internalSetParameter(index, param);
    293     }
    294 }
    295 
    296 OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalGetParameter(
    297         OMX_INDEXTYPE index, OMX_PTR param) {
    298     switch ((int)index) {
    299         case OMX_IndexParamVideoErrorCorrection:
    300         {
    301             return OMX_ErrorNotImplemented;
    302         }
    303 
    304         case OMX_IndexParamVideoPortFormat:
    305         {
    306             OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
    307                 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param;
    308 
    309             if (formatParams->nPortIndex == kInputPortIndex) {
    310                 if (formatParams->nIndex >= NELEM(kSupportedColorFormats)) {
    311                     return OMX_ErrorNoMore;
    312                 }
    313 
    314                 // Color formats, in order of preference
    315                 formatParams->eColorFormat = kSupportedColorFormats[formatParams->nIndex];
    316                 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
    317                 formatParams->xFramerate = mFramerate;
    318                 return OMX_ErrorNone;
    319             } else if (formatParams->nPortIndex == kOutputPortIndex) {
    320                 formatParams->eCompressionFormat = mCodingType;
    321                 formatParams->eColorFormat = OMX_COLOR_FormatUnused;
    322                 formatParams->xFramerate = 0;
    323                 return OMX_ErrorNone;
    324             } else {
    325                 return OMX_ErrorBadPortIndex;
    326             }
    327         }
    328 
    329         case OMX_IndexParamVideoProfileLevelQuerySupported:
    330         {
    331             OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
    332                   (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) param;
    333 
    334             if (profileLevel->nPortIndex != kOutputPortIndex) {
    335                 ALOGE("Invalid port index: %u", profileLevel->nPortIndex);
    336                 return OMX_ErrorUnsupportedIndex;
    337             }
    338 
    339             if (profileLevel->nProfileIndex >= mNumProfileLevels) {
    340                 return OMX_ErrorNoMore;
    341             }
    342 
    343             profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile;
    344             profileLevel->eLevel   = mProfileLevels[profileLevel->nProfileIndex].mLevel;
    345             return OMX_ErrorNone;
    346         }
    347 
    348         case OMX_IndexParamConsumerUsageBits:
    349         {
    350             OMX_U32 *usageBits = (OMX_U32 *)param;
    351             *usageBits = GRALLOC_USAGE_SW_READ_OFTEN;
    352             return OMX_ErrorNone;
    353         }
    354 
    355         default:
    356             return SimpleSoftOMXComponent::internalGetParameter(index, param);
    357     }
    358 }
    359 
    360 // static
    361 void SoftVideoEncoderOMXComponent::ConvertFlexYUVToPlanar(
    362         uint8_t *dst, size_t dstStride, size_t dstVStride,
    363         struct android_ycbcr *ycbcr, int32_t width, int32_t height) {
    364     const uint8_t *src = (const uint8_t *)ycbcr->y;
    365     const uint8_t *srcU = (const uint8_t *)ycbcr->cb;
    366     const uint8_t *srcV = (const uint8_t *)ycbcr->cr;
    367     uint8_t *dstU = dst + dstVStride * dstStride;
    368     uint8_t *dstV = dstU + (dstVStride >> 1) * (dstStride >> 1);
    369 
    370     for (size_t y = height; y > 0; --y) {
    371         memcpy(dst, src, width);
    372         dst += dstStride;
    373         src += ycbcr->ystride;
    374     }
    375     if (ycbcr->cstride == ycbcr->ystride >> 1 && ycbcr->chroma_step == 1) {
    376         // planar
    377         for (size_t y = height >> 1; y > 0; --y) {
    378             memcpy(dstU, srcU, width >> 1);
    379             dstU += dstStride >> 1;
    380             srcU += ycbcr->cstride;
    381             memcpy(dstV, srcV, width >> 1);
    382             dstV += dstStride >> 1;
    383             srcV += ycbcr->cstride;
    384         }
    385     } else {
    386         // arbitrary
    387         for (size_t y = height >> 1; y > 0; --y) {
    388             for (size_t x = width >> 1; x > 0; --x) {
    389                 *dstU++ = *srcU;
    390                 *dstV++ = *srcV;
    391                 srcU += ycbcr->chroma_step;
    392                 srcV += ycbcr->chroma_step;
    393             }
    394             dstU += (dstStride >> 1) - (width >> 1);
    395             dstV += (dstStride >> 1) - (width >> 1);
    396             srcU += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step;
    397             srcV += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step;
    398         }
    399     }
    400 }
    401 
    402 // static
    403 void SoftVideoEncoderOMXComponent::ConvertYUV420SemiPlanarToYUV420Planar(
    404         const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height) {
    405     // TODO: add support for stride
    406     int32_t outYsize = width * height;
    407     uint32_t *outY  = (uint32_t *) outYUV;
    408     uint16_t *outCb = (uint16_t *) (outYUV + outYsize);
    409     uint16_t *outCr = (uint16_t *) (outYUV + outYsize + (outYsize >> 2));
    410 
    411     /* Y copying */
    412     memcpy(outY, inYVU, outYsize);
    413 
    414     /* U & V copying */
    415     // FIXME this only works if width is multiple of 4
    416     uint32_t *inYVU_4 = (uint32_t *) (inYVU + outYsize);
    417     for (int32_t i = height >> 1; i > 0; --i) {
    418         for (int32_t j = width >> 2; j > 0; --j) {
    419             uint32_t temp = *inYVU_4++;
    420             uint32_t tempU = temp & 0xFF;
    421             tempU = tempU | ((temp >> 8) & 0xFF00);
    422 
    423             uint32_t tempV = (temp >> 8) & 0xFF;
    424             tempV = tempV | ((temp >> 16) & 0xFF00);
    425 
    426             *outCb++ = tempU;
    427             *outCr++ = tempV;
    428         }
    429     }
    430 }
    431 
    432 // static
    433 void SoftVideoEncoderOMXComponent::ConvertRGB32ToPlanar(
    434         uint8_t *dstY, size_t dstStride, size_t dstVStride,
    435         const uint8_t *src, size_t width, size_t height, size_t srcStride,
    436         bool bgr) {
    437     CHECK((width & 1) == 0);
    438     CHECK((height & 1) == 0);
    439 
    440     uint8_t *dstU = dstY + dstStride * dstVStride;
    441     uint8_t *dstV = dstU + (dstStride >> 1) * (dstVStride >> 1);
    442 
    443 #ifdef SURFACE_IS_BGR32
    444     bgr = !bgr;
    445 #endif
    446 
    447     const size_t redOffset   = bgr ? 2 : 0;
    448     const size_t greenOffset = 1;
    449     const size_t blueOffset  = bgr ? 0 : 2;
    450 
    451     for (size_t y = 0; y < height; ++y) {
    452         for (size_t x = 0; x < width; ++x) {
    453             unsigned red   = src[redOffset];
    454             unsigned green = src[greenOffset];
    455             unsigned blue  = src[blueOffset];
    456 
    457             // using ITU-R BT.601 conversion matrix
    458             unsigned luma =
    459                 ((red * 66 + green * 129 + blue * 25) >> 8) + 16;
    460 
    461             dstY[x] = luma;
    462 
    463             if ((x & 1) == 0 && (y & 1) == 0) {
    464                 unsigned U =
    465                     ((-red * 38 - green * 74 + blue * 112) >> 8) + 128;
    466 
    467                 unsigned V =
    468                     ((red * 112 - green * 94 - blue * 18) >> 8) + 128;
    469 
    470                 dstU[x >> 1] = U;
    471                 dstV[x >> 1] = V;
    472             }
    473             src += 4;
    474         }
    475 
    476         if ((y & 1) == 0) {
    477             dstU += dstStride >> 1;
    478             dstV += dstStride >> 1;
    479         }
    480 
    481         src += srcStride - 4 * width;
    482         dstY += dstStride;
    483     }
    484 }
    485 
    486 const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer(
    487         uint8_t *dst, size_t dstSize,
    488         const uint8_t *src, size_t srcSize,
    489         size_t width, size_t height) const {
    490     size_t dstStride = width;
    491     size_t dstVStride = height;
    492 
    493     MetadataBufferType bufferType = *(MetadataBufferType *)src;
    494     bool usingANWBuffer = bufferType == kMetadataBufferTypeANWBuffer;
    495     if (!usingANWBuffer && bufferType != kMetadataBufferTypeGrallocSource) {
    496         ALOGE("Unsupported metadata type (%d)", bufferType);
    497         return NULL;
    498     }
    499 
    500     if (mGrallocModule == NULL) {
    501         CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
    502     }
    503 
    504     const gralloc_module_t *grmodule =
    505         (const gralloc_module_t *)mGrallocModule;
    506 
    507     buffer_handle_t handle;
    508     int format;
    509     size_t srcStride;
    510     size_t srcVStride;
    511     if (usingANWBuffer) {
    512         if (srcSize < sizeof(VideoNativeMetadata)) {
    513             ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoNativeMetadata));
    514             return NULL;
    515         }
    516 
    517         VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)src;
    518         ANativeWindowBuffer *buffer = nativeMeta.pBuffer;
    519         handle = buffer->handle;
    520         format = buffer->format;
    521         srcStride = buffer->stride;
    522         srcVStride = buffer->height;
    523         // convert stride from pixels to bytes
    524         if (format != HAL_PIXEL_FORMAT_YV12 &&
    525             format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
    526             // TODO do we need to support other formats?
    527             srcStride *= 4;
    528         }
    529 
    530         if (nativeMeta.nFenceFd >= 0) {
    531             sp<Fence> fence = new Fence(nativeMeta.nFenceFd);
    532             nativeMeta.nFenceFd = -1;
    533             status_t err = fence->wait(IOMX::kFenceTimeoutMs);
    534             if (err != OK) {
    535                 ALOGE("Timed out waiting on input fence");
    536                 return NULL;
    537             }
    538         }
    539     } else {
    540         // TODO: remove this part.  Check if anyone uses this.
    541 
    542         if (srcSize < sizeof(VideoGrallocMetadata)) {
    543             ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoGrallocMetadata));
    544             return NULL;
    545         }
    546 
    547         VideoGrallocMetadata &grallocMeta = *(VideoGrallocMetadata *)(src);
    548         handle = grallocMeta.pHandle;
    549         // assume HAL_PIXEL_FORMAT_RGBA_8888
    550         // there is no way to get the src stride without the graphic buffer
    551         format = HAL_PIXEL_FORMAT_RGBA_8888;
    552         srcStride = width * 4;
    553         srcVStride = height;
    554     }
    555 
    556     size_t neededSize =
    557         dstStride * dstVStride + (width >> 1)
    558                 + (dstStride >> 1) * ((dstVStride >> 1) + (height >> 1) - 1);
    559     if (dstSize < neededSize) {
    560         ALOGE("destination buffer is too small (%zu vs %zu)", dstSize, neededSize);
    561         return NULL;
    562     }
    563 
    564     void *bits = NULL;
    565     struct android_ycbcr ycbcr;
    566     status_t res;
    567     if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
    568         res = grmodule->lock_ycbcr(
    569                  grmodule, handle,
    570                  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
    571                  0, 0, width, height, &ycbcr);
    572     } else {
    573         res = grmodule->lock(
    574                  grmodule, handle,
    575                  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
    576                  0, 0, width, height, &bits);
    577     }
    578     if (res != OK) {
    579         ALOGE("Unable to lock image buffer %p for access", handle);
    580         return NULL;
    581     }
    582 
    583     switch (format) {
    584         case HAL_PIXEL_FORMAT_YV12:  // YCrCb / YVU planar
    585             // convert to flex YUV
    586             ycbcr.y = bits;
    587             ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride;
    588             ycbcr.cb = (uint8_t *)ycbcr.cr + (srcStride >> 1) * (srcVStride >> 1);
    589             ycbcr.chroma_step = 1;
    590             ycbcr.cstride = srcVStride >> 1;
    591             ycbcr.ystride = srcVStride;
    592             ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
    593             break;
    594         case HAL_PIXEL_FORMAT_YCrCb_420_SP:  // YCrCb / YVU semiplanar, NV21
    595             // convert to flex YUV
    596             ycbcr.y = bits;
    597             ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride;
    598             ycbcr.cb = (uint8_t *)ycbcr.cr + 1;
    599             ycbcr.chroma_step = 2;
    600             ycbcr.cstride = srcVStride;
    601             ycbcr.ystride = srcVStride;
    602             ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
    603             break;
    604         case HAL_PIXEL_FORMAT_YCbCr_420_888:
    605             ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
    606             break;
    607         case HAL_PIXEL_FORMAT_RGBA_8888:
    608         case HAL_PIXEL_FORMAT_BGRA_8888:
    609             ConvertRGB32ToPlanar(
    610                     dst, dstStride, dstVStride,
    611                     (const uint8_t *)bits, width, height, srcStride,
    612                     format == HAL_PIXEL_FORMAT_BGRA_8888);
    613             break;
    614         default:
    615             ALOGE("Unsupported pixel format %#x", format);
    616             dst = NULL;
    617             break;
    618     }
    619 
    620     if (grmodule->unlock(grmodule, handle) != OK) {
    621         ALOGE("Unable to unlock image buffer %p for access", handle);
    622     }
    623 
    624     return dst;
    625 }
    626 
    627 OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex(
    628         const char *name, OMX_INDEXTYPE *index) {
    629     if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers") ||
    630         !strcmp(name, "OMX.google.android.index.storeANWBufferInMetadata")) {
    631         *(int32_t*)index = kStoreMetaDataExtensionIndex;
    632         return OMX_ErrorNone;
    633     }
    634     return SimpleSoftOMXComponent::getExtensionIndex(name, index);
    635 }
    636 
    637 }  // namespace android
    638