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