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