SoftVP8Encoder.cpp revision 4f61e52d32f05db3cb04a0e29f9a2507ceffaf99
1/*
2 * Copyright (C) 2016 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 "SoftVP8Encoder"
19#include "SoftVP8Encoder.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
35static const CodecProfileLevel kVp8ProfileLevels[] = {
36    { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version0 },
37    { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version1 },
38    { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version2 },
39    { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version3 },
40};
41
42SoftVP8Encoder::SoftVP8Encoder(const char *name,
43                               const OMX_CALLBACKTYPE *callbacks,
44                               OMX_PTR appData,
45                               OMX_COMPONENTTYPE **component)
46    : SoftVPXEncoder(
47            name, callbacks, appData, component, "video_encoder.vp8",
48            OMX_VIDEO_CodingVP8, MEDIA_MIMETYPE_VIDEO_VP8, 2,
49            kVp8ProfileLevels, NELEM(kVp8ProfileLevels)),
50      mDCTPartitions(0),
51      mLevel(OMX_VIDEO_VP8Level_Version0) {
52}
53
54void SoftVP8Encoder::setCodecSpecificInterface() {
55    mCodecInterface = vpx_codec_vp8_cx();
56}
57
58bool SoftVP8Encoder::setCodecSpecificConfiguration() {
59    switch (mLevel) {
60        case OMX_VIDEO_VP8Level_Version0:
61            mCodecConfiguration->g_profile = 0;
62            break;
63
64        case OMX_VIDEO_VP8Level_Version1:
65            mCodecConfiguration->g_profile = 1;
66            break;
67
68        case OMX_VIDEO_VP8Level_Version2:
69            mCodecConfiguration->g_profile = 2;
70            break;
71
72        case OMX_VIDEO_VP8Level_Version3:
73            mCodecConfiguration->g_profile = 3;
74            break;
75
76        default:
77            mCodecConfiguration->g_profile = 0;
78    }
79    return true;
80}
81
82vpx_codec_err_t SoftVP8Encoder::setCodecSpecificControls() {
83    vpx_codec_err_t codec_return = vpx_codec_control(mCodecContext,
84                                                     VP8E_SET_TOKEN_PARTITIONS,
85                                                     mDCTPartitions);
86    if (codec_return != VPX_CODEC_OK) {
87        ALOGE("Error setting dct partitions for vpx encoder.");
88    }
89    return codec_return;
90}
91
92OMX_ERRORTYPE SoftVP8Encoder::internalGetParameter(OMX_INDEXTYPE index,
93                                                   OMX_PTR param) {
94    // can include extension index OMX_INDEXEXTTYPE
95    const int32_t indexFull = index;
96
97    switch (indexFull) {
98        case OMX_IndexParamVideoVp8:
99            return internalGetVp8Params(
100                (OMX_VIDEO_PARAM_VP8TYPE *)param);
101
102        case OMX_IndexParamVideoAndroidVp8Encoder:
103            return internalGetAndroidVp8Params(
104                (OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param);
105
106        default:
107            return SoftVPXEncoder::internalGetParameter(index, param);
108    }
109}
110
111OMX_ERRORTYPE SoftVP8Encoder::internalSetParameter(OMX_INDEXTYPE index,
112                                                   const OMX_PTR param) {
113    // can include extension index OMX_INDEXEXTTYPE
114    const int32_t indexFull = index;
115
116    switch (indexFull) {
117        case OMX_IndexParamVideoVp8:
118            return internalSetVp8Params(
119                (const OMX_VIDEO_PARAM_VP8TYPE *)param);
120
121        case OMX_IndexParamVideoAndroidVp8Encoder:
122            return internalSetAndroidVp8Params(
123                (const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param);
124
125        default:
126            return SoftVPXEncoder::internalSetParameter(index, param);
127    }
128}
129
130OMX_ERRORTYPE SoftVP8Encoder::internalGetVp8Params(
131        OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
132    if (vp8Params->nPortIndex != kOutputPortIndex) {
133        return OMX_ErrorUnsupportedIndex;
134    }
135
136    vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain;
137    vp8Params->eLevel = mLevel;
138    vp8Params->bErrorResilientMode = mErrorResilience;
139    vp8Params->nDCTPartitions = mDCTPartitions;
140    return OMX_ErrorNone;
141}
142
143OMX_ERRORTYPE SoftVP8Encoder::internalSetVp8Params(
144        const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
145    if (vp8Params->nPortIndex != kOutputPortIndex) {
146        return OMX_ErrorUnsupportedIndex;
147    }
148
149    if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) {
150        return OMX_ErrorBadParameter;
151    }
152
153    if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 ||
154        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 ||
155        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 ||
156        vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) {
157        mLevel = vp8Params->eLevel;
158    } else {
159        return OMX_ErrorBadParameter;
160    }
161
162    mErrorResilience = vp8Params->bErrorResilientMode;
163    if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) {
164        mDCTPartitions = vp8Params->nDCTPartitions;
165    } else {
166        return OMX_ErrorBadParameter;
167    }
168    return OMX_ErrorNone;
169}
170
171OMX_ERRORTYPE SoftVP8Encoder::internalGetAndroidVp8Params(
172        OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams) {
173    if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
174        return OMX_ErrorUnsupportedIndex;
175    }
176
177    vp8AndroidParams->nKeyFrameInterval = mKeyFrameInterval;
178    vp8AndroidParams->eTemporalPattern = mTemporalPatternType;
179    vp8AndroidParams->nTemporalLayerCount = mTemporalLayers;
180    vp8AndroidParams->nMinQuantizer = mMinQuantizer;
181    vp8AndroidParams->nMaxQuantizer = mMaxQuantizer;
182    memcpy(vp8AndroidParams->nTemporalLayerBitrateRatio,
183           mTemporalLayerBitrateRatio, sizeof(mTemporalLayerBitrateRatio));
184    return OMX_ErrorNone;
185}
186
187OMX_ERRORTYPE SoftVP8Encoder::internalSetAndroidVp8Params(
188        const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams) {
189    if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
190        return OMX_ErrorUnsupportedIndex;
191    }
192    if (vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternNone &&
193        vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
194        return OMX_ErrorBadParameter;
195    }
196    if (vp8AndroidParams->nTemporalLayerCount > OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) {
197        return OMX_ErrorBadParameter;
198    }
199    if (vp8AndroidParams->nMinQuantizer > vp8AndroidParams->nMaxQuantizer) {
200        return OMX_ErrorBadParameter;
201    }
202
203    mTemporalPatternType = vp8AndroidParams->eTemporalPattern;
204    if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
205        mTemporalLayers = vp8AndroidParams->nTemporalLayerCount;
206    } else if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternNone) {
207        mTemporalLayers = 0;
208    }
209    // Check the bitrate distribution between layers is in increasing order
210    if (mTemporalLayers > 1) {
211        for (size_t i = 0; i < mTemporalLayers - 1; i++) {
212            if (vp8AndroidParams->nTemporalLayerBitrateRatio[i + 1] <=
213                    vp8AndroidParams->nTemporalLayerBitrateRatio[i]) {
214                ALOGE("Wrong bitrate ratio - should be in increasing order.");
215                return OMX_ErrorBadParameter;
216            }
217        }
218    }
219    mKeyFrameInterval = vp8AndroidParams->nKeyFrameInterval;
220    mMinQuantizer = vp8AndroidParams->nMinQuantizer;
221    mMaxQuantizer = vp8AndroidParams->nMaxQuantizer;
222    memcpy(mTemporalLayerBitrateRatio, vp8AndroidParams->nTemporalLayerBitrateRatio,
223            sizeof(mTemporalLayerBitrateRatio));
224    ALOGD("VPx: internalSetAndroidVp8Params. BRMode: %u. TS: %zu. KF: %u."
225          " QP: %u - %u BR0: %u. BR1: %u. BR2: %u",
226          (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
227          mMinQuantizer, mMaxQuantizer, mTemporalLayerBitrateRatio[0],
228          mTemporalLayerBitrateRatio[1], mTemporalLayerBitrateRatio[2]);
229    return OMX_ErrorNone;
230}
231
232}  // namespace android
233