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