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