SoftVideoEncoderOMXComponent.cpp revision a21bed3d626d148e584bdddeeecf287b782b3fcb
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
176    if (!isValidOMXParam(port)) {
177        return OMX_ErrorBadParameter;
178    }
179
180    if (port->nPortIndex == kInputPortIndex) {
181        mWidth = port->format.video.nFrameWidth;
182        mHeight = port->format.video.nFrameHeight;
183
184        // xFramerate comes in Q16 format, in frames per second unit
185        mFramerate = port->format.video.xFramerate;
186
187        if (port->format.video.eCompressionFormat != OMX_VIDEO_CodingUnused
188                || (port->format.video.eColorFormat != OMX_COLOR_FormatYUV420Planar
189                        && port->format.video.eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar
190                        && port->format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque)) {
191            return OMX_ErrorUnsupportedSetting;
192        }
193
194        mColorFormat = port->format.video.eColorFormat;
195    } else if (port->nPortIndex == kOutputPortIndex) {
196        if (port->format.video.eCompressionFormat != mCodingType
197                || port->format.video.eColorFormat != OMX_COLOR_FormatUnused) {
198            return OMX_ErrorUnsupportedSetting;
199        }
200
201        mBitrate = port->format.video.nBitrate;
202    } else {
203        return OMX_ErrorBadPortIndex;
204    }
205
206    updatePortParams();
207    return OMX_ErrorNone;
208}
209
210OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalSetParameter(
211        OMX_INDEXTYPE index, const OMX_PTR param) {
212    // can include extension index OMX_INDEXEXTTYPE
213    const int32_t indexFull = index;
214
215    switch (indexFull) {
216        case OMX_IndexParamVideoErrorCorrection:
217        {
218            return OMX_ErrorNotImplemented;
219        }
220
221        case OMX_IndexParamStandardComponentRole:
222        {
223            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
224                (const OMX_PARAM_COMPONENTROLETYPE *)param;
225
226            if (!isValidOMXParam(roleParams)) {
227                return OMX_ErrorBadParameter;
228            }
229
230            if (strncmp((const char *)roleParams->cRole,
231                        mComponentRole,
232                        OMX_MAX_STRINGNAME_SIZE - 1)) {
233                return OMX_ErrorUnsupportedSetting;
234            }
235
236            return OMX_ErrorNone;
237        }
238
239        case OMX_IndexParamPortDefinition:
240        {
241            OMX_ERRORTYPE err = internalSetPortParams((const OMX_PARAM_PORTDEFINITIONTYPE *)param);
242
243            if (err != OMX_ErrorNone) {
244                return err;
245            }
246
247            return SimpleSoftOMXComponent::internalSetParameter(index, param);
248        }
249
250        case OMX_IndexParamVideoPortFormat:
251        {
252            const OMX_VIDEO_PARAM_PORTFORMATTYPE* format =
253                (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param;
254
255            if (!isValidOMXParam(format)) {
256                return OMX_ErrorBadParameter;
257            }
258
259            if (format->nPortIndex == kInputPortIndex) {
260                if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar ||
261                    format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
262                    format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
263                    mColorFormat = format->eColorFormat;
264
265                    updatePortParams();
266                    return OMX_ErrorNone;
267                } else {
268                    ALOGE("Unsupported color format %i", format->eColorFormat);
269                    return OMX_ErrorUnsupportedSetting;
270                }
271            } else if (format->nPortIndex == kOutputPortIndex) {
272                if (format->eCompressionFormat == mCodingType) {
273                    return OMX_ErrorNone;
274                } else {
275                    return OMX_ErrorUnsupportedSetting;
276                }
277            } else {
278                return OMX_ErrorBadPortIndex;
279            }
280        }
281
282        case kStoreMetaDataExtensionIndex:
283        {
284            // storeMetaDataInBuffers
285            const StoreMetaDataInBuffersParams *storeParam =
286                (const StoreMetaDataInBuffersParams *)param;
287
288            if (!isValidOMXParam(storeParam)) {
289                return OMX_ErrorBadParameter;
290            }
291
292            if (storeParam->nPortIndex == kOutputPortIndex) {
293                return storeParam->bStoreMetaData ? OMX_ErrorUnsupportedSetting : OMX_ErrorNone;
294            } else if (storeParam->nPortIndex != kInputPortIndex) {
295                return OMX_ErrorBadPortIndex;
296            }
297
298            mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE);
299            if (mInputDataIsMeta) {
300                mColorFormat = OMX_COLOR_FormatAndroidOpaque;
301            } else if (mColorFormat == OMX_COLOR_FormatAndroidOpaque) {
302                mColorFormat = OMX_COLOR_FormatYUV420Planar;
303            }
304            updatePortParams();
305            return OMX_ErrorNone;
306        }
307
308        default:
309            return SimpleSoftOMXComponent::internalSetParameter(index, param);
310    }
311}
312
313OMX_ERRORTYPE SoftVideoEncoderOMXComponent::internalGetParameter(
314        OMX_INDEXTYPE index, OMX_PTR param) {
315    switch ((int)index) {
316        case OMX_IndexParamVideoErrorCorrection:
317        {
318            return OMX_ErrorNotImplemented;
319        }
320
321        case OMX_IndexParamVideoPortFormat:
322        {
323            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
324                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param;
325
326            if (!isValidOMXParam(formatParams)) {
327                return OMX_ErrorBadParameter;
328            }
329
330            if (formatParams->nPortIndex == kInputPortIndex) {
331                if (formatParams->nIndex >= NELEM(kSupportedColorFormats)) {
332                    return OMX_ErrorNoMore;
333                }
334
335                // Color formats, in order of preference
336                formatParams->eColorFormat = kSupportedColorFormats[formatParams->nIndex];
337                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
338                formatParams->xFramerate = mFramerate;
339                return OMX_ErrorNone;
340            } else if (formatParams->nPortIndex == kOutputPortIndex) {
341                formatParams->eCompressionFormat = mCodingType;
342                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
343                formatParams->xFramerate = 0;
344                return OMX_ErrorNone;
345            } else {
346                return OMX_ErrorBadPortIndex;
347            }
348        }
349
350        case OMX_IndexParamVideoProfileLevelQuerySupported:
351        {
352            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
353                  (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) param;
354
355            if (!isValidOMXParam(profileLevel)) {
356                return OMX_ErrorBadParameter;
357            }
358
359            if (profileLevel->nPortIndex != kOutputPortIndex) {
360                ALOGE("Invalid port index: %u", profileLevel->nPortIndex);
361                return OMX_ErrorUnsupportedIndex;
362            }
363
364            if (profileLevel->nProfileIndex >= mNumProfileLevels) {
365                return OMX_ErrorNoMore;
366            }
367
368            profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile;
369            profileLevel->eLevel   = mProfileLevels[profileLevel->nProfileIndex].mLevel;
370            return OMX_ErrorNone;
371        }
372
373        case OMX_IndexParamConsumerUsageBits:
374        {
375            OMX_U32 *usageBits = (OMX_U32 *)param;
376            *usageBits = GRALLOC_USAGE_SW_READ_OFTEN;
377            return OMX_ErrorNone;
378        }
379
380        default:
381            return SimpleSoftOMXComponent::internalGetParameter(index, param);
382    }
383}
384
385// static
386void SoftVideoEncoderOMXComponent::ConvertFlexYUVToPlanar(
387        uint8_t *dst, size_t dstStride, size_t dstVStride,
388        struct android_ycbcr *ycbcr, int32_t width, int32_t height) {
389    const uint8_t *src = (const uint8_t *)ycbcr->y;
390    const uint8_t *srcU = (const uint8_t *)ycbcr->cb;
391    const uint8_t *srcV = (const uint8_t *)ycbcr->cr;
392    uint8_t *dstU = dst + dstVStride * dstStride;
393    uint8_t *dstV = dstU + (dstVStride >> 1) * (dstStride >> 1);
394
395    for (size_t y = height; y > 0; --y) {
396        memcpy(dst, src, width);
397        dst += dstStride;
398        src += ycbcr->ystride;
399    }
400    if (ycbcr->cstride == ycbcr->ystride >> 1 && ycbcr->chroma_step == 1) {
401        // planar
402        for (size_t y = height >> 1; y > 0; --y) {
403            memcpy(dstU, srcU, width >> 1);
404            dstU += dstStride >> 1;
405            srcU += ycbcr->cstride;
406            memcpy(dstV, srcV, width >> 1);
407            dstV += dstStride >> 1;
408            srcV += ycbcr->cstride;
409        }
410    } else {
411        // arbitrary
412        for (size_t y = height >> 1; y > 0; --y) {
413            for (size_t x = width >> 1; x > 0; --x) {
414                *dstU++ = *srcU;
415                *dstV++ = *srcV;
416                srcU += ycbcr->chroma_step;
417                srcV += ycbcr->chroma_step;
418            }
419            dstU += (dstStride >> 1) - (width >> 1);
420            dstV += (dstStride >> 1) - (width >> 1);
421            srcU += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step;
422            srcV += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step;
423        }
424    }
425}
426
427// static
428void SoftVideoEncoderOMXComponent::ConvertYUV420SemiPlanarToYUV420Planar(
429        const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height) {
430    // TODO: add support for stride
431    int32_t outYsize = width * height;
432    uint32_t *outY  = (uint32_t *) outYUV;
433    uint16_t *outCb = (uint16_t *) (outYUV + outYsize);
434    uint16_t *outCr = (uint16_t *) (outYUV + outYsize + (outYsize >> 2));
435
436    /* Y copying */
437    memcpy(outY, inYVU, outYsize);
438
439    /* U & V copying */
440    // FIXME this only works if width is multiple of 4
441    uint32_t *inYVU_4 = (uint32_t *) (inYVU + outYsize);
442    for (int32_t i = height >> 1; i > 0; --i) {
443        for (int32_t j = width >> 2; j > 0; --j) {
444            uint32_t temp = *inYVU_4++;
445            uint32_t tempU = temp & 0xFF;
446            tempU = tempU | ((temp >> 8) & 0xFF00);
447
448            uint32_t tempV = (temp >> 8) & 0xFF;
449            tempV = tempV | ((temp >> 16) & 0xFF00);
450
451            *outCb++ = tempU;
452            *outCr++ = tempV;
453        }
454    }
455}
456
457// static
458void SoftVideoEncoderOMXComponent::ConvertRGB32ToPlanar(
459        uint8_t *dstY, size_t dstStride, size_t dstVStride,
460        const uint8_t *src, size_t width, size_t height, size_t srcStride,
461        bool bgr) {
462    CHECK((width & 1) == 0);
463    CHECK((height & 1) == 0);
464
465    uint8_t *dstU = dstY + dstStride * dstVStride;
466    uint8_t *dstV = dstU + (dstStride >> 1) * (dstVStride >> 1);
467
468#ifdef SURFACE_IS_BGR32
469    bgr = !bgr;
470#endif
471
472    const size_t redOffset   = bgr ? 2 : 0;
473    const size_t greenOffset = 1;
474    const size_t blueOffset  = bgr ? 0 : 2;
475
476    for (size_t y = 0; y < height; ++y) {
477        for (size_t x = 0; x < width; ++x) {
478            unsigned red   = src[redOffset];
479            unsigned green = src[greenOffset];
480            unsigned blue  = src[blueOffset];
481
482            // using ITU-R BT.601 conversion matrix
483            unsigned luma =
484                ((red * 66 + green * 129 + blue * 25) >> 8) + 16;
485
486            dstY[x] = luma;
487
488            if ((x & 1) == 0 && (y & 1) == 0) {
489                unsigned U =
490                    ((-red * 38 - green * 74 + blue * 112) >> 8) + 128;
491
492                unsigned V =
493                    ((red * 112 - green * 94 - blue * 18) >> 8) + 128;
494
495                dstU[x >> 1] = U;
496                dstV[x >> 1] = V;
497            }
498            src += 4;
499        }
500
501        if ((y & 1) == 0) {
502            dstU += dstStride >> 1;
503            dstV += dstStride >> 1;
504        }
505
506        src += srcStride - 4 * width;
507        dstY += dstStride;
508    }
509}
510
511const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer(
512        uint8_t *dst, size_t dstSize,
513        const uint8_t *src, size_t srcSize,
514        size_t width, size_t height) const {
515    size_t dstStride = width;
516    size_t dstVStride = height;
517
518    MetadataBufferType bufferType = *(MetadataBufferType *)src;
519    bool usingANWBuffer = bufferType == kMetadataBufferTypeANWBuffer;
520    if (!usingANWBuffer && bufferType != kMetadataBufferTypeGrallocSource) {
521        ALOGE("Unsupported metadata type (%d)", bufferType);
522        return NULL;
523    }
524
525    if (mGrallocModule == NULL) {
526        CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
527    }
528
529    const gralloc_module_t *grmodule =
530        (const gralloc_module_t *)mGrallocModule;
531
532    buffer_handle_t handle;
533    int format;
534    size_t srcStride;
535    size_t srcVStride;
536    if (usingANWBuffer) {
537        if (srcSize < sizeof(VideoNativeMetadata)) {
538            ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoNativeMetadata));
539            return NULL;
540        }
541
542        VideoNativeMetadata &nativeMeta = *(VideoNativeMetadata *)src;
543        ANativeWindowBuffer *buffer = nativeMeta.pBuffer;
544        handle = buffer->handle;
545        format = buffer->format;
546        srcStride = buffer->stride;
547        srcVStride = buffer->height;
548        // convert stride from pixels to bytes
549        if (format != HAL_PIXEL_FORMAT_YV12 &&
550            format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
551            // TODO do we need to support other formats?
552            srcStride *= 4;
553        }
554
555        if (nativeMeta.nFenceFd >= 0) {
556            sp<Fence> fence = new Fence(nativeMeta.nFenceFd);
557            nativeMeta.nFenceFd = -1;
558            status_t err = fence->wait(IOMX::kFenceTimeoutMs);
559            if (err != OK) {
560                ALOGE("Timed out waiting on input fence");
561                return NULL;
562            }
563        }
564    } else {
565        // TODO: remove this part.  Check if anyone uses this.
566
567        if (srcSize < sizeof(VideoGrallocMetadata)) {
568            ALOGE("Metadata is too small (%zu vs %zu)", srcSize, sizeof(VideoGrallocMetadata));
569            return NULL;
570        }
571
572        VideoGrallocMetadata &grallocMeta = *(VideoGrallocMetadata *)(src);
573        handle = grallocMeta.pHandle;
574        // assume HAL_PIXEL_FORMAT_RGBA_8888
575        // there is no way to get the src stride without the graphic buffer
576        format = HAL_PIXEL_FORMAT_RGBA_8888;
577        srcStride = width * 4;
578        srcVStride = height;
579    }
580
581    size_t neededSize =
582        dstStride * dstVStride + (width >> 1)
583                + (dstStride >> 1) * ((dstVStride >> 1) + (height >> 1) - 1);
584    if (dstSize < neededSize) {
585        ALOGE("destination buffer is too small (%zu vs %zu)", dstSize, neededSize);
586        return NULL;
587    }
588
589    void *bits = NULL;
590    struct android_ycbcr ycbcr;
591    status_t res;
592    if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
593        res = grmodule->lock_ycbcr(
594                 grmodule, handle,
595                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
596                 0, 0, width, height, &ycbcr);
597    } else {
598        res = grmodule->lock(
599                 grmodule, handle,
600                 GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
601                 0, 0, width, height, &bits);
602    }
603    if (res != OK) {
604        ALOGE("Unable to lock image buffer %p for access", handle);
605        return NULL;
606    }
607
608    switch (format) {
609        case HAL_PIXEL_FORMAT_YV12:  // YCrCb / YVU planar
610            // convert to flex YUV
611            ycbcr.y = bits;
612            ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride;
613            ycbcr.cb = (uint8_t *)ycbcr.cr + (srcStride >> 1) * (srcVStride >> 1);
614            ycbcr.chroma_step = 1;
615            ycbcr.cstride = srcVStride >> 1;
616            ycbcr.ystride = srcVStride;
617            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
618            break;
619        case HAL_PIXEL_FORMAT_YCrCb_420_SP:  // YCrCb / YVU semiplanar, NV21
620            // convert to flex YUV
621            ycbcr.y = bits;
622            ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride;
623            ycbcr.cb = (uint8_t *)ycbcr.cr + 1;
624            ycbcr.chroma_step = 2;
625            ycbcr.cstride = srcVStride;
626            ycbcr.ystride = srcVStride;
627            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
628            break;
629        case HAL_PIXEL_FORMAT_YCbCr_420_888:
630            ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height);
631            break;
632        case HAL_PIXEL_FORMAT_RGBA_8888:
633        case HAL_PIXEL_FORMAT_BGRA_8888:
634            ConvertRGB32ToPlanar(
635                    dst, dstStride, dstVStride,
636                    (const uint8_t *)bits, width, height, srcStride,
637                    format == HAL_PIXEL_FORMAT_BGRA_8888);
638            break;
639        default:
640            ALOGE("Unsupported pixel format %#x", format);
641            dst = NULL;
642            break;
643    }
644
645    if (grmodule->unlock(grmodule, handle) != OK) {
646        ALOGE("Unable to unlock image buffer %p for access", handle);
647    }
648
649    return dst;
650}
651
652OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex(
653        const char *name, OMX_INDEXTYPE *index) {
654    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers") ||
655        !strcmp(name, "OMX.google.android.index.storeANWBufferInMetadata")) {
656        *(int32_t*)index = kStoreMetaDataExtensionIndex;
657        return OMX_ErrorNone;
658    }
659    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
660}
661
662}  // namespace android
663