SoftVPXEncoder.cpp revision a32d5435d9585794b72dd12546054f13adb845f2
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
30template<class T>
31static void InitOMXParams(T *params) {
32    params->nSize = sizeof(T);
33    // OMX IL 1.1.2
34    params->nVersion.s.nVersionMajor = 1;
35    params->nVersion.s.nVersionMinor = 1;
36    params->nVersion.s.nRevision = 2;
37    params->nVersion.s.nStep = 0;
38}
39
40
41static int GetCPUCoreCount() {
42    int cpuCoreCount = 1;
43#if defined(_SC_NPROCESSORS_ONLN)
44    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
45#else
46    // _SC_NPROC_ONLN must be defined...
47    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
48#endif
49    CHECK_GE(cpuCoreCount, 1);
50    return cpuCoreCount;
51}
52
53SoftVPXEncoder::SoftVPXEncoder(const char *name,
54                               const OMX_CALLBACKTYPE *callbacks,
55                               OMX_PTR appData,
56                               OMX_COMPONENTTYPE **component)
57    : SoftVideoEncoderOMXComponent(name, callbacks, appData, component),
58      mCodecContext(NULL),
59      mCodecConfiguration(NULL),
60      mCodecInterface(NULL),
61      mWidth(176),
62      mHeight(144),
63      mBitrate(192000),  // in bps
64      mFramerate(30 << 16), // in Q16 format
65      mBitrateUpdated(false),
66      mBitrateControlMode(VPX_VBR),  // variable bitrate
67      mDCTPartitions(0),
68      mErrorResilience(OMX_FALSE),
69      mColorFormat(OMX_COLOR_FormatYUV420Planar),
70      mLevel(OMX_VIDEO_VP8Level_Version0),
71      mKeyFrameInterval(0),
72      mMinQuantizer(0),
73      mMaxQuantizer(0),
74      mTemporalLayers(0),
75      mTemporalPatternType(OMX_VIDEO_VPXTemporalLayerPatternNone),
76      mTemporalPatternLength(0),
77      mTemporalPatternIdx(0),
78      mLastTimestamp(0x7FFFFFFFFFFFFFFFLL),
79      mConversionBuffer(NULL),
80      mInputDataIsMeta(false),
81      mKeyFrameRequested(false) {
82    memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio));
83    mTemporalLayerBitrateRatio[0] = 100;
84    initPorts();
85}
86
87
88SoftVPXEncoder::~SoftVPXEncoder() {
89    releaseEncoder();
90}
91
92
93void SoftVPXEncoder::initPorts() {
94    OMX_PARAM_PORTDEFINITIONTYPE inputPort;
95    OMX_PARAM_PORTDEFINITIONTYPE outputPort;
96
97    InitOMXParams(&inputPort);
98    InitOMXParams(&outputPort);
99
100    inputPort.nBufferCountMin = kNumBuffers;
101    inputPort.nBufferCountActual = inputPort.nBufferCountMin;
102    inputPort.bEnabled = OMX_TRUE;
103    inputPort.bPopulated = OMX_FALSE;
104    inputPort.eDomain = OMX_PortDomainVideo;
105    inputPort.bBuffersContiguous = OMX_FALSE;
106    inputPort.format.video.pNativeRender = NULL;
107    inputPort.format.video.nFrameWidth = mWidth;
108    inputPort.format.video.nFrameHeight = mHeight;
109    inputPort.format.video.nStride = inputPort.format.video.nFrameWidth;
110    inputPort.format.video.nSliceHeight = inputPort.format.video.nFrameHeight;
111    inputPort.format.video.nBitrate = 0;
112    // frameRate is in Q16 format.
113    inputPort.format.video.xFramerate = mFramerate;
114    inputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
115    inputPort.nPortIndex = kInputPortIndex;
116    inputPort.eDir = OMX_DirInput;
117    inputPort.nBufferAlignment = kInputBufferAlignment;
118    inputPort.format.video.cMIMEType =
119        const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
120    inputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
121    inputPort.format.video.eColorFormat = mColorFormat;
122    inputPort.format.video.pNativeWindow = NULL;
123    inputPort.nBufferSize =
124        (inputPort.format.video.nStride *
125        inputPort.format.video.nSliceHeight * 3) / 2;
126
127    addPort(inputPort);
128
129    outputPort.nBufferCountMin = kNumBuffers;
130    outputPort.nBufferCountActual = outputPort.nBufferCountMin;
131    outputPort.bEnabled = OMX_TRUE;
132    outputPort.bPopulated = OMX_FALSE;
133    outputPort.eDomain = OMX_PortDomainVideo;
134    outputPort.bBuffersContiguous = OMX_FALSE;
135    outputPort.format.video.pNativeRender = NULL;
136    outputPort.format.video.nFrameWidth = mWidth;
137    outputPort.format.video.nFrameHeight = mHeight;
138    outputPort.format.video.nStride = outputPort.format.video.nFrameWidth;
139    outputPort.format.video.nSliceHeight = outputPort.format.video.nFrameHeight;
140    outputPort.format.video.nBitrate = mBitrate;
141    outputPort.format.video.xFramerate = 0;
142    outputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
143    outputPort.nPortIndex = kOutputPortIndex;
144    outputPort.eDir = OMX_DirOutput;
145    outputPort.nBufferAlignment = kOutputBufferAlignment;
146    outputPort.format.video.cMIMEType =
147        const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VP8);
148    outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVP8;
149    outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused;
150    outputPort.format.video.pNativeWindow = NULL;
151    outputPort.nBufferSize = 1024 * 1024; // arbitrary
152
153    addPort(outputPort);
154}
155
156
157status_t SoftVPXEncoder::initEncoder() {
158    vpx_codec_err_t codec_return;
159
160    mCodecContext = new vpx_codec_ctx_t;
161    mCodecConfiguration = new vpx_codec_enc_cfg_t;
162    mCodecInterface = vpx_codec_vp8_cx();
163
164    if (mCodecInterface == NULL) {
165        return UNKNOWN_ERROR;
166    }
167    ALOGD("VP8: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
168          (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
169          mMinQuantizer, mMaxQuantizer);
170    codec_return = vpx_codec_enc_config_default(mCodecInterface,
171                                                mCodecConfiguration,
172                                                0);  // Codec specific flags
173
174    if (codec_return != VPX_CODEC_OK) {
175        ALOGE("Error populating default configuration for vpx encoder.");
176        return UNKNOWN_ERROR;
177    }
178
179    mCodecConfiguration->g_w = mWidth;
180    mCodecConfiguration->g_h = mHeight;
181    mCodecConfiguration->g_threads = GetCPUCoreCount();
182    mCodecConfiguration->g_error_resilient = mErrorResilience;
183
184    switch (mLevel) {
185        case OMX_VIDEO_VP8Level_Version0:
186            mCodecConfiguration->g_profile = 0;
187            break;
188
189        case OMX_VIDEO_VP8Level_Version1:
190            mCodecConfiguration->g_profile = 1;
191            break;
192
193        case OMX_VIDEO_VP8Level_Version2:
194            mCodecConfiguration->g_profile = 2;
195            break;
196
197        case OMX_VIDEO_VP8Level_Version3:
198            mCodecConfiguration->g_profile = 3;
199            break;
200
201        default:
202            mCodecConfiguration->g_profile = 0;
203    }
204
205    // OMX timebase unit is microsecond
206    // g_timebase is in seconds (i.e. 1/1000000 seconds)
207    mCodecConfiguration->g_timebase.num = 1;
208    mCodecConfiguration->g_timebase.den = 1000000;
209    // rc_target_bitrate is in kbps, mBitrate in bps
210    mCodecConfiguration->rc_target_bitrate = (mBitrate + 500) / 1000;
211    mCodecConfiguration->rc_end_usage = mBitrateControlMode;
212    // Disable frame drop - not allowed in MediaCodec now.
213    mCodecConfiguration->rc_dropframe_thresh = 0;
214    if (mBitrateControlMode == VPX_CBR) {
215        // Disable spatial resizing.
216        mCodecConfiguration->rc_resize_allowed = 0;
217        // Single-pass mode.
218        mCodecConfiguration->g_pass = VPX_RC_ONE_PASS;
219        // Maximum amount of bits that can be subtracted from the target
220        // bitrate - expressed as percentage of the target bitrate.
221        mCodecConfiguration->rc_undershoot_pct = 100;
222        // Maximum amount of bits that can be added to the target
223        // bitrate - expressed as percentage of the target bitrate.
224        mCodecConfiguration->rc_overshoot_pct = 15;
225        // Initial value of the buffer level in ms.
226        mCodecConfiguration->rc_buf_initial_sz = 500;
227        // Amount of data that the encoder should try to maintain in ms.
228        mCodecConfiguration->rc_buf_optimal_sz = 600;
229        // The amount of data that may be buffered by the decoding
230        // application in ms.
231        mCodecConfiguration->rc_buf_sz = 1000;
232        // Enable error resilience - needed for packet loss.
233        mCodecConfiguration->g_error_resilient = 1;
234        // Disable lagged encoding.
235        mCodecConfiguration->g_lag_in_frames = 0;
236        // Maximum key frame interval - for CBR boost to 3000
237        mCodecConfiguration->kf_max_dist = 3000;
238        // Encoder determines optimal key frame placement automatically.
239        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
240    }
241
242    // Frames temporal pattern - for now WebRTC like pattern is only supported.
243    switch (mTemporalLayers) {
244        case 0:
245        {
246            mTemporalPatternLength = 0;
247            break;
248        }
249        case 1:
250        {
251            mCodecConfiguration->ts_number_layers = 1;
252            mCodecConfiguration->ts_rate_decimator[0] = 1;
253            mCodecConfiguration->ts_periodicity = 1;
254            mCodecConfiguration->ts_layer_id[0] = 0;
255            mTemporalPattern[0] = kTemporalUpdateLastRefAll;
256            mTemporalPatternLength = 1;
257            break;
258        }
259        case 2:
260        {
261            mCodecConfiguration->ts_number_layers = 2;
262            mCodecConfiguration->ts_rate_decimator[0] = 2;
263            mCodecConfiguration->ts_rate_decimator[1] = 1;
264            mCodecConfiguration->ts_periodicity = 2;
265            mCodecConfiguration->ts_layer_id[0] = 0;
266            mCodecConfiguration->ts_layer_id[1] = 1;
267            mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
268            mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
269            mTemporalPattern[2] = kTemporalUpdateLastRefAltRef;
270            mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef;
271            mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
272            mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef;
273            mTemporalPattern[6] = kTemporalUpdateLastRefAltRef;
274            mTemporalPattern[7] = kTemporalUpdateNone;
275            mTemporalPatternLength = 8;
276            break;
277        }
278        case 3:
279        {
280            mCodecConfiguration->ts_number_layers = 3;
281            mCodecConfiguration->ts_rate_decimator[0] = 4;
282            mCodecConfiguration->ts_rate_decimator[1] = 2;
283            mCodecConfiguration->ts_rate_decimator[2] = 1;
284            mCodecConfiguration->ts_periodicity = 4;
285            mCodecConfiguration->ts_layer_id[0] = 0;
286            mCodecConfiguration->ts_layer_id[1] = 2;
287            mCodecConfiguration->ts_layer_id[2] = 1;
288            mCodecConfiguration->ts_layer_id[3] = 2;
289            mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
290            mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef;
291            mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
292            mTemporalPattern[3] = kTemporalUpdateNone;
293            mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
294            mTemporalPattern[5] = kTemporalUpdateNone;
295            mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef;
296            mTemporalPattern[7] = kTemporalUpdateNone;
297            mTemporalPatternLength = 8;
298            break;
299        }
300        default:
301        {
302            ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
303            return UNKNOWN_ERROR;
304        }
305    }
306
307    // Set bitrate values for each layer
308    for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) {
309        mCodecConfiguration->ts_target_bitrate[i] =
310            mCodecConfiguration->rc_target_bitrate *
311            mTemporalLayerBitrateRatio[i] / 100;
312    }
313    if (mKeyFrameInterval > 0) {
314        mCodecConfiguration->kf_max_dist = mKeyFrameInterval;
315        mCodecConfiguration->kf_min_dist = mKeyFrameInterval;
316        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
317    }
318    if (mMinQuantizer > 0) {
319        mCodecConfiguration->rc_min_quantizer = mMinQuantizer;
320    }
321    if (mMaxQuantizer > 0) {
322        mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
323    }
324
325    codec_return = vpx_codec_enc_init(mCodecContext,
326                                      mCodecInterface,
327                                      mCodecConfiguration,
328                                      0);  // flags
329
330    if (codec_return != VPX_CODEC_OK) {
331        ALOGE("Error initializing vpx encoder");
332        return UNKNOWN_ERROR;
333    }
334
335    codec_return = vpx_codec_control(mCodecContext,
336                                     VP8E_SET_TOKEN_PARTITIONS,
337                                     mDCTPartitions);
338    if (codec_return != VPX_CODEC_OK) {
339        ALOGE("Error setting dct partitions for vpx encoder.");
340        return UNKNOWN_ERROR;
341    }
342
343    // Extra CBR settings
344    if (mBitrateControlMode == VPX_CBR) {
345        codec_return = vpx_codec_control(mCodecContext,
346                                         VP8E_SET_STATIC_THRESHOLD,
347                                         1);
348        if (codec_return == VPX_CODEC_OK) {
349            uint32_t rc_max_intra_target =
350                mCodecConfiguration->rc_buf_optimal_sz * (mFramerate >> 17) / 10;
351            // Don't go below 3 times per frame bandwidth.
352            if (rc_max_intra_target < 300) {
353                rc_max_intra_target = 300;
354            }
355            codec_return = vpx_codec_control(mCodecContext,
356                                             VP8E_SET_MAX_INTRA_BITRATE_PCT,
357                                             rc_max_intra_target);
358        }
359        if (codec_return == VPX_CODEC_OK) {
360            codec_return = vpx_codec_control(mCodecContext,
361                                             VP8E_SET_CPUUSED,
362                                             -8);
363        }
364        if (codec_return != VPX_CODEC_OK) {
365            ALOGE("Error setting cbr parameters for vpx encoder.");
366            return UNKNOWN_ERROR;
367        }
368    }
369
370    if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) {
371        free(mConversionBuffer);
372        mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
373        if (mConversionBuffer == NULL) {
374            ALOGE("Allocating conversion buffer failed.");
375            return UNKNOWN_ERROR;
376        }
377    }
378    return OK;
379}
380
381
382status_t SoftVPXEncoder::releaseEncoder() {
383    if (mCodecContext != NULL) {
384        vpx_codec_destroy(mCodecContext);
385        delete mCodecContext;
386        mCodecContext = NULL;
387    }
388
389    if (mCodecConfiguration != NULL) {
390        delete mCodecConfiguration;
391        mCodecConfiguration = NULL;
392    }
393
394    if (mConversionBuffer != NULL) {
395        free(mConversionBuffer);
396        mConversionBuffer = NULL;
397    }
398
399    // this one is not allocated by us
400    mCodecInterface = NULL;
401
402    return OK;
403}
404
405
406OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index,
407                                                   OMX_PTR param) {
408    // can include extension index OMX_INDEXEXTTYPE
409    const int32_t indexFull = index;
410
411    switch (indexFull) {
412        case OMX_IndexParamVideoPortFormat: {
413            OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
414                (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param;
415
416            if (formatParams->nPortIndex == kInputPortIndex) {
417                if (formatParams->nIndex >= kNumberOfSupportedColorFormats) {
418                    return OMX_ErrorNoMore;
419                }
420
421                // Color formats, in order of preference
422                if (formatParams->nIndex == 0) {
423                    formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
424                } else if (formatParams->nIndex == 1) {
425                    formatParams->eColorFormat =
426                        OMX_COLOR_FormatYUV420SemiPlanar;
427                } else {
428                    formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque;
429                }
430
431                formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
432                formatParams->xFramerate = mFramerate;
433                return OMX_ErrorNone;
434            } else if (formatParams->nPortIndex == kOutputPortIndex) {
435                formatParams->eCompressionFormat = OMX_VIDEO_CodingVP8;
436                formatParams->eColorFormat = OMX_COLOR_FormatUnused;
437                formatParams->xFramerate = 0;
438                return OMX_ErrorNone;
439            } else {
440                return OMX_ErrorBadPortIndex;
441            }
442        }
443
444        case OMX_IndexParamVideoBitrate: {
445            OMX_VIDEO_PARAM_BITRATETYPE *bitrate =
446                (OMX_VIDEO_PARAM_BITRATETYPE *)param;
447
448                if (bitrate->nPortIndex != kOutputPortIndex) {
449                    return OMX_ErrorUnsupportedIndex;
450                }
451
452                bitrate->nTargetBitrate = mBitrate;
453
454                if (mBitrateControlMode == VPX_VBR) {
455                    bitrate->eControlRate = OMX_Video_ControlRateVariable;
456                } else if (mBitrateControlMode == VPX_CBR) {
457                    bitrate->eControlRate = OMX_Video_ControlRateConstant;
458                } else {
459                    return OMX_ErrorUnsupportedSetting;
460                }
461                return OMX_ErrorNone;
462        }
463
464        // VP8 specific parameters that use extension headers
465        case OMX_IndexParamVideoVp8: {
466            OMX_VIDEO_PARAM_VP8TYPE *vp8Params =
467                (OMX_VIDEO_PARAM_VP8TYPE *)param;
468
469                if (vp8Params->nPortIndex != kOutputPortIndex) {
470                    return OMX_ErrorUnsupportedIndex;
471                }
472
473                vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain;
474                vp8Params->eLevel = mLevel;
475                vp8Params->nDCTPartitions = mDCTPartitions;
476                vp8Params->bErrorResilientMode = mErrorResilience;
477                return OMX_ErrorNone;
478        }
479
480        case OMX_IndexParamVideoAndroidVp8Encoder: {
481            OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vp8AndroidParams =
482                (OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param;
483
484                if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
485                    return OMX_ErrorUnsupportedIndex;
486                }
487
488                vp8AndroidParams->nKeyFrameInterval = mKeyFrameInterval;
489                vp8AndroidParams->eTemporalPattern = mTemporalPatternType;
490                vp8AndroidParams->nTemporalLayerCount = mTemporalLayers;
491                vp8AndroidParams->nMinQuantizer = mMinQuantizer;
492                vp8AndroidParams->nMaxQuantizer = mMaxQuantizer;
493                memcpy(vp8AndroidParams->nTemporalLayerBitrateRatio,
494                       mTemporalLayerBitrateRatio, sizeof(mTemporalLayerBitrateRatio));
495                return OMX_ErrorNone;
496        }
497
498        case OMX_IndexParamVideoProfileLevelQuerySupported: {
499            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
500                (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
501
502            if (profileAndLevel->nPortIndex != kOutputPortIndex) {
503                return OMX_ErrorUnsupportedIndex;
504            }
505
506            switch (profileAndLevel->nProfileIndex) {
507                case 0:
508                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version0;
509                    break;
510
511                case 1:
512                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version1;
513                    break;
514
515                case 2:
516                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version2;
517                    break;
518
519                case 3:
520                    profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version3;
521                    break;
522
523                default:
524                    return OMX_ErrorNoMore;
525            }
526
527            profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain;
528            return OMX_ErrorNone;
529        }
530
531        case OMX_IndexParamVideoProfileLevelCurrent: {
532            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
533                (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
534
535            if (profileAndLevel->nPortIndex != kOutputPortIndex) {
536                return OMX_ErrorUnsupportedIndex;
537            }
538
539            profileAndLevel->eLevel = mLevel;
540            profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain;
541            return OMX_ErrorNone;
542        }
543
544        default:
545            return SimpleSoftOMXComponent::internalGetParameter(index, param);
546    }
547}
548
549
550OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index,
551                                                   const OMX_PTR param) {
552    // can include extension index OMX_INDEXEXTTYPE
553    const int32_t indexFull = index;
554
555    switch (indexFull) {
556        case OMX_IndexParamStandardComponentRole:
557            return internalSetRoleParams(
558                (const OMX_PARAM_COMPONENTROLETYPE *)param);
559
560        case OMX_IndexParamVideoBitrate:
561            return internalSetBitrateParams(
562                (const OMX_VIDEO_PARAM_BITRATETYPE *)param);
563
564        case OMX_IndexParamPortDefinition:
565        {
566            OMX_ERRORTYPE err = internalSetPortParams(
567                (const OMX_PARAM_PORTDEFINITIONTYPE *)param);
568
569            if (err != OMX_ErrorNone) {
570                return err;
571            }
572
573            return SimpleSoftOMXComponent::internalSetParameter(index, param);
574        }
575
576        case OMX_IndexParamVideoPortFormat:
577            return internalSetFormatParams(
578                (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param);
579
580        case OMX_IndexParamVideoVp8:
581            return internalSetVp8Params(
582                (const OMX_VIDEO_PARAM_VP8TYPE *)param);
583
584        case OMX_IndexParamVideoAndroidVp8Encoder:
585            return internalSetAndroidVp8Params(
586                (const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param);
587
588        case OMX_IndexParamVideoProfileLevelCurrent:
589            return internalSetProfileLevel(
590                (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param);
591
592        case kStoreMetaDataExtensionIndex:
593        {
594            // storeMetaDataInBuffers
595            const StoreMetaDataInBuffersParams *storeParam =
596                (const StoreMetaDataInBuffersParams *)param;
597
598            if (storeParam->nPortIndex != kInputPortIndex) {
599                return OMX_ErrorBadPortIndex;
600            }
601
602            mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE);
603
604            return OMX_ErrorNone;
605        }
606
607        default:
608            return SimpleSoftOMXComponent::internalSetParameter(index, param);
609    }
610}
611
612OMX_ERRORTYPE SoftVPXEncoder::setConfig(
613        OMX_INDEXTYPE index, const OMX_PTR _params) {
614    switch (index) {
615        case OMX_IndexConfigVideoIntraVOPRefresh:
616        {
617            OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
618                (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params;
619
620            if (params->nPortIndex != kOutputPortIndex) {
621                return OMX_ErrorBadPortIndex;
622            }
623
624            mKeyFrameRequested = params->IntraRefreshVOP;
625            return OMX_ErrorNone;
626        }
627
628        case OMX_IndexConfigVideoBitrate:
629        {
630            OMX_VIDEO_CONFIG_BITRATETYPE *params =
631                (OMX_VIDEO_CONFIG_BITRATETYPE *)_params;
632
633            if (params->nPortIndex != kOutputPortIndex) {
634                return OMX_ErrorBadPortIndex;
635            }
636
637            if (mBitrate != params->nEncodeBitrate) {
638                mBitrate = params->nEncodeBitrate;
639                mBitrateUpdated = true;
640            }
641            return OMX_ErrorNone;
642        }
643
644        default:
645            return SimpleSoftOMXComponent::setConfig(index, _params);
646    }
647}
648
649OMX_ERRORTYPE SoftVPXEncoder::internalSetProfileLevel(
650        const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel) {
651    if (profileAndLevel->nPortIndex != kOutputPortIndex) {
652        return OMX_ErrorUnsupportedIndex;
653    }
654
655    if (profileAndLevel->eProfile != OMX_VIDEO_VP8ProfileMain) {
656        return OMX_ErrorBadParameter;
657    }
658
659    if (profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version0 ||
660        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version1 ||
661        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version2 ||
662        profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version3) {
663        mLevel = (OMX_VIDEO_VP8LEVELTYPE)profileAndLevel->eLevel;
664    } else {
665        return OMX_ErrorBadParameter;
666    }
667
668    return OMX_ErrorNone;
669}
670
671
672OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params(
673        const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
674    if (vp8Params->nPortIndex != kOutputPortIndex) {
675        return OMX_ErrorUnsupportedIndex;
676    }
677
678    if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) {
679        return OMX_ErrorBadParameter;
680    }
681
682    if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 ||
683        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 ||
684        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 ||
685        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) {
686        mLevel = vp8Params->eLevel;
687    } else {
688        return OMX_ErrorBadParameter;
689    }
690
691    if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) {
692        mDCTPartitions = vp8Params->nDCTPartitions;
693    } else {
694        return OMX_ErrorBadParameter;
695    }
696
697    mErrorResilience = vp8Params->bErrorResilientMode;
698    return OMX_ErrorNone;
699}
700
701OMX_ERRORTYPE SoftVPXEncoder::internalSetAndroidVp8Params(
702        const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams) {
703    if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
704        return OMX_ErrorUnsupportedIndex;
705    }
706    if (vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternNone &&
707        vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
708        return OMX_ErrorBadParameter;
709    }
710    if (vp8AndroidParams->nTemporalLayerCount > OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) {
711        return OMX_ErrorBadParameter;
712    }
713    if (vp8AndroidParams->nMinQuantizer > vp8AndroidParams->nMaxQuantizer) {
714        return OMX_ErrorBadParameter;
715    }
716
717    mTemporalPatternType = vp8AndroidParams->eTemporalPattern;
718    if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
719        mTemporalLayers = vp8AndroidParams->nTemporalLayerCount;
720    } else if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternNone) {
721        mTemporalLayers = 0;
722    }
723    // Check the bitrate distribution between layers is in increasing order
724    if (mTemporalLayers > 1) {
725        for (size_t i = 0; i < mTemporalLayers - 1; i++) {
726            if (vp8AndroidParams->nTemporalLayerBitrateRatio[i + 1] <=
727                    vp8AndroidParams->nTemporalLayerBitrateRatio[i]) {
728                ALOGE("Wrong bitrate ratio - should be in increasing order.");
729                return OMX_ErrorBadParameter;
730            }
731        }
732    }
733    mKeyFrameInterval = vp8AndroidParams->nKeyFrameInterval;
734    mMinQuantizer = vp8AndroidParams->nMinQuantizer;
735    mMaxQuantizer = vp8AndroidParams->nMaxQuantizer;
736    memcpy(mTemporalLayerBitrateRatio, vp8AndroidParams->nTemporalLayerBitrateRatio,
737            sizeof(mTemporalLayerBitrateRatio));
738    ALOGD("VP8: internalSetAndroidVp8Params. BRMode: %u. TS: %zu. KF: %u."
739          " QP: %u - %u BR0: %u. BR1: %u. BR2: %u",
740          (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
741          mMinQuantizer, mMaxQuantizer, mTemporalLayerBitrateRatio[0],
742          mTemporalLayerBitrateRatio[1], mTemporalLayerBitrateRatio[2]);
743    return OMX_ErrorNone;
744}
745
746OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams(
747        const OMX_VIDEO_PARAM_PORTFORMATTYPE* format) {
748    if (format->nPortIndex == kInputPortIndex) {
749        if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar ||
750            format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
751            format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
752            mColorFormat = format->eColorFormat;
753
754            OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
755            def->format.video.eColorFormat = mColorFormat;
756
757            return OMX_ErrorNone;
758        } else {
759            ALOGE("Unsupported color format %i", format->eColorFormat);
760            return OMX_ErrorUnsupportedSetting;
761        }
762    } else if (format->nPortIndex == kOutputPortIndex) {
763        if (format->eCompressionFormat == OMX_VIDEO_CodingVP8) {
764            return OMX_ErrorNone;
765        } else {
766            return OMX_ErrorUnsupportedSetting;
767        }
768    } else {
769        return OMX_ErrorBadPortIndex;
770    }
771}
772
773
774OMX_ERRORTYPE SoftVPXEncoder::internalSetRoleParams(
775        const OMX_PARAM_COMPONENTROLETYPE* role) {
776    const char* roleText = (const char*)role->cRole;
777    const size_t roleTextMaxSize = OMX_MAX_STRINGNAME_SIZE - 1;
778
779    if (strncmp(roleText, "video_encoder.vp8", roleTextMaxSize)) {
780        ALOGE("Unsupported component role");
781        return OMX_ErrorBadParameter;
782    }
783
784    return OMX_ErrorNone;
785}
786
787
788OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams(
789        const OMX_PARAM_PORTDEFINITIONTYPE* port) {
790    if (port->nPortIndex == kInputPortIndex) {
791        mWidth = port->format.video.nFrameWidth;
792        mHeight = port->format.video.nFrameHeight;
793
794        // xFramerate comes in Q16 format, in frames per second unit
795        mFramerate = port->format.video.xFramerate;
796
797        if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar ||
798            port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
799            port->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
800            mColorFormat = port->format.video.eColorFormat;
801        } else {
802            return OMX_ErrorUnsupportedSetting;
803        }
804
805        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
806        def->format.video.nFrameWidth = mWidth;
807        def->format.video.nFrameHeight = mHeight;
808        def->format.video.nStride = def->format.video.nFrameWidth;
809        def->format.video.nSliceHeight = def->format.video.nFrameHeight;
810        def->format.video.xFramerate = mFramerate;
811        def->format.video.eColorFormat = mColorFormat;
812        def->nBufferSize =
813            (def->format.video.nStride * def->format.video.nSliceHeight * 3) / 2;
814        def = &editPortInfo(kOutputPortIndex)->mDef;
815        def->format.video.nFrameWidth = mWidth;
816        def->format.video.nFrameHeight = mHeight;
817
818        return OMX_ErrorNone;
819    } else if (port->nPortIndex == kOutputPortIndex) {
820        mBitrate = port->format.video.nBitrate;
821        mWidth = port->format.video.nFrameWidth;
822        mHeight = port->format.video.nFrameHeight;
823
824        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
825        def->format.video.nFrameWidth = mWidth;
826        def->format.video.nFrameHeight = mHeight;
827        def->format.video.nBitrate = mBitrate;
828        return OMX_ErrorNone;
829    } else {
830        return OMX_ErrorBadPortIndex;
831    }
832}
833
834
835OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams(
836        const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) {
837    if (bitrate->nPortIndex != kOutputPortIndex) {
838        return OMX_ErrorUnsupportedIndex;
839    }
840
841    mBitrate = bitrate->nTargetBitrate;
842
843    if (bitrate->eControlRate == OMX_Video_ControlRateVariable) {
844        mBitrateControlMode = VPX_VBR;
845    } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) {
846        mBitrateControlMode = VPX_CBR;
847    } else {
848        return OMX_ErrorUnsupportedSetting;
849    }
850
851    return OMX_ErrorNone;
852}
853
854vpx_enc_frame_flags_t SoftVPXEncoder::getEncodeFlags() {
855    vpx_enc_frame_flags_t flags = 0;
856    int patternIdx = mTemporalPatternIdx % mTemporalPatternLength;
857    mTemporalPatternIdx++;
858    switch (mTemporalPattern[patternIdx]) {
859        case kTemporalUpdateLast:
860            flags |= VP8_EFLAG_NO_UPD_GF;
861            flags |= VP8_EFLAG_NO_UPD_ARF;
862            flags |= VP8_EFLAG_NO_REF_GF;
863            flags |= VP8_EFLAG_NO_REF_ARF;
864            break;
865        case kTemporalUpdateGoldenWithoutDependency:
866            flags |= VP8_EFLAG_NO_REF_GF;
867            // Deliberately no break here.
868        case kTemporalUpdateGolden:
869            flags |= VP8_EFLAG_NO_REF_ARF;
870            flags |= VP8_EFLAG_NO_UPD_ARF;
871            flags |= VP8_EFLAG_NO_UPD_LAST;
872            break;
873        case kTemporalUpdateAltrefWithoutDependency:
874            flags |= VP8_EFLAG_NO_REF_ARF;
875            flags |= VP8_EFLAG_NO_REF_GF;
876            // Deliberately no break here.
877        case kTemporalUpdateAltref:
878            flags |= VP8_EFLAG_NO_UPD_GF;
879            flags |= VP8_EFLAG_NO_UPD_LAST;
880            break;
881        case kTemporalUpdateNoneNoRefAltref:
882            flags |= VP8_EFLAG_NO_REF_ARF;
883            // Deliberately no break here.
884        case kTemporalUpdateNone:
885            flags |= VP8_EFLAG_NO_UPD_GF;
886            flags |= VP8_EFLAG_NO_UPD_ARF;
887            flags |= VP8_EFLAG_NO_UPD_LAST;
888            flags |= VP8_EFLAG_NO_UPD_ENTROPY;
889            break;
890        case kTemporalUpdateNoneNoRefGoldenRefAltRef:
891            flags |= VP8_EFLAG_NO_REF_GF;
892            flags |= VP8_EFLAG_NO_UPD_GF;
893            flags |= VP8_EFLAG_NO_UPD_ARF;
894            flags |= VP8_EFLAG_NO_UPD_LAST;
895            flags |= VP8_EFLAG_NO_UPD_ENTROPY;
896            break;
897        case kTemporalUpdateGoldenWithoutDependencyRefAltRef:
898            flags |= VP8_EFLAG_NO_REF_GF;
899            flags |= VP8_EFLAG_NO_UPD_ARF;
900            flags |= VP8_EFLAG_NO_UPD_LAST;
901            break;
902        case kTemporalUpdateLastRefAltRef:
903            flags |= VP8_EFLAG_NO_UPD_GF;
904            flags |= VP8_EFLAG_NO_UPD_ARF;
905            flags |= VP8_EFLAG_NO_REF_GF;
906            break;
907        case kTemporalUpdateGoldenRefAltRef:
908            flags |= VP8_EFLAG_NO_UPD_ARF;
909            flags |= VP8_EFLAG_NO_UPD_LAST;
910            break;
911        case kTemporalUpdateLastAndGoldenRefAltRef:
912            flags |= VP8_EFLAG_NO_UPD_ARF;
913            flags |= VP8_EFLAG_NO_REF_GF;
914            break;
915        case kTemporalUpdateLastRefAll:
916            flags |= VP8_EFLAG_NO_UPD_ARF;
917            flags |= VP8_EFLAG_NO_UPD_GF;
918            break;
919    }
920    return flags;
921}
922
923void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) {
924    // Initialize encoder if not already
925    if (mCodecContext == NULL) {
926        if (OK != initEncoder()) {
927            ALOGE("Failed to initialize encoder");
928            notify(OMX_EventError,
929                   OMX_ErrorUndefined,
930                   0,  // Extra notification data
931                   NULL);  // Notification data pointer
932            return;
933        }
934    }
935
936    vpx_codec_err_t codec_return;
937    List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex);
938    List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex);
939
940    while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) {
941        BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin();
942        OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader;
943
944        BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin();
945        OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader;
946
947        if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
948            inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
949            inputBufferInfo->mOwnedByUs = false;
950            notifyEmptyBufferDone(inputBufferHeader);
951
952            outputBufferHeader->nFilledLen = 0;
953            outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS;
954
955            outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
956            outputBufferInfo->mOwnedByUs = false;
957            notifyFillBufferDone(outputBufferHeader);
958            return;
959        }
960
961        const uint8_t *source =
962            inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
963
964        if (mInputDataIsMeta) {
965            source = extractGraphicBuffer(
966                    mConversionBuffer, mWidth * mHeight * 3 / 2,
967                    source, inputBufferHeader->nFilledLen,
968                    mWidth, mHeight);
969            if (source == NULL) {
970                ALOGE("Unable to extract gralloc buffer in metadata mode");
971                notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
972                return;
973            }
974        } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
975            ConvertYUV420SemiPlanarToYUV420Planar(
976                    source, mConversionBuffer, mWidth, mHeight);
977
978            source = mConversionBuffer;
979        }
980        vpx_image_t raw_frame;
981        vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
982                     kInputBufferAlignment, (uint8_t *)source);
983
984        vpx_enc_frame_flags_t flags = 0;
985        if (mTemporalPatternLength > 0) {
986            flags = getEncodeFlags();
987        }
988        if (mKeyFrameRequested) {
989            flags |= VPX_EFLAG_FORCE_KF;
990            mKeyFrameRequested = false;
991        }
992
993        if (mBitrateUpdated) {
994            mCodecConfiguration->rc_target_bitrate = mBitrate/1000;
995            vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext,
996                                                           mCodecConfiguration);
997            if (res != VPX_CODEC_OK) {
998                ALOGE("vp8 encoder failed to update bitrate: %s",
999                      vpx_codec_err_to_string(res));
1000                notify(OMX_EventError,
1001                       OMX_ErrorUndefined,
1002                       0, // Extra notification data
1003                       NULL); // Notification data pointer
1004            }
1005            mBitrateUpdated = false;
1006        }
1007
1008        uint32_t frameDuration;
1009        if (inputBufferHeader->nTimeStamp > mLastTimestamp) {
1010            frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp);
1011        } else {
1012            frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate);
1013        }
1014        mLastTimestamp = inputBufferHeader->nTimeStamp;
1015        codec_return = vpx_codec_encode(
1016                mCodecContext,
1017                &raw_frame,
1018                inputBufferHeader->nTimeStamp,  // in timebase units
1019                frameDuration,  // frame duration in timebase units
1020                flags,  // frame flags
1021                VPX_DL_REALTIME);  // encoding deadline
1022        if (codec_return != VPX_CODEC_OK) {
1023            ALOGE("vpx encoder failed to encode frame");
1024            notify(OMX_EventError,
1025                   OMX_ErrorUndefined,
1026                   0,  // Extra notification data
1027                   NULL);  // Notification data pointer
1028            return;
1029        }
1030
1031        vpx_codec_iter_t encoded_packet_iterator = NULL;
1032        const vpx_codec_cx_pkt_t* encoded_packet;
1033
1034        while ((encoded_packet = vpx_codec_get_cx_data(
1035                        mCodecContext, &encoded_packet_iterator))) {
1036            if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
1037                outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts;
1038                outputBufferHeader->nFlags = 0;
1039                if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY)
1040                  outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
1041                outputBufferHeader->nOffset = 0;
1042                outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz;
1043                memcpy(outputBufferHeader->pBuffer,
1044                       encoded_packet->data.frame.buf,
1045                       encoded_packet->data.frame.sz);
1046                outputBufferInfo->mOwnedByUs = false;
1047                outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
1048                notifyFillBufferDone(outputBufferHeader);
1049            }
1050        }
1051
1052        inputBufferInfo->mOwnedByUs = false;
1053        inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
1054        notifyEmptyBufferDone(inputBufferHeader);
1055    }
1056}
1057
1058}  // namespace android
1059
1060
1061android::SoftOMXComponent *createSoftOMXComponent(
1062        const char *name, const OMX_CALLBACKTYPE *callbacks,
1063        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
1064    return new android::SoftVPXEncoder(name, callbacks, appData, component);
1065}
1066