SoftVPXEncoder.cpp revision 30c08634416a99a0f627e4de3a5f49dcf0a72fd3
1/*
2 * Copyright (C) 2013 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// #define LOG_NDEBUG 0
18#define LOG_TAG "SoftVPXEncoder"
19#include "SoftVPXEncoder.h"
20
21#include <utils/Log.h>
22
23#include <media/hardware/HardwareAPI.h>
24#include <media/hardware/MetadataBufferType.h>
25#include <media/stagefright/foundation/ADebug.h>
26#include <media/stagefright/MediaDefs.h>
27
28namespace android {
29
30
31template<class T>
32static void InitOMXParams(T *params) {
33    params->nSize = sizeof(T);
34    // OMX IL 1.1.2
35    params->nVersion.s.nVersionMajor = 1;
36    params->nVersion.s.nVersionMinor = 1;
37    params->nVersion.s.nRevision = 2;
38    params->nVersion.s.nStep = 0;
39}
40
41
42static int GetCPUCoreCount() {
43    int cpuCoreCount = 1;
44#if defined(_SC_NPROCESSORS_ONLN)
45    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
46#else
47    // _SC_NPROC_ONLN must be defined...
48    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
49#endif
50    CHECK_GE(cpuCoreCount, 1);
51    return cpuCoreCount;
52}
53
54
55// This color conversion utility is copied from SoftMPEG4Encoder.cpp
56inline static void ConvertSemiPlanarToPlanar(uint8_t *inyuv,
57                                             uint8_t* outyuv,
58                                             int32_t width,
59                                             int32_t height) {
60    int32_t outYsize = width * height;
61    uint32_t *outy =  (uint32_t *) outyuv;
62    uint16_t *outcb = (uint16_t *) (outyuv + outYsize);
63    uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2));
64
65    /* Y copying */
66    memcpy(outy, inyuv, outYsize);
67
68    /* U & V copying */
69    uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
70    for (int32_t i = height >> 1; i > 0; --i) {
71        for (int32_t j = width >> 2; j > 0; --j) {
72            uint32_t temp = *inyuv_4++;
73            uint32_t tempU = temp & 0xFF;
74            tempU = tempU | ((temp >> 8) & 0xFF00);
75
76            uint32_t tempV = (temp >> 8) & 0xFF;
77            tempV = tempV | ((temp >> 16) & 0xFF00);
78
79            // Flip U and V
80            *outcb++ = tempV;
81            *outcr++ = tempU;
82        }
83    }
84}
85
86static void ConvertRGB32ToPlanar(
87        const uint8_t *src, uint8_t *dstY, int32_t width, int32_t height) {
88    CHECK((width & 1) == 0);
89    CHECK((height & 1) == 0);
90
91    uint8_t *dstU = dstY + width * height;
92    uint8_t *dstV = dstU + (width / 2) * (height / 2);
93
94    for (int32_t y = 0; y < height; ++y) {
95        for (int32_t x = 0; x < width; ++x) {
96#ifdef SURFACE_IS_BGR32
97            unsigned blue = src[4 * x];
98            unsigned green = src[4 * x + 1];
99            unsigned red= src[4 * x + 2];
100#else
101            unsigned red= src[4 * x];
102            unsigned green = src[4 * x + 1];
103            unsigned blue = src[4 * x + 2];
104#endif
105
106            unsigned luma =
107                ((red * 66 + green * 129 + blue * 25) >> 8) + 16;
108
109            dstY[x] = luma;
110
111            if ((x & 1) == 0 && (y & 1) == 0) {
112                unsigned U =
113                    ((-red * 38 - green * 74 + blue * 112) >> 8) + 128;
114
115                unsigned V =
116                    ((red * 112 - green * 94 - blue * 18) >> 8) + 128;
117
118                dstU[x / 2] = U;
119                dstV[x / 2] = V;
120            }
121        }
122
123        if ((y & 1) == 0) {
124            dstU += width / 2;
125            dstV += width / 2;
126        }
127
128        src += 4 * width;
129        dstY += width;
130    }
131}
132
133SoftVPXEncoder::SoftVPXEncoder(const char *name,
134                               const OMX_CALLBACKTYPE *callbacks,
135                               OMX_PTR appData,
136                               OMX_COMPONENTTYPE **component)
137    : SimpleSoftOMXComponent(name, callbacks, appData, component),
138      mCodecContext(NULL),
139      mCodecConfiguration(NULL),
140      mCodecInterface(NULL),
141      mWidth(176),
142      mHeight(144),
143      mBitrate(192000),  // in bps
144      mBitrateUpdated(false),
145      mBitrateControlMode(VPX_VBR),  // variable bitrate
146      mFrameDurationUs(33333),  // Defaults to 30 fps
147      mDCTPartitions(0),
148      mErrorResilience(OMX_FALSE),
149      mColorFormat(OMX_COLOR_FormatYUV420Planar),
150      mLevel(OMX_VIDEO_VP8Level_Version0),
151      mConversionBuffer(NULL),
152      mInputDataIsMeta(false),
153      mGrallocModule(NULL),
154      mKeyFrameRequested(false) {
155    initPorts();
156}
157
158
159SoftVPXEncoder::~SoftVPXEncoder() {
160    releaseEncoder();
161}
162
163
164void SoftVPXEncoder::initPorts() {
165    OMX_PARAM_PORTDEFINITIONTYPE inputPort;
166    OMX_PARAM_PORTDEFINITIONTYPE outputPort;
167
168    InitOMXParams(&inputPort);
169    InitOMXParams(&outputPort);
170
171    inputPort.nBufferCountMin = kNumBuffers;
172    inputPort.nBufferCountActual = inputPort.nBufferCountMin;
173    inputPort.bEnabled = OMX_TRUE;
174    inputPort.bPopulated = OMX_FALSE;
175    inputPort.eDomain = OMX_PortDomainVideo;
176    inputPort.bBuffersContiguous = OMX_FALSE;
177    inputPort.format.video.pNativeRender = NULL;
178    inputPort.format.video.nFrameWidth = mWidth;
179    inputPort.format.video.nFrameHeight = mHeight;
180    inputPort.format.video.nStride = inputPort.format.video.nFrameWidth;
181    inputPort.format.video.nSliceHeight = inputPort.format.video.nFrameHeight;
182    inputPort.format.video.nBitrate = 0;
183    // frameRate is reciprocal of frameDuration, which is
184    // in microseconds. It is also in Q16 format.
185    inputPort.format.video.xFramerate = (1000000/mFrameDurationUs) << 16;
186    inputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
187    inputPort.nPortIndex = kInputPortIndex;
188    inputPort.eDir = OMX_DirInput;
189    inputPort.nBufferAlignment = kInputBufferAlignment;
190    inputPort.format.video.cMIMEType =
191        const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
192    inputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
193    inputPort.format.video.eColorFormat = mColorFormat;
194    inputPort.format.video.pNativeWindow = NULL;
195    inputPort.nBufferSize =
196        (inputPort.format.video.nStride *
197        inputPort.format.video.nSliceHeight * 3) / 2;
198
199    addPort(inputPort);
200
201    outputPort.nBufferCountMin = kNumBuffers;
202    outputPort.nBufferCountActual = outputPort.nBufferCountMin;
203    outputPort.bEnabled = OMX_TRUE;
204    outputPort.bPopulated = OMX_FALSE;
205    outputPort.eDomain = OMX_PortDomainVideo;
206    outputPort.bBuffersContiguous = OMX_FALSE;
207    outputPort.format.video.pNativeRender = NULL;
208    outputPort.format.video.nFrameWidth = mWidth;
209    outputPort.format.video.nFrameHeight = mHeight;
210    outputPort.format.video.nStride = outputPort.format.video.nFrameWidth;
211    outputPort.format.video.nSliceHeight = outputPort.format.video.nFrameHeight;
212    outputPort.format.video.nBitrate = mBitrate;
213    outputPort.format.video.xFramerate = 0;
214    outputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
215    outputPort.nPortIndex = kOutputPortIndex;
216    outputPort.eDir = OMX_DirOutput;
217    outputPort.nBufferAlignment = kOutputBufferAlignment;
218    outputPort.format.video.cMIMEType =
219        const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VP8);
220    outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVP8;
221    outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused;
222    outputPort.format.video.pNativeWindow = NULL;
223    outputPort.nBufferSize = 256 * 1024;  // arbitrary
224
225    addPort(outputPort);
226}
227
228
229status_t SoftVPXEncoder::initEncoder() {
230    vpx_codec_err_t codec_return;
231
232    mCodecContext = new vpx_codec_ctx_t;
233    mCodecConfiguration = new vpx_codec_enc_cfg_t;
234    mCodecInterface = vpx_codec_vp8_cx();
235
236    if (mCodecInterface == NULL) {
237        return UNKNOWN_ERROR;
238    }
239
240    codec_return = vpx_codec_enc_config_default(mCodecInterface,
241                                                mCodecConfiguration,
242                                                0);  // Codec specific flags
243
244    if (codec_return != VPX_CODEC_OK) {
245        ALOGE("Error populating default configuration for vpx encoder.");
246        return UNKNOWN_ERROR;
247    }
248
249    mCodecConfiguration->g_w = mWidth;
250    mCodecConfiguration->g_h = mHeight;
251    mCodecConfiguration->g_threads = GetCPUCoreCount();
252    mCodecConfiguration->g_error_resilient = mErrorResilience;
253
254    switch (mLevel) {
255        case OMX_VIDEO_VP8Level_Version0:
256            mCodecConfiguration->g_profile = 0;
257            break;
258
259        case OMX_VIDEO_VP8Level_Version1:
260            mCodecConfiguration->g_profile = 1;
261            break;
262
263        case OMX_VIDEO_VP8Level_Version2:
264            mCodecConfiguration->g_profile = 2;
265            break;
266
267        case OMX_VIDEO_VP8Level_Version3:
268            mCodecConfiguration->g_profile = 3;
269            break;
270
271        default:
272            mCodecConfiguration->g_profile = 0;
273    }
274
275    // OMX timebase unit is microsecond
276    // g_timebase is in seconds (i.e. 1/1000000 seconds)
277    mCodecConfiguration->g_timebase.num = 1;
278    mCodecConfiguration->g_timebase.den = 1000000;
279    // rc_target_bitrate is in kbps, mBitrate in bps
280    mCodecConfiguration->rc_target_bitrate = mBitrate/1000;
281    mCodecConfiguration->rc_end_usage = mBitrateControlMode;
282
283    codec_return = vpx_codec_enc_init(mCodecContext,
284                                      mCodecInterface,
285                                      mCodecConfiguration,
286                                      0);  // flags
287
288    if (codec_return != VPX_CODEC_OK) {
289        ALOGE("Error initializing vpx encoder");
290        return UNKNOWN_ERROR;
291    }
292
293    codec_return = vpx_codec_control(mCodecContext,
294                                     VP8E_SET_TOKEN_PARTITIONS,
295                                     mDCTPartitions);
296    if (codec_return != VPX_CODEC_OK) {
297        ALOGE("Error setting dct partitions for vpx encoder.");
298        return UNKNOWN_ERROR;
299    }
300
301    if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) {
302        if (mConversionBuffer == NULL) {
303            mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
304            if (mConversionBuffer == NULL) {
305                ALOGE("Allocating conversion buffer failed.");
306                return UNKNOWN_ERROR;
307            }
308        }
309    }
310    return OK;
311}
312
313
314status_t SoftVPXEncoder::releaseEncoder() {
315    if (mCodecContext != NULL) {
316        vpx_codec_destroy(mCodecContext);
317        delete mCodecContext;
318        mCodecContext = NULL;
319    }
320
321    if (mCodecConfiguration != NULL) {
322        delete mCodecConfiguration;
323        mCodecConfiguration = NULL;
324    }
325
326    if (mConversionBuffer != NULL) {
327        delete mConversionBuffer;
328        mConversionBuffer = NULL;
329    }
330
331    // this one is not allocated by us
332    mCodecInterface = NULL;
333
334    return OK;
335}
336
337
338OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index,
339                                                   OMX_PTR param) {
340    // can include extension index OMX_INDEXEXTTYPE
341    const int32_t indexFull = index;
342
343    switch (indexFull) {
344        case OMX_IndexParamVideoPortFormat: {
345            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
346                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param;
347
348            if (formatParams->nPortIndex == kInputPortIndex) {
349                if (formatParams->nIndex >= kNumberOfSupportedColorFormats) {
350                    return OMX_ErrorNoMore;
351                }
352
353                // Color formats, in order of preference
354                if (formatParams->nIndex == 0) {
355                    formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
356                } else if (formatParams->nIndex == 1) {
357                    formatParams->eColorFormat =
358                        OMX_COLOR_FormatYUV420SemiPlanar;
359                } else {
360                    formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque;
361                }
362
363                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
364                // Converting from microseconds
365                // Also converting to Q16 format
366                formatParams->xFramerate = (1000000/mFrameDurationUs) << 16;
367                return OMX_ErrorNone;
368            } else if (formatParams->nPortIndex == kOutputPortIndex) {
369                formatParams->eCompressionFormat = OMX_VIDEO_CodingVP8;
370                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
371                formatParams->xFramerate = 0;
372                return OMX_ErrorNone;
373            } else {
374                return OMX_ErrorBadPortIndex;
375            }
376        }
377
378        case OMX_IndexParamVideoBitrate: {
379            OMX_VIDEO_PARAM_BITRATETYPE *bitrate =
380                (OMX_VIDEO_PARAM_BITRATETYPE *)param;
381
382                if (bitrate->nPortIndex != kOutputPortIndex) {
383                    return OMX_ErrorUnsupportedIndex;
384                }
385
386                bitrate->nTargetBitrate = mBitrate;
387
388                if (mBitrateControlMode == VPX_VBR) {
389                    bitrate->eControlRate = OMX_Video_ControlRateVariable;
390                } else if (mBitrateControlMode == VPX_CBR) {
391                    bitrate->eControlRate = OMX_Video_ControlRateConstant;
392                } else {
393                    return OMX_ErrorUnsupportedSetting;
394                }
395                return OMX_ErrorNone;
396        }
397
398        // VP8 specific parameters that use extension headers
399        case OMX_IndexParamVideoVp8: {
400            OMX_VIDEO_PARAM_VP8TYPE *vp8Params =
401                (OMX_VIDEO_PARAM_VP8TYPE *)param;
402
403                if (vp8Params->nPortIndex != kOutputPortIndex) {
404                    return OMX_ErrorUnsupportedIndex;
405                }
406
407                vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain;
408                vp8Params->eLevel = mLevel;
409                vp8Params->nDCTPartitions = mDCTPartitions;
410                vp8Params->bErrorResilientMode = mErrorResilience;
411                return OMX_ErrorNone;
412        }
413
414        case OMX_IndexParamVideoProfileLevelQuerySupported: {
415            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
416                (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
417
418            if (profileAndLevel->nPortIndex != kOutputPortIndex) {
419                return OMX_ErrorUnsupportedIndex;
420            }
421
422            switch (profileAndLevel->nProfileIndex) {
423                case 0:
424                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version0;
425                    break;
426
427                case 1:
428                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version1;
429                    break;
430
431                case 2:
432                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version2;
433                    break;
434
435                case 3:
436                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version3;
437                    break;
438
439                default:
440                    return OMX_ErrorNoMore;
441            }
442
443            profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain;
444            return OMX_ErrorNone;
445        }
446
447        case OMX_IndexParamVideoProfileLevelCurrent: {
448            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
449                (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
450
451            if (profileAndLevel->nPortIndex != kOutputPortIndex) {
452                return OMX_ErrorUnsupportedIndex;
453            }
454
455            profileAndLevel->eLevel = mLevel;
456            profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain;
457            return OMX_ErrorNone;
458        }
459
460        default:
461            return SimpleSoftOMXComponent::internalGetParameter(index, param);
462    }
463}
464
465
466OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index,
467                                                   const OMX_PTR param) {
468    // can include extension index OMX_INDEXEXTTYPE
469    const int32_t indexFull = index;
470
471    switch (indexFull) {
472        case OMX_IndexParamStandardComponentRole:
473            return internalSetRoleParams(
474                (const OMX_PARAM_COMPONENTROLETYPE *)param);
475
476        case OMX_IndexParamVideoBitrate:
477            return internalSetBitrateParams(
478                (const OMX_VIDEO_PARAM_BITRATETYPE *)param);
479
480        case OMX_IndexParamPortDefinition:
481        {
482            OMX_ERRORTYPE err = internalSetPortParams(
483                (const OMX_PARAM_PORTDEFINITIONTYPE *)param);
484
485            if (err != OMX_ErrorNone) {
486                return err;
487            }
488
489            return SimpleSoftOMXComponent::internalSetParameter(index, param);
490        }
491
492        case OMX_IndexParamVideoPortFormat:
493            return internalSetFormatParams(
494                (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param);
495
496        case OMX_IndexParamVideoVp8:
497            return internalSetVp8Params(
498                (const OMX_VIDEO_PARAM_VP8TYPE *)param);
499
500        case OMX_IndexParamVideoProfileLevelCurrent:
501            return internalSetProfileLevel(
502                (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param);
503
504        case OMX_IndexVendorStartUnused:
505        {
506            // storeMetaDataInBuffers
507            const StoreMetaDataInBuffersParams *storeParam =
508                (const StoreMetaDataInBuffersParams *)param;
509
510            if (storeParam->nPortIndex != kInputPortIndex) {
511                return OMX_ErrorBadPortIndex;
512            }
513
514            mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE);
515
516            return OMX_ErrorNone;
517        }
518
519        default:
520            return SimpleSoftOMXComponent::internalSetParameter(index, param);
521    }
522}
523
524OMX_ERRORTYPE SoftVPXEncoder::setConfig(
525        OMX_INDEXTYPE index, const OMX_PTR _params) {
526    switch (index) {
527        case OMX_IndexConfigVideoIntraVOPRefresh:
528        {
529            OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
530                (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params;
531
532            if (params->nPortIndex != kOutputPortIndex) {
533                return OMX_ErrorBadPortIndex;
534            }
535
536            mKeyFrameRequested = params->IntraRefreshVOP;
537            return OMX_ErrorNone;
538        }
539
540        case OMX_IndexConfigVideoBitrate:
541        {
542            OMX_VIDEO_CONFIG_BITRATETYPE *params =
543                (OMX_VIDEO_CONFIG_BITRATETYPE *)_params;
544
545            if (params->nPortIndex != kOutputPortIndex) {
546                return OMX_ErrorBadPortIndex;
547            }
548
549            if (mBitrate != params->nEncodeBitrate) {
550                mBitrate = params->nEncodeBitrate;
551                mBitrateUpdated = true;
552            }
553            return OMX_ErrorNone;
554        }
555
556        default:
557            return SimpleSoftOMXComponent::setConfig(index, _params);
558    }
559}
560
561OMX_ERRORTYPE SoftVPXEncoder::internalSetProfileLevel(
562        const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel) {
563    if (profileAndLevel->nPortIndex != kOutputPortIndex) {
564        return OMX_ErrorUnsupportedIndex;
565    }
566
567    if (profileAndLevel->eProfile != OMX_VIDEO_VP8ProfileMain) {
568        return OMX_ErrorBadParameter;
569    }
570
571    if (profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version0 ||
572        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version1 ||
573        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version2 ||
574        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version3) {
575        mLevel = (OMX_VIDEO_VP8LEVELTYPE)profileAndLevel->eLevel;
576    } else {
577        return OMX_ErrorBadParameter;
578    }
579
580    return OMX_ErrorNone;
581}
582
583
584OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params(
585        const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
586    if (vp8Params->nPortIndex != kOutputPortIndex) {
587        return OMX_ErrorUnsupportedIndex;
588    }
589
590    if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) {
591        return OMX_ErrorBadParameter;
592    }
593
594    if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 ||
595        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 ||
596        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 ||
597        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) {
598        mLevel = vp8Params->eLevel;
599    } else {
600        return OMX_ErrorBadParameter;
601    }
602
603    if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) {
604        mDCTPartitions = vp8Params->nDCTPartitions;
605    } else {
606        return OMX_ErrorBadParameter;
607    }
608
609    mErrorResilience = vp8Params->bErrorResilientMode;
610    return OMX_ErrorNone;
611}
612
613
614OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams(
615        const OMX_VIDEO_PARAM_PORTFORMATTYPE* format) {
616    if (format->nPortIndex == kInputPortIndex) {
617        if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar ||
618            format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
619            format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
620            mColorFormat = format->eColorFormat;
621
622            OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
623            def->format.video.eColorFormat = mColorFormat;
624
625            return OMX_ErrorNone;
626        } else {
627            ALOGE("Unsupported color format %i", format->eColorFormat);
628            return OMX_ErrorUnsupportedSetting;
629        }
630    } else if (format->nPortIndex == kOutputPortIndex) {
631        if (format->eCompressionFormat == OMX_VIDEO_CodingVP8) {
632            return OMX_ErrorNone;
633        } else {
634            return OMX_ErrorUnsupportedSetting;
635        }
636    } else {
637        return OMX_ErrorBadPortIndex;
638    }
639}
640
641
642OMX_ERRORTYPE SoftVPXEncoder::internalSetRoleParams(
643        const OMX_PARAM_COMPONENTROLETYPE* role) {
644    const char* roleText = (const char*)role->cRole;
645    const size_t roleTextMaxSize = OMX_MAX_STRINGNAME_SIZE - 1;
646
647    if (strncmp(roleText, "video_encoder.vp8", roleTextMaxSize)) {
648        ALOGE("Unsupported component role");
649        return OMX_ErrorBadParameter;
650    }
651
652    return OMX_ErrorNone;
653}
654
655
656OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams(
657        const OMX_PARAM_PORTDEFINITIONTYPE* port) {
658    if (port->nPortIndex == kInputPortIndex) {
659        mWidth = port->format.video.nFrameWidth;
660        mHeight = port->format.video.nFrameHeight;
661
662        // xFramerate comes in Q16 format, in frames per second unit
663        const uint32_t framerate = port->format.video.xFramerate >> 16;
664        // frame duration is in microseconds
665        mFrameDurationUs = (1000000/framerate);
666
667        if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar ||
668            port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
669            port->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
670            mColorFormat = port->format.video.eColorFormat;
671        } else {
672            return OMX_ErrorUnsupportedSetting;
673        }
674
675        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
676        def->format.video.nFrameWidth = mWidth;
677        def->format.video.nFrameHeight = mHeight;
678        def->format.video.xFramerate = port->format.video.xFramerate;
679        def->format.video.eColorFormat = mColorFormat;
680
681        return OMX_ErrorNone;
682    } else if (port->nPortIndex == kOutputPortIndex) {
683        mBitrate = port->format.video.nBitrate;
684        return OMX_ErrorNone;
685    } else {
686        return OMX_ErrorBadPortIndex;
687    }
688}
689
690
691OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams(
692        const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) {
693    if (bitrate->nPortIndex != kOutputPortIndex) {
694        return OMX_ErrorUnsupportedIndex;
695    }
696
697    mBitrate = bitrate->nTargetBitrate;
698
699    if (bitrate->eControlRate == OMX_Video_ControlRateVariable) {
700        mBitrateControlMode = VPX_VBR;
701    } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) {
702        mBitrateControlMode = VPX_CBR;
703    } else {
704        return OMX_ErrorUnsupportedSetting;
705    }
706
707    return OMX_ErrorNone;
708}
709
710
711void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) {
712    // Initialize encoder if not already
713    if (mCodecContext == NULL) {
714        if (OK != initEncoder()) {
715            ALOGE("Failed to initialize encoder");
716            notify(OMX_EventError,
717                   OMX_ErrorUndefined,
718                   0,  // Extra notification data
719                   NULL);  // Notification data pointer
720            return;
721        }
722    }
723
724    vpx_codec_err_t codec_return;
725    List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex);
726    List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex);
727
728    while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) {
729        BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin();
730        OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader;
731
732        BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin();
733        OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader;
734
735        if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
736            inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
737            inputBufferInfo->mOwnedByUs = false;
738            notifyEmptyBufferDone(inputBufferHeader);
739
740            outputBufferHeader->nFilledLen = 0;
741            outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS;
742
743            outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
744            outputBufferInfo->mOwnedByUs = false;
745            notifyFillBufferDone(outputBufferHeader);
746            return;
747        }
748
749        uint8_t *source =
750            inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
751
752        if (mInputDataIsMeta) {
753            CHECK_GE(inputBufferHeader->nFilledLen,
754                     4 + sizeof(buffer_handle_t));
755
756            uint32_t bufferType = *(uint32_t *)source;
757            CHECK_EQ(bufferType, kMetadataBufferTypeGrallocSource);
758
759            if (mGrallocModule == NULL) {
760                CHECK_EQ(0, hw_get_module(
761                            GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
762            }
763
764            const gralloc_module_t *grmodule =
765                (const gralloc_module_t *)mGrallocModule;
766
767            buffer_handle_t handle = *(buffer_handle_t *)(source + 4);
768
769            void *bits;
770            CHECK_EQ(0,
771                     grmodule->lock(
772                         grmodule, handle,
773                         GRALLOC_USAGE_SW_READ_OFTEN
774                            | GRALLOC_USAGE_SW_WRITE_NEVER,
775                         0, 0, mWidth, mHeight, &bits));
776
777            ConvertRGB32ToPlanar(
778                    (const uint8_t *)bits, mConversionBuffer, mWidth, mHeight);
779
780            source = mConversionBuffer;
781
782            CHECK_EQ(0, grmodule->unlock(grmodule, handle));
783        } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
784            ConvertSemiPlanarToPlanar(
785                    source, mConversionBuffer, mWidth, mHeight);
786
787            source = mConversionBuffer;
788        }
789        vpx_image_t raw_frame;
790        vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
791                     kInputBufferAlignment, source);
792
793        vpx_enc_frame_flags_t flags = 0;
794        if (mKeyFrameRequested) {
795            flags |= VPX_EFLAG_FORCE_KF;
796            mKeyFrameRequested = false;
797        }
798
799        if (mBitrateUpdated) {
800            mCodecConfiguration->rc_target_bitrate = mBitrate/1000;
801            vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext,
802                                                           mCodecConfiguration);
803            if (res != VPX_CODEC_OK) {
804                ALOGE("vp8 encoder failed to update bitrate: %s",
805                      vpx_codec_err_to_string(res));
806                notify(OMX_EventError,
807                       OMX_ErrorUndefined,
808                       0, // Extra notification data
809                       NULL); // Notification data pointer
810            }
811            mBitrateUpdated = false;
812        }
813
814        codec_return = vpx_codec_encode(
815                mCodecContext,
816                &raw_frame,
817                inputBufferHeader->nTimeStamp,  // in timebase units
818                mFrameDurationUs,  // frame duration in timebase units
819                flags,  // frame flags
820                VPX_DL_REALTIME);  // encoding deadline
821        if (codec_return != VPX_CODEC_OK) {
822            ALOGE("vpx encoder failed to encode frame");
823            notify(OMX_EventError,
824                   OMX_ErrorUndefined,
825                   0,  // Extra notification data
826                   NULL);  // Notification data pointer
827            return;
828        }
829
830        vpx_codec_iter_t encoded_packet_iterator = NULL;
831        const vpx_codec_cx_pkt_t* encoded_packet;
832
833        while ((encoded_packet = vpx_codec_get_cx_data(
834                        mCodecContext, &encoded_packet_iterator))) {
835            if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
836                outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts;
837                outputBufferHeader->nFlags = 0;
838                if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY)
839                  outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
840                outputBufferHeader->nOffset = 0;
841                outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz;
842                memcpy(outputBufferHeader->pBuffer,
843                       encoded_packet->data.frame.buf,
844                       encoded_packet->data.frame.sz);
845                outputBufferInfo->mOwnedByUs = false;
846                outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
847                notifyFillBufferDone(outputBufferHeader);
848            }
849        }
850
851        inputBufferInfo->mOwnedByUs = false;
852        inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
853        notifyEmptyBufferDone(inputBufferHeader);
854    }
855}
856
857OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex(
858        const char *name, OMX_INDEXTYPE *index) {
859    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) {
860        *index = OMX_IndexVendorStartUnused;
861        return OMX_ErrorNone;
862    }
863
864    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
865}
866
867}  // namespace android
868
869
870android::SoftOMXComponent *createSoftOMXComponent(
871        const char *name, const OMX_CALLBACKTYPE *callbacks,
872        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
873    return new android::SoftVPXEncoder(name, callbacks, appData, component);
874}
875