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