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