SoftVideoEncoderOMXComponent.cpp revision a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5
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
37namespace android {
38
39const static OMX_COLOR_FORMATTYPE kSupportedColorFormats[] = {
40    OMX_COLOR_FormatYUV420Planar,
41    OMX_COLOR_FormatYUV420SemiPlanar,
42    OMX_COLOR_FormatAndroidOpaque
43};
44
45template<class T>
46static 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
54SoftVideoEncoderOMXComponent::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
81void 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
147void 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
171OMX_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
203OMX_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
294OMX_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
352void 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
394void 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
424void 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
477const 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
606OMX_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