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