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