SoftVPXEncoder.cpp revision a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5
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#include <utils/misc.h>
23
24#include <media/hardware/HardwareAPI.h>
25#include <media/hardware/MetadataBufferType.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/MediaDefs.h>
28
29namespace android {
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
54static const CodecProfileLevel kProfileLevels[] = {
55    { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version0 },
56    { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version1 },
57    { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version2 },
58    { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version3 },
59};
60
61SoftVPXEncoder::SoftVPXEncoder(const char *name,
62                               const OMX_CALLBACKTYPE *callbacks,
63                               OMX_PTR appData,
64                               OMX_COMPONENTTYPE **component)
65    : SoftVideoEncoderOMXComponent(
66            name, "video_encoder.vp8", OMX_VIDEO_CodingVP8,
67            kProfileLevels, NELEM(kProfileLevels),
68            176 /* width */, 144 /* height */,
69            callbacks, appData, component),
70      mCodecContext(NULL),
71      mCodecConfiguration(NULL),
72      mCodecInterface(NULL),
73      mBitrateUpdated(false),
74      mBitrateControlMode(VPX_VBR),  // variable bitrate
75      mDCTPartitions(0),
76      mErrorResilience(OMX_FALSE),
77      mLevel(OMX_VIDEO_VP8Level_Version0),
78      mKeyFrameInterval(0),
79      mMinQuantizer(0),
80      mMaxQuantizer(0),
81      mTemporalLayers(0),
82      mTemporalPatternType(OMX_VIDEO_VPXTemporalLayerPatternNone),
83      mTemporalPatternLength(0),
84      mTemporalPatternIdx(0),
85      mLastTimestamp(0x7FFFFFFFFFFFFFFFLL),
86      mConversionBuffer(NULL),
87      mKeyFrameRequested(false) {
88    memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio));
89    mTemporalLayerBitrateRatio[0] = 100;
90
91    const size_t kMinOutputBufferSize = 1024 * 1024; // arbitrary
92
93    initPorts(
94            kNumBuffers, kNumBuffers, kMinOutputBufferSize,
95            MEDIA_MIMETYPE_VIDEO_VP8, 2 /* minCompressionRatio */);
96}
97
98
99SoftVPXEncoder::~SoftVPXEncoder() {
100    releaseEncoder();
101}
102
103status_t SoftVPXEncoder::initEncoder() {
104    vpx_codec_err_t codec_return;
105
106    mCodecContext = new vpx_codec_ctx_t;
107    mCodecConfiguration = new vpx_codec_enc_cfg_t;
108    mCodecInterface = vpx_codec_vp8_cx();
109
110    if (mCodecInterface == NULL) {
111        return UNKNOWN_ERROR;
112    }
113    ALOGD("VP8: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
114          (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
115          mMinQuantizer, mMaxQuantizer);
116    codec_return = vpx_codec_enc_config_default(mCodecInterface,
117                                                mCodecConfiguration,
118                                                0);  // Codec specific flags
119
120    if (codec_return != VPX_CODEC_OK) {
121        ALOGE("Error populating default configuration for vpx encoder.");
122        return UNKNOWN_ERROR;
123    }
124
125    mCodecConfiguration->g_w = mWidth;
126    mCodecConfiguration->g_h = mHeight;
127    mCodecConfiguration->g_threads = GetCPUCoreCount();
128    mCodecConfiguration->g_error_resilient = mErrorResilience;
129
130    switch (mLevel) {
131        case OMX_VIDEO_VP8Level_Version0:
132            mCodecConfiguration->g_profile = 0;
133            break;
134
135        case OMX_VIDEO_VP8Level_Version1:
136            mCodecConfiguration->g_profile = 1;
137            break;
138
139        case OMX_VIDEO_VP8Level_Version2:
140            mCodecConfiguration->g_profile = 2;
141            break;
142
143        case OMX_VIDEO_VP8Level_Version3:
144            mCodecConfiguration->g_profile = 3;
145            break;
146
147        default:
148            mCodecConfiguration->g_profile = 0;
149    }
150
151    // OMX timebase unit is microsecond
152    // g_timebase is in seconds (i.e. 1/1000000 seconds)
153    mCodecConfiguration->g_timebase.num = 1;
154    mCodecConfiguration->g_timebase.den = 1000000;
155    // rc_target_bitrate is in kbps, mBitrate in bps
156    mCodecConfiguration->rc_target_bitrate = (mBitrate + 500) / 1000;
157    mCodecConfiguration->rc_end_usage = mBitrateControlMode;
158    // Disable frame drop - not allowed in MediaCodec now.
159    mCodecConfiguration->rc_dropframe_thresh = 0;
160    if (mBitrateControlMode == VPX_CBR) {
161        // Disable spatial resizing.
162        mCodecConfiguration->rc_resize_allowed = 0;
163        // Single-pass mode.
164        mCodecConfiguration->g_pass = VPX_RC_ONE_PASS;
165        // Maximum amount of bits that can be subtracted from the target
166        // bitrate - expressed as percentage of the target bitrate.
167        mCodecConfiguration->rc_undershoot_pct = 100;
168        // Maximum amount of bits that can be added to the target
169        // bitrate - expressed as percentage of the target bitrate.
170        mCodecConfiguration->rc_overshoot_pct = 15;
171        // Initial value of the buffer level in ms.
172        mCodecConfiguration->rc_buf_initial_sz = 500;
173        // Amount of data that the encoder should try to maintain in ms.
174        mCodecConfiguration->rc_buf_optimal_sz = 600;
175        // The amount of data that may be buffered by the decoding
176        // application in ms.
177        mCodecConfiguration->rc_buf_sz = 1000;
178        // Enable error resilience - needed for packet loss.
179        mCodecConfiguration->g_error_resilient = 1;
180        // Disable lagged encoding.
181        mCodecConfiguration->g_lag_in_frames = 0;
182        // Maximum key frame interval - for CBR boost to 3000
183        mCodecConfiguration->kf_max_dist = 3000;
184        // Encoder determines optimal key frame placement automatically.
185        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
186    }
187
188    // Frames temporal pattern - for now WebRTC like pattern is only supported.
189    switch (mTemporalLayers) {
190        case 0:
191        {
192            mTemporalPatternLength = 0;
193            break;
194        }
195        case 1:
196        {
197            mCodecConfiguration->ts_number_layers = 1;
198            mCodecConfiguration->ts_rate_decimator[0] = 1;
199            mCodecConfiguration->ts_periodicity = 1;
200            mCodecConfiguration->ts_layer_id[0] = 0;
201            mTemporalPattern[0] = kTemporalUpdateLastRefAll;
202            mTemporalPatternLength = 1;
203            break;
204        }
205        case 2:
206        {
207            mCodecConfiguration->ts_number_layers = 2;
208            mCodecConfiguration->ts_rate_decimator[0] = 2;
209            mCodecConfiguration->ts_rate_decimator[1] = 1;
210            mCodecConfiguration->ts_periodicity = 2;
211            mCodecConfiguration->ts_layer_id[0] = 0;
212            mCodecConfiguration->ts_layer_id[1] = 1;
213            mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
214            mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
215            mTemporalPattern[2] = kTemporalUpdateLastRefAltRef;
216            mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef;
217            mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
218            mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef;
219            mTemporalPattern[6] = kTemporalUpdateLastRefAltRef;
220            mTemporalPattern[7] = kTemporalUpdateNone;
221            mTemporalPatternLength = 8;
222            break;
223        }
224        case 3:
225        {
226            mCodecConfiguration->ts_number_layers = 3;
227            mCodecConfiguration->ts_rate_decimator[0] = 4;
228            mCodecConfiguration->ts_rate_decimator[1] = 2;
229            mCodecConfiguration->ts_rate_decimator[2] = 1;
230            mCodecConfiguration->ts_periodicity = 4;
231            mCodecConfiguration->ts_layer_id[0] = 0;
232            mCodecConfiguration->ts_layer_id[1] = 2;
233            mCodecConfiguration->ts_layer_id[2] = 1;
234            mCodecConfiguration->ts_layer_id[3] = 2;
235            mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
236            mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef;
237            mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
238            mTemporalPattern[3] = kTemporalUpdateNone;
239            mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
240            mTemporalPattern[5] = kTemporalUpdateNone;
241            mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef;
242            mTemporalPattern[7] = kTemporalUpdateNone;
243            mTemporalPatternLength = 8;
244            break;
245        }
246        default:
247        {
248            ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
249            return UNKNOWN_ERROR;
250        }
251    }
252
253    // Set bitrate values for each layer
254    for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) {
255        mCodecConfiguration->ts_target_bitrate[i] =
256            mCodecConfiguration->rc_target_bitrate *
257            mTemporalLayerBitrateRatio[i] / 100;
258    }
259    if (mKeyFrameInterval > 0) {
260        mCodecConfiguration->kf_max_dist = mKeyFrameInterval;
261        mCodecConfiguration->kf_min_dist = mKeyFrameInterval;
262        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
263    }
264    if (mMinQuantizer > 0) {
265        mCodecConfiguration->rc_min_quantizer = mMinQuantizer;
266    }
267    if (mMaxQuantizer > 0) {
268        mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
269    }
270
271    codec_return = vpx_codec_enc_init(mCodecContext,
272                                      mCodecInterface,
273                                      mCodecConfiguration,
274                                      0);  // flags
275
276    if (codec_return != VPX_CODEC_OK) {
277        ALOGE("Error initializing vpx encoder");
278        return UNKNOWN_ERROR;
279    }
280
281    codec_return = vpx_codec_control(mCodecContext,
282                                     VP8E_SET_TOKEN_PARTITIONS,
283                                     mDCTPartitions);
284    if (codec_return != VPX_CODEC_OK) {
285        ALOGE("Error setting dct partitions for vpx encoder.");
286        return UNKNOWN_ERROR;
287    }
288
289    // Extra CBR settings
290    if (mBitrateControlMode == VPX_CBR) {
291        codec_return = vpx_codec_control(mCodecContext,
292                                         VP8E_SET_STATIC_THRESHOLD,
293                                         1);
294        if (codec_return == VPX_CODEC_OK) {
295            uint32_t rc_max_intra_target =
296                mCodecConfiguration->rc_buf_optimal_sz * (mFramerate >> 17) / 10;
297            // Don't go below 3 times per frame bandwidth.
298            if (rc_max_intra_target < 300) {
299                rc_max_intra_target = 300;
300            }
301            codec_return = vpx_codec_control(mCodecContext,
302                                             VP8E_SET_MAX_INTRA_BITRATE_PCT,
303                                             rc_max_intra_target);
304        }
305        if (codec_return == VPX_CODEC_OK) {
306            codec_return = vpx_codec_control(mCodecContext,
307                                             VP8E_SET_CPUUSED,
308                                             -8);
309        }
310        if (codec_return != VPX_CODEC_OK) {
311            ALOGE("Error setting cbr parameters for vpx encoder.");
312            return UNKNOWN_ERROR;
313        }
314    }
315
316    if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) {
317        free(mConversionBuffer);
318        mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
319        if (mConversionBuffer == NULL) {
320            ALOGE("Allocating conversion buffer failed.");
321            return UNKNOWN_ERROR;
322        }
323    }
324    return OK;
325}
326
327
328status_t SoftVPXEncoder::releaseEncoder() {
329    if (mCodecContext != NULL) {
330        vpx_codec_destroy(mCodecContext);
331        delete mCodecContext;
332        mCodecContext = NULL;
333    }
334
335    if (mCodecConfiguration != NULL) {
336        delete mCodecConfiguration;
337        mCodecConfiguration = NULL;
338    }
339
340    if (mConversionBuffer != NULL) {
341        free(mConversionBuffer);
342        mConversionBuffer = NULL;
343    }
344
345    // this one is not allocated by us
346    mCodecInterface = NULL;
347
348    return OK;
349}
350
351
352OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index,
353                                                   OMX_PTR param) {
354    // can include extension index OMX_INDEXEXTTYPE
355    const int32_t indexFull = index;
356
357    switch (indexFull) {
358        case OMX_IndexParamVideoBitrate: {
359            OMX_VIDEO_PARAM_BITRATETYPE *bitrate =
360                (OMX_VIDEO_PARAM_BITRATETYPE *)param;
361
362                if (bitrate->nPortIndex != kOutputPortIndex) {
363                    return OMX_ErrorUnsupportedIndex;
364                }
365
366                bitrate->nTargetBitrate = mBitrate;
367
368                if (mBitrateControlMode == VPX_VBR) {
369                    bitrate->eControlRate = OMX_Video_ControlRateVariable;
370                } else if (mBitrateControlMode == VPX_CBR) {
371                    bitrate->eControlRate = OMX_Video_ControlRateConstant;
372                } else {
373                    return OMX_ErrorUnsupportedSetting;
374                }
375                return OMX_ErrorNone;
376        }
377
378        // VP8 specific parameters that use extension headers
379        case OMX_IndexParamVideoVp8: {
380            OMX_VIDEO_PARAM_VP8TYPE *vp8Params =
381                (OMX_VIDEO_PARAM_VP8TYPE *)param;
382
383                if (vp8Params->nPortIndex != kOutputPortIndex) {
384                    return OMX_ErrorUnsupportedIndex;
385                }
386
387                vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain;
388                vp8Params->eLevel = mLevel;
389                vp8Params->nDCTPartitions = mDCTPartitions;
390                vp8Params->bErrorResilientMode = mErrorResilience;
391                return OMX_ErrorNone;
392        }
393
394        case OMX_IndexParamVideoAndroidVp8Encoder: {
395            OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vp8AndroidParams =
396                (OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param;
397
398                if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
399                    return OMX_ErrorUnsupportedIndex;
400                }
401
402                vp8AndroidParams->nKeyFrameInterval = mKeyFrameInterval;
403                vp8AndroidParams->eTemporalPattern = mTemporalPatternType;
404                vp8AndroidParams->nTemporalLayerCount = mTemporalLayers;
405                vp8AndroidParams->nMinQuantizer = mMinQuantizer;
406                vp8AndroidParams->nMaxQuantizer = mMaxQuantizer;
407                memcpy(vp8AndroidParams->nTemporalLayerBitrateRatio,
408                       mTemporalLayerBitrateRatio, sizeof(mTemporalLayerBitrateRatio));
409                return OMX_ErrorNone;
410        }
411
412        default:
413            return SoftVideoEncoderOMXComponent::internalGetParameter(index, param);
414    }
415}
416
417
418OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index,
419                                                   const OMX_PTR param) {
420    // can include extension index OMX_INDEXEXTTYPE
421    const int32_t indexFull = index;
422
423    switch (indexFull) {
424        case OMX_IndexParamVideoBitrate:
425            return internalSetBitrateParams(
426                (const OMX_VIDEO_PARAM_BITRATETYPE *)param);
427
428        case OMX_IndexParamVideoVp8:
429            return internalSetVp8Params(
430                (const OMX_VIDEO_PARAM_VP8TYPE *)param);
431
432        case OMX_IndexParamVideoAndroidVp8Encoder:
433            return internalSetAndroidVp8Params(
434                (const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param);
435
436        default:
437            return SoftVideoEncoderOMXComponent::internalSetParameter(index, param);
438    }
439}
440
441OMX_ERRORTYPE SoftVPXEncoder::setConfig(
442        OMX_INDEXTYPE index, const OMX_PTR _params) {
443    switch (index) {
444        case OMX_IndexConfigVideoIntraVOPRefresh:
445        {
446            OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
447                (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params;
448
449            if (params->nPortIndex != kOutputPortIndex) {
450                return OMX_ErrorBadPortIndex;
451            }
452
453            mKeyFrameRequested = params->IntraRefreshVOP;
454            return OMX_ErrorNone;
455        }
456
457        case OMX_IndexConfigVideoBitrate:
458        {
459            OMX_VIDEO_CONFIG_BITRATETYPE *params =
460                (OMX_VIDEO_CONFIG_BITRATETYPE *)_params;
461
462            if (params->nPortIndex != kOutputPortIndex) {
463                return OMX_ErrorBadPortIndex;
464            }
465
466            if (mBitrate != params->nEncodeBitrate) {
467                mBitrate = params->nEncodeBitrate;
468                mBitrateUpdated = true;
469            }
470            return OMX_ErrorNone;
471        }
472
473        default:
474            return SimpleSoftOMXComponent::setConfig(index, _params);
475    }
476}
477
478OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params(
479        const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
480    if (vp8Params->nPortIndex != kOutputPortIndex) {
481        return OMX_ErrorUnsupportedIndex;
482    }
483
484    if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) {
485        return OMX_ErrorBadParameter;
486    }
487
488    if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 ||
489        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 ||
490        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 ||
491        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) {
492        mLevel = vp8Params->eLevel;
493    } else {
494        return OMX_ErrorBadParameter;
495    }
496
497    if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) {
498        mDCTPartitions = vp8Params->nDCTPartitions;
499    } else {
500        return OMX_ErrorBadParameter;
501    }
502
503    mErrorResilience = vp8Params->bErrorResilientMode;
504    return OMX_ErrorNone;
505}
506
507OMX_ERRORTYPE SoftVPXEncoder::internalSetAndroidVp8Params(
508        const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams) {
509    if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
510        return OMX_ErrorUnsupportedIndex;
511    }
512    if (vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternNone &&
513        vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
514        return OMX_ErrorBadParameter;
515    }
516    if (vp8AndroidParams->nTemporalLayerCount > OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) {
517        return OMX_ErrorBadParameter;
518    }
519    if (vp8AndroidParams->nMinQuantizer > vp8AndroidParams->nMaxQuantizer) {
520        return OMX_ErrorBadParameter;
521    }
522
523    mTemporalPatternType = vp8AndroidParams->eTemporalPattern;
524    if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
525        mTemporalLayers = vp8AndroidParams->nTemporalLayerCount;
526    } else if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternNone) {
527        mTemporalLayers = 0;
528    }
529    // Check the bitrate distribution between layers is in increasing order
530    if (mTemporalLayers > 1) {
531        for (size_t i = 0; i < mTemporalLayers - 1; i++) {
532            if (vp8AndroidParams->nTemporalLayerBitrateRatio[i + 1] <=
533                    vp8AndroidParams->nTemporalLayerBitrateRatio[i]) {
534                ALOGE("Wrong bitrate ratio - should be in increasing order.");
535                return OMX_ErrorBadParameter;
536            }
537        }
538    }
539    mKeyFrameInterval = vp8AndroidParams->nKeyFrameInterval;
540    mMinQuantizer = vp8AndroidParams->nMinQuantizer;
541    mMaxQuantizer = vp8AndroidParams->nMaxQuantizer;
542    memcpy(mTemporalLayerBitrateRatio, vp8AndroidParams->nTemporalLayerBitrateRatio,
543            sizeof(mTemporalLayerBitrateRatio));
544    ALOGD("VP8: internalSetAndroidVp8Params. BRMode: %u. TS: %zu. KF: %u."
545          " QP: %u - %u BR0: %u. BR1: %u. BR2: %u",
546          (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
547          mMinQuantizer, mMaxQuantizer, mTemporalLayerBitrateRatio[0],
548          mTemporalLayerBitrateRatio[1], mTemporalLayerBitrateRatio[2]);
549    return OMX_ErrorNone;
550}
551
552OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams(
553        const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) {
554    if (bitrate->nPortIndex != kOutputPortIndex) {
555        return OMX_ErrorUnsupportedIndex;
556    }
557
558    mBitrate = bitrate->nTargetBitrate;
559
560    if (bitrate->eControlRate == OMX_Video_ControlRateVariable) {
561        mBitrateControlMode = VPX_VBR;
562    } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) {
563        mBitrateControlMode = VPX_CBR;
564    } else {
565        return OMX_ErrorUnsupportedSetting;
566    }
567
568    return OMX_ErrorNone;
569}
570
571vpx_enc_frame_flags_t SoftVPXEncoder::getEncodeFlags() {
572    vpx_enc_frame_flags_t flags = 0;
573    int patternIdx = mTemporalPatternIdx % mTemporalPatternLength;
574    mTemporalPatternIdx++;
575    switch (mTemporalPattern[patternIdx]) {
576        case kTemporalUpdateLast:
577            flags |= VP8_EFLAG_NO_UPD_GF;
578            flags |= VP8_EFLAG_NO_UPD_ARF;
579            flags |= VP8_EFLAG_NO_REF_GF;
580            flags |= VP8_EFLAG_NO_REF_ARF;
581            break;
582        case kTemporalUpdateGoldenWithoutDependency:
583            flags |= VP8_EFLAG_NO_REF_GF;
584            // Deliberately no break here.
585        case kTemporalUpdateGolden:
586            flags |= VP8_EFLAG_NO_REF_ARF;
587            flags |= VP8_EFLAG_NO_UPD_ARF;
588            flags |= VP8_EFLAG_NO_UPD_LAST;
589            break;
590        case kTemporalUpdateAltrefWithoutDependency:
591            flags |= VP8_EFLAG_NO_REF_ARF;
592            flags |= VP8_EFLAG_NO_REF_GF;
593            // Deliberately no break here.
594        case kTemporalUpdateAltref:
595            flags |= VP8_EFLAG_NO_UPD_GF;
596            flags |= VP8_EFLAG_NO_UPD_LAST;
597            break;
598        case kTemporalUpdateNoneNoRefAltref:
599            flags |= VP8_EFLAG_NO_REF_ARF;
600            // Deliberately no break here.
601        case kTemporalUpdateNone:
602            flags |= VP8_EFLAG_NO_UPD_GF;
603            flags |= VP8_EFLAG_NO_UPD_ARF;
604            flags |= VP8_EFLAG_NO_UPD_LAST;
605            flags |= VP8_EFLAG_NO_UPD_ENTROPY;
606            break;
607        case kTemporalUpdateNoneNoRefGoldenRefAltRef:
608            flags |= VP8_EFLAG_NO_REF_GF;
609            flags |= VP8_EFLAG_NO_UPD_GF;
610            flags |= VP8_EFLAG_NO_UPD_ARF;
611            flags |= VP8_EFLAG_NO_UPD_LAST;
612            flags |= VP8_EFLAG_NO_UPD_ENTROPY;
613            break;
614        case kTemporalUpdateGoldenWithoutDependencyRefAltRef:
615            flags |= VP8_EFLAG_NO_REF_GF;
616            flags |= VP8_EFLAG_NO_UPD_ARF;
617            flags |= VP8_EFLAG_NO_UPD_LAST;
618            break;
619        case kTemporalUpdateLastRefAltRef:
620            flags |= VP8_EFLAG_NO_UPD_GF;
621            flags |= VP8_EFLAG_NO_UPD_ARF;
622            flags |= VP8_EFLAG_NO_REF_GF;
623            break;
624        case kTemporalUpdateGoldenRefAltRef:
625            flags |= VP8_EFLAG_NO_UPD_ARF;
626            flags |= VP8_EFLAG_NO_UPD_LAST;
627            break;
628        case kTemporalUpdateLastAndGoldenRefAltRef:
629            flags |= VP8_EFLAG_NO_UPD_ARF;
630            flags |= VP8_EFLAG_NO_REF_GF;
631            break;
632        case kTemporalUpdateLastRefAll:
633            flags |= VP8_EFLAG_NO_UPD_ARF;
634            flags |= VP8_EFLAG_NO_UPD_GF;
635            break;
636    }
637    return flags;
638}
639
640void SoftVPXEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
641    // Initialize encoder if not already
642    if (mCodecContext == NULL) {
643        if (OK != initEncoder()) {
644            ALOGE("Failed to initialize encoder");
645            notify(OMX_EventError,
646                   OMX_ErrorUndefined,
647                   0,  // Extra notification data
648                   NULL);  // Notification data pointer
649            return;
650        }
651    }
652
653    vpx_codec_err_t codec_return;
654    List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex);
655    List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex);
656
657    while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) {
658        BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin();
659        OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader;
660
661        BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin();
662        OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader;
663
664        if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
665            inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
666            inputBufferInfo->mOwnedByUs = false;
667            notifyEmptyBufferDone(inputBufferHeader);
668
669            outputBufferHeader->nFilledLen = 0;
670            outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS;
671
672            outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
673            outputBufferInfo->mOwnedByUs = false;
674            notifyFillBufferDone(outputBufferHeader);
675            return;
676        }
677
678        const uint8_t *source =
679            inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
680
681        if (mInputDataIsMeta) {
682            source = extractGraphicBuffer(
683                    mConversionBuffer, mWidth * mHeight * 3 / 2,
684                    source, inputBufferHeader->nFilledLen,
685                    mWidth, mHeight);
686            if (source == NULL) {
687                ALOGE("Unable to extract gralloc buffer in metadata mode");
688                notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
689                return;
690            }
691        } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
692            ConvertYUV420SemiPlanarToYUV420Planar(
693                    source, mConversionBuffer, mWidth, mHeight);
694
695            source = mConversionBuffer;
696        }
697        vpx_image_t raw_frame;
698        vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
699                     kInputBufferAlignment, (uint8_t *)source);
700
701        vpx_enc_frame_flags_t flags = 0;
702        if (mTemporalPatternLength > 0) {
703            flags = getEncodeFlags();
704        }
705        if (mKeyFrameRequested) {
706            flags |= VPX_EFLAG_FORCE_KF;
707            mKeyFrameRequested = false;
708        }
709
710        if (mBitrateUpdated) {
711            mCodecConfiguration->rc_target_bitrate = mBitrate/1000;
712            vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext,
713                                                           mCodecConfiguration);
714            if (res != VPX_CODEC_OK) {
715                ALOGE("vp8 encoder failed to update bitrate: %s",
716                      vpx_codec_err_to_string(res));
717                notify(OMX_EventError,
718                       OMX_ErrorUndefined,
719                       0, // Extra notification data
720                       NULL); // Notification data pointer
721            }
722            mBitrateUpdated = false;
723        }
724
725        uint32_t frameDuration;
726        if (inputBufferHeader->nTimeStamp > mLastTimestamp) {
727            frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp);
728        } else {
729            frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate);
730        }
731        mLastTimestamp = inputBufferHeader->nTimeStamp;
732        codec_return = vpx_codec_encode(
733                mCodecContext,
734                &raw_frame,
735                inputBufferHeader->nTimeStamp,  // in timebase units
736                frameDuration,  // frame duration in timebase units
737                flags,  // frame flags
738                VPX_DL_REALTIME);  // encoding deadline
739        if (codec_return != VPX_CODEC_OK) {
740            ALOGE("vpx encoder failed to encode frame");
741            notify(OMX_EventError,
742                   OMX_ErrorUndefined,
743                   0,  // Extra notification data
744                   NULL);  // Notification data pointer
745            return;
746        }
747
748        vpx_codec_iter_t encoded_packet_iterator = NULL;
749        const vpx_codec_cx_pkt_t* encoded_packet;
750
751        while ((encoded_packet = vpx_codec_get_cx_data(
752                        mCodecContext, &encoded_packet_iterator))) {
753            if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
754                outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts;
755                outputBufferHeader->nFlags = 0;
756                if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY)
757                  outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
758                outputBufferHeader->nOffset = 0;
759                outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz;
760                memcpy(outputBufferHeader->pBuffer,
761                       encoded_packet->data.frame.buf,
762                       encoded_packet->data.frame.sz);
763                outputBufferInfo->mOwnedByUs = false;
764                outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
765                notifyFillBufferDone(outputBufferHeader);
766            }
767        }
768
769        inputBufferInfo->mOwnedByUs = false;
770        inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
771        notifyEmptyBufferDone(inputBufferHeader);
772    }
773}
774
775}  // namespace android
776
777
778android::SoftOMXComponent *createSoftOMXComponent(
779        const char *name, const OMX_CALLBACKTYPE *callbacks,
780        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
781    return new android::SoftVPXEncoder(name, callbacks, appData, component);
782}
783