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