SoftVideoEncoderOMXComponent.cpp revision 9847fcefb183e1cb09eb48e17a09577392b0e8f4
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 = 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
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 usingANWBuffer = bufferType == kMetadataBufferTypeANWBuffer;
486    if (!usingANWBuffer && 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 (usingANWBuffer) {
503        if (srcSize < sizeof(VideoNativeMetadata)) {
504            ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoNativeMetadata));
505            return NULL;
506        }
507
508        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)src;
509        ANativeWindowBuffer *buffer = nativeMeta.pBuffer;
510        handle = buffer->handle;
511        format = buffer->format;
512        srcStride = buffer->stride;
513        srcVStride = buffer->height;
514        // convert stride from pixels to bytes
515        if (format != HAL_PIXEL_FORMAT_YV12 &&
516            format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
517            // TODO do we need to support other formats?
518            srcStride *= 4;
519        }
520
521        if (nativeMeta.nFenceFd >= 0) {
522            sp<Fence> fence = new Fence(nativeMeta.nFenceFd);
523            nativeMeta.nFenceFd = -1;
524            status_t err = fence->wait(IOMX::kFenceTimeoutMs);
525            if (err != OK) {
526                ALOGE("Timed out waiting on input fence");
527                return NULL;
528            }
529        }
530    } else {
531        // TODO: remove this part.  Check if anyone uses this.
532
533        if (srcSize < sizeof(VideoGrallocMetadata)) {
534            ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoGrallocMetadata));
535            return NULL;
536        }
537
538        VideoGrallocMetadata &grallocMeta = *(VideoGrallocMetadata *)(src);
539        handle = grallocMeta.pHandle;
540        // assume HAL_PIXEL_FORMAT_RGBA_8888
541        // there is no way to get the src stride without the graphic buffer
542        format = HAL_PIXEL_FORMAT_RGBA_8888;
543        srcStride = width * 4;
544        srcVStride = height;
545    }
546
547    size_t neededSize =
548        dstStride * dstVStride + (width >> 1)
549                + (dstStride >> 1) * ((dstVStride >> 1) + (height >> 1) - 1);
550    if (dstSize < neededSize) {
551        ALOGE("destination buffer is too small (%zu vs %zu)", dstSize, neededSize);
552        return NULL;
553    }
554
555    void *bits = NULL;
556    struct android_ycbcr ycbcr;
557    status_t res;
558    if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
559        res = grmodule->lock_ycbcr(
560                 grmodule, handle,
561                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
562                 0, 0, width, height, &ycbcr);
563    } else {
564        res = grmodule->lock(
565                 grmodule, handle,
566                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
567                 0, 0, width, height, &bits);
568    }
569    if (res != OK) {
570        ALOGE("Unable to lock image buffer %p for access", handle);
571        return NULL;
572    }
573
574    switch (format) {
575        case HAL_PIXEL_FORMAT_YV12:  // YCrCb / YVU planar
576            // convert to flex YUV
577            ycbcr.y = bits;
578            ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride;
579            ycbcr.cb = (uint8_t *)ycbcr.cr + (srcStride >> 1) * (srcVStride >> 1);
580            ycbcr.chroma_step = 1;
581            ycbcr.cstride = srcVStride >> 1;
582            ycbcr.ystride = srcVStride;
583            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
584            break;
585        case HAL_PIXEL_FORMAT_YCrCb_420_SP:  // YCrCb / YVU semiplanar, NV21
586            // convert to flex YUV
587            ycbcr.y = bits;
588            ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride;
589            ycbcr.cb = (uint8_t *)ycbcr.cr + 1;
590            ycbcr.chroma_step = 2;
591            ycbcr.cstride = srcVStride;
592            ycbcr.ystride = srcVStride;
593            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
594            break;
595        case HAL_PIXEL_FORMAT_YCbCr_420_888:
596            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
597            break;
598        case HAL_PIXEL_FORMAT_RGBA_8888:
599        case HAL_PIXEL_FORMAT_BGRA_8888:
600            ConvertRGB32ToPlanar(
601                    dst, dstStride, dstVStride,
602                    (const uint8_t *)bits, width, height, srcStride,
603                    format == HAL_PIXEL_FORMAT_BGRA_8888);
604            break;
605        default:
606            ALOGE("Unsupported pixel format %#x", format);
607            dst = NULL;
608            break;
609    }
610
611    if (grmodule->unlock(grmodule, handle) != OK) {
612        ALOGE("Unable to unlock image buffer %p for access", handle);
613    }
614
615    return dst;
616}
617
618OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex(
619        const char *name, OMX_INDEXTYPE *index) {
620    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers") ||
621        !strcmp(name, "OMX.google.android.index.storeANWBufferInMetadata")) {
622        *(int32_t*)index = kStoreMetaDataExtensionIndex;
623        return OMX_ErrorNone;
624    }
625    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
626}
627
628}  // namespace android
629