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