SoftVideoEncoderOMXComponent.cpp revision fe7df6220dbdd2ada97bf195c542c5e399695ed0
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
38namespace android {
39
40const static OMX_COLOR_FORMATTYPE kSupportedColorFormats[] = {
41    OMX_COLOR_FormatYUV420Planar,
42    OMX_COLOR_FormatYUV420SemiPlanar,
43    OMX_COLOR_FormatAndroidOpaque
44};
45
46template<class T>
47static 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
55SoftVideoEncoderOMXComponent::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
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 ((int)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        case OMX_IndexParamConsumerUsageBits:
347        {
348            OMX_U32 *usageBits = (OMX_U32 *)param;
349            *usageBits = GRALLOC_USAGE_SW_READ_OFTEN;
350            return OMX_ErrorNone;
351        }
352
353        default:
354            return SimpleSoftOMXComponent::internalGetParameter(index, param);
355    }
356}
357
358// static
359__attribute__((no_sanitize("integer")))
360void SoftVideoEncoderOMXComponent::ConvertFlexYUVToPlanar(
361        uint8_t *dst, size_t dstStride, size_t dstVStride,
362        struct android_ycbcr *ycbcr, int32_t width, int32_t height) {
363    const uint8_t *src = (const uint8_t *)ycbcr->y;
364    const uint8_t *srcU = (const uint8_t *)ycbcr->cb;
365    const uint8_t *srcV = (const uint8_t *)ycbcr->cr;
366    uint8_t *dstU = dst + dstVStride * dstStride;
367    uint8_t *dstV = dstU + (dstVStride >> 1) * (dstStride >> 1);
368
369    for (size_t y = height; y > 0; --y) {
370        memcpy(dst, src, width);
371        dst += dstStride;
372        src += ycbcr->ystride;
373    }
374    if (ycbcr->cstride == ycbcr->ystride >> 1 && ycbcr->chroma_step == 1) {
375        // planar
376        for (size_t y = height >> 1; y > 0; --y) {
377            memcpy(dstU, srcU, width >> 1);
378            dstU += dstStride >> 1;
379            srcU += ycbcr->cstride;
380            memcpy(dstV, srcV, width >> 1);
381            dstV += dstStride >> 1;
382            srcV += ycbcr->cstride;
383        }
384    } else {
385        // arbitrary
386        for (size_t y = height >> 1; y > 0; --y) {
387            for (size_t x = width >> 1; x > 0; --x) {
388                *dstU++ = *srcU;
389                *dstV++ = *srcV;
390                srcU += ycbcr->chroma_step;
391                srcV += ycbcr->chroma_step;
392            }
393            dstU += (dstStride >> 1) - (width >> 1);
394            dstV += (dstStride >> 1) - (width >> 1);
395            srcU += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step;
396            srcV += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step;
397        }
398    }
399}
400
401// static
402__attribute__((no_sanitize("integer")))
403void SoftVideoEncoderOMXComponent::ConvertYUV420SemiPlanarToYUV420Planar(
404        const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height) {
405    // TODO: add support for stride
406    int32_t outYsize = width * height;
407    uint32_t *outY  = (uint32_t *) outYUV;
408    uint16_t *outCb = (uint16_t *) (outYUV + outYsize);
409    uint16_t *outCr = (uint16_t *) (outYUV + outYsize + (outYsize >> 2));
410
411    /* Y copying */
412    memcpy(outY, inYVU, outYsize);
413
414    /* U & V copying */
415    // FIXME this only works if width is multiple of 4
416    uint32_t *inYVU_4 = (uint32_t *) (inYVU + outYsize);
417    for (int32_t i = height >> 1; i > 0; --i) {
418        for (int32_t j = width >> 2; j > 0; --j) {
419            uint32_t temp = *inYVU_4++;
420            uint32_t tempU = temp & 0xFF;
421            tempU = tempU | ((temp >> 8) & 0xFF00);
422
423            uint32_t tempV = (temp >> 8) & 0xFF;
424            tempV = tempV | ((temp >> 16) & 0xFF00);
425
426            *outCb++ = tempU;
427            *outCr++ = tempV;
428        }
429    }
430}
431
432// static
433__attribute__((no_sanitize("integer")))
434void SoftVideoEncoderOMXComponent::ConvertRGB32ToPlanar(
435        uint8_t *dstY, size_t dstStride, size_t dstVStride,
436        const uint8_t *src, size_t width, size_t height, size_t srcStride,
437        bool bgr) {
438    CHECK((width & 1) == 0);
439    CHECK((height & 1) == 0);
440
441    uint8_t *dstU = dstY + dstStride * dstVStride;
442    uint8_t *dstV = dstU + (dstStride >> 1) * (dstVStride >> 1);
443
444#ifdef SURFACE_IS_BGR32
445    bgr = !bgr;
446#endif
447
448    const size_t redOffset   = bgr ? 2 : 0;
449    const size_t greenOffset = 1;
450    const size_t blueOffset  = bgr ? 0 : 2;
451
452    for (size_t y = 0; y < height; ++y) {
453        for (size_t x = 0; x < width; ++x) {
454            unsigned red   = src[redOffset];
455            unsigned green = src[greenOffset];
456            unsigned blue  = src[blueOffset];
457
458            // using ITU-R BT.601 conversion matrix
459            unsigned luma =
460                ((red * 66 + green * 129 + blue * 25) >> 8) + 16;
461
462            dstY[x] = luma;
463
464            if ((x & 1) == 0 && (y & 1) == 0) {
465                unsigned U =
466                    ((-red * 38 - green * 74 + blue * 112) >> 8) + 128;
467
468                unsigned V =
469                    ((red * 112 - green * 94 - blue * 18) >> 8) + 128;
470
471                dstU[x >> 1] = U;
472                dstV[x >> 1] = V;
473            }
474            src += 4;
475        }
476
477        if ((y & 1) == 0) {
478            dstU += dstStride >> 1;
479            dstV += dstStride >> 1;
480        }
481
482        src += srcStride - 4 * width;
483        dstY += dstStride;
484    }
485}
486
487const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer(
488        uint8_t *dst, size_t dstSize,
489        const uint8_t *src, size_t srcSize,
490        size_t width, size_t height) const {
491    size_t dstStride = width;
492    size_t dstVStride = height;
493
494    MetadataBufferType bufferType = *(MetadataBufferType *)src;
495    bool usingANWBuffer = bufferType == kMetadataBufferTypeANWBuffer;
496    if (!usingANWBuffer && bufferType != kMetadataBufferTypeGrallocSource) {
497        ALOGE("Unsupported metadata type (%d)", bufferType);
498        return NULL;
499    }
500
501    buffer_handle_t handle;
502    int format;
503    size_t srcStride;
504    size_t srcVStride;
505    if (usingANWBuffer) {
506        if (srcSize < sizeof(VideoNativeMetadata)) {
507            ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoNativeMetadata));
508            return NULL;
509        }
510
511        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)src;
512        ANativeWindowBuffer *buffer = nativeMeta.pBuffer;
513        handle = buffer->handle;
514        format = buffer->format;
515        srcStride = buffer->stride;
516        srcVStride = buffer->height;
517        // convert stride from pixels to bytes
518        if (format != HAL_PIXEL_FORMAT_YV12 &&
519            format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
520            // TODO do we need to support other formats?
521            srcStride *= 4;
522        }
523
524        if (nativeMeta.nFenceFd >= 0) {
525            sp<Fence> fence = new Fence(nativeMeta.nFenceFd);
526            nativeMeta.nFenceFd = -1;
527            status_t err = fence->wait(IOMX::kFenceTimeoutMs);
528            if (err != OK) {
529                ALOGE("Timed out waiting on input fence");
530                return NULL;
531            }
532        }
533    } else {
534        // TODO: remove this part.  Check if anyone uses this.
535
536        if (srcSize < sizeof(VideoGrallocMetadata)) {
537            ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoGrallocMetadata));
538            return NULL;
539        }
540
541        VideoGrallocMetadata &grallocMeta = *(VideoGrallocMetadata *)(src);
542        handle = grallocMeta.pHandle;
543        // assume HAL_PIXEL_FORMAT_RGBA_8888
544        // there is no way to get the src stride without the graphic buffer
545        format = HAL_PIXEL_FORMAT_RGBA_8888;
546        srcStride = width * 4;
547        srcVStride = height;
548    }
549
550    size_t neededSize =
551        dstStride * dstVStride + (width >> 1)
552                + (dstStride >> 1) * ((dstVStride >> 1) + (height >> 1) - 1);
553    if (dstSize < neededSize) {
554        ALOGE("destination buffer is too small (%zu vs %zu)", dstSize, neededSize);
555        return NULL;
556    }
557
558    auto& mapper = GraphicBufferMapper::get();
559
560    void *bits = NULL;
561    struct android_ycbcr ycbcr;
562    status_t res;
563    if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
564        res = mapper.lockYCbCr(
565                 handle,
566                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
567                 Rect(width, height), &ycbcr);
568    } else {
569        res = mapper.lock(
570                 handle,
571                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
572                 Rect(width, height), &bits);
573    }
574    if (res != OK) {
575        ALOGE("Unable to lock image buffer %p for access", handle);
576        return NULL;
577    }
578
579    switch (format) {
580        case HAL_PIXEL_FORMAT_YV12:  // YCrCb / YVU planar
581            // convert to flex YUV
582            ycbcr.y = bits;
583            ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride;
584            ycbcr.cb = (uint8_t *)ycbcr.cr + (srcStride >> 1) * (srcVStride >> 1);
585            ycbcr.chroma_step = 1;
586            ycbcr.cstride = srcVStride >> 1;
587            ycbcr.ystride = srcVStride;
588            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
589            break;
590        case HAL_PIXEL_FORMAT_YCrCb_420_SP:  // YCrCb / YVU semiplanar, NV21
591            // convert to flex YUV
592            ycbcr.y = bits;
593            ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride;
594            ycbcr.cb = (uint8_t *)ycbcr.cr + 1;
595            ycbcr.chroma_step = 2;
596            ycbcr.cstride = srcVStride;
597            ycbcr.ystride = srcVStride;
598            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
599            break;
600        case HAL_PIXEL_FORMAT_YCbCr_420_888:
601            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
602            break;
603        case HAL_PIXEL_FORMAT_RGBA_8888:
604        case HAL_PIXEL_FORMAT_BGRA_8888:
605            ConvertRGB32ToPlanar(
606                    dst, dstStride, dstVStride,
607                    (const uint8_t *)bits, width, height, srcStride,
608                    format == HAL_PIXEL_FORMAT_BGRA_8888);
609            break;
610        default:
611            ALOGE("Unsupported pixel format %#x", format);
612            dst = NULL;
613            break;
614    }
615
616    if (mapper.unlock(handle) != OK) {
617        ALOGE("Unable to unlock image buffer %p for access", handle);
618    }
619
620    return dst;
621}
622
623OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex(
624        const char *name, OMX_INDEXTYPE *index) {
625    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers") ||
626        !strcmp(name, "OMX.google.android.index.storeANWBufferInMetadata")) {
627        *(int32_t*)index = kStoreMetaDataExtensionIndex;
628        return OMX_ErrorNone;
629    }
630    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
631}
632
633}  // namespace android
634