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