SoftVPXEncoder.cpp revision e35ff4de22fec058d57f694e86b906ca8b8007dd
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 (bitrate->nPortIndex != kOutputPortIndex) { 377 return OMX_ErrorUnsupportedIndex; 378 } 379 380 bitrate->nTargetBitrate = mBitrate; 381 382 if (mBitrateControlMode == VPX_VBR) { 383 bitrate->eControlRate = OMX_Video_ControlRateVariable; 384 } else if (mBitrateControlMode == VPX_CBR) { 385 bitrate->eControlRate = OMX_Video_ControlRateConstant; 386 } else { 387 return OMX_ErrorUnsupportedSetting; 388 } 389 return OMX_ErrorNone; 390 } 391 392 // VP8 specific parameters that use extension headers 393 case OMX_IndexParamVideoVp8: { 394 OMX_VIDEO_PARAM_VP8TYPE *vp8Params = 395 (OMX_VIDEO_PARAM_VP8TYPE *)param; 396 397 if (vp8Params->nPortIndex != kOutputPortIndex) { 398 return OMX_ErrorUnsupportedIndex; 399 } 400 401 vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain; 402 vp8Params->eLevel = mLevel; 403 vp8Params->nDCTPartitions = mDCTPartitions; 404 vp8Params->bErrorResilientMode = mErrorResilience; 405 return OMX_ErrorNone; 406 } 407 408 case OMX_IndexParamVideoAndroidVp8Encoder: { 409 OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vp8AndroidParams = 410 (OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param; 411 412 if (vp8AndroidParams->nPortIndex != kOutputPortIndex) { 413 return OMX_ErrorUnsupportedIndex; 414 } 415 416 vp8AndroidParams->nKeyFrameInterval = mKeyFrameInterval; 417 vp8AndroidParams->eTemporalPattern = mTemporalPatternType; 418 vp8AndroidParams->nTemporalLayerCount = mTemporalLayers; 419 vp8AndroidParams->nMinQuantizer = mMinQuantizer; 420 vp8AndroidParams->nMaxQuantizer = mMaxQuantizer; 421 memcpy(vp8AndroidParams->nTemporalLayerBitrateRatio, 422 mTemporalLayerBitrateRatio, sizeof(mTemporalLayerBitrateRatio)); 423 return OMX_ErrorNone; 424 } 425 426 default: 427 return SoftVideoEncoderOMXComponent::internalGetParameter(index, param); 428 } 429} 430 431 432OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index, 433 const OMX_PTR param) { 434 // can include extension index OMX_INDEXEXTTYPE 435 const int32_t indexFull = index; 436 437 switch (indexFull) { 438 case OMX_IndexParamVideoBitrate: 439 return internalSetBitrateParams( 440 (const OMX_VIDEO_PARAM_BITRATETYPE *)param); 441 442 case OMX_IndexParamVideoVp8: 443 return internalSetVp8Params( 444 (const OMX_VIDEO_PARAM_VP8TYPE *)param); 445 446 case OMX_IndexParamVideoAndroidVp8Encoder: 447 return internalSetAndroidVp8Params( 448 (const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param); 449 450 default: 451 return SoftVideoEncoderOMXComponent::internalSetParameter(index, param); 452 } 453} 454 455OMX_ERRORTYPE SoftVPXEncoder::setConfig( 456 OMX_INDEXTYPE index, const OMX_PTR _params) { 457 switch (index) { 458 case OMX_IndexConfigVideoIntraVOPRefresh: 459 { 460 OMX_CONFIG_INTRAREFRESHVOPTYPE *params = 461 (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params; 462 463 if (params->nPortIndex != kOutputPortIndex) { 464 return OMX_ErrorBadPortIndex; 465 } 466 467 mKeyFrameRequested = params->IntraRefreshVOP; 468 return OMX_ErrorNone; 469 } 470 471 case OMX_IndexConfigVideoBitrate: 472 { 473 OMX_VIDEO_CONFIG_BITRATETYPE *params = 474 (OMX_VIDEO_CONFIG_BITRATETYPE *)_params; 475 476 if (params->nPortIndex != kOutputPortIndex) { 477 return OMX_ErrorBadPortIndex; 478 } 479 480 if (mBitrate != params->nEncodeBitrate) { 481 mBitrate = params->nEncodeBitrate; 482 mBitrateUpdated = true; 483 } 484 return OMX_ErrorNone; 485 } 486 487 default: 488 return SimpleSoftOMXComponent::setConfig(index, _params); 489 } 490} 491 492OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params( 493 const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) { 494 if (vp8Params->nPortIndex != kOutputPortIndex) { 495 return OMX_ErrorUnsupportedIndex; 496 } 497 498 if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) { 499 return OMX_ErrorBadParameter; 500 } 501 502 if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 || 503 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 || 504 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 || 505 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) { 506 mLevel = vp8Params->eLevel; 507 } else { 508 return OMX_ErrorBadParameter; 509 } 510 511 if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) { 512 mDCTPartitions = vp8Params->nDCTPartitions; 513 } else { 514 return OMX_ErrorBadParameter; 515 } 516 517 mErrorResilience = vp8Params->bErrorResilientMode; 518 return OMX_ErrorNone; 519} 520 521OMX_ERRORTYPE SoftVPXEncoder::internalSetAndroidVp8Params( 522 const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams) { 523 if (vp8AndroidParams->nPortIndex != kOutputPortIndex) { 524 return OMX_ErrorUnsupportedIndex; 525 } 526 if (vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternNone && 527 vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternWebRTC) { 528 return OMX_ErrorBadParameter; 529 } 530 if (vp8AndroidParams->nTemporalLayerCount > OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) { 531 return OMX_ErrorBadParameter; 532 } 533 if (vp8AndroidParams->nMinQuantizer > vp8AndroidParams->nMaxQuantizer) { 534 return OMX_ErrorBadParameter; 535 } 536 537 mTemporalPatternType = vp8AndroidParams->eTemporalPattern; 538 if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) { 539 mTemporalLayers = vp8AndroidParams->nTemporalLayerCount; 540 } else if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternNone) { 541 mTemporalLayers = 0; 542 } 543 // Check the bitrate distribution between layers is in increasing order 544 if (mTemporalLayers > 1) { 545 for (size_t i = 0; i < mTemporalLayers - 1; i++) { 546 if (vp8AndroidParams->nTemporalLayerBitrateRatio[i + 1] <= 547 vp8AndroidParams->nTemporalLayerBitrateRatio[i]) { 548 ALOGE("Wrong bitrate ratio - should be in increasing order."); 549 return OMX_ErrorBadParameter; 550 } 551 } 552 } 553 mKeyFrameInterval = vp8AndroidParams->nKeyFrameInterval; 554 mMinQuantizer = vp8AndroidParams->nMinQuantizer; 555 mMaxQuantizer = vp8AndroidParams->nMaxQuantizer; 556 memcpy(mTemporalLayerBitrateRatio, vp8AndroidParams->nTemporalLayerBitrateRatio, 557 sizeof(mTemporalLayerBitrateRatio)); 558 ALOGD("VP8: internalSetAndroidVp8Params. BRMode: %u. TS: %zu. KF: %u." 559 " QP: %u - %u BR0: %u. BR1: %u. BR2: %u", 560 (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval, 561 mMinQuantizer, mMaxQuantizer, mTemporalLayerBitrateRatio[0], 562 mTemporalLayerBitrateRatio[1], mTemporalLayerBitrateRatio[2]); 563 return OMX_ErrorNone; 564} 565 566OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams( 567 const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) { 568 if (bitrate->nPortIndex != kOutputPortIndex) { 569 return OMX_ErrorUnsupportedIndex; 570 } 571 572 mBitrate = bitrate->nTargetBitrate; 573 574 if (bitrate->eControlRate == OMX_Video_ControlRateVariable) { 575 mBitrateControlMode = VPX_VBR; 576 } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) { 577 mBitrateControlMode = VPX_CBR; 578 } else { 579 return OMX_ErrorUnsupportedSetting; 580 } 581 582 return OMX_ErrorNone; 583} 584 585vpx_enc_frame_flags_t SoftVPXEncoder::getEncodeFlags() { 586 vpx_enc_frame_flags_t flags = 0; 587 int patternIdx = mTemporalPatternIdx % mTemporalPatternLength; 588 mTemporalPatternIdx++; 589 switch (mTemporalPattern[patternIdx]) { 590 case kTemporalUpdateLast: 591 flags |= VP8_EFLAG_NO_UPD_GF; 592 flags |= VP8_EFLAG_NO_UPD_ARF; 593 flags |= VP8_EFLAG_NO_REF_GF; 594 flags |= VP8_EFLAG_NO_REF_ARF; 595 break; 596 case kTemporalUpdateGoldenWithoutDependency: 597 flags |= VP8_EFLAG_NO_REF_GF; 598 // Deliberately no break here. 599 case kTemporalUpdateGolden: 600 flags |= VP8_EFLAG_NO_REF_ARF; 601 flags |= VP8_EFLAG_NO_UPD_ARF; 602 flags |= VP8_EFLAG_NO_UPD_LAST; 603 break; 604 case kTemporalUpdateAltrefWithoutDependency: 605 flags |= VP8_EFLAG_NO_REF_ARF; 606 flags |= VP8_EFLAG_NO_REF_GF; 607 // Deliberately no break here. 608 case kTemporalUpdateAltref: 609 flags |= VP8_EFLAG_NO_UPD_GF; 610 flags |= VP8_EFLAG_NO_UPD_LAST; 611 break; 612 case kTemporalUpdateNoneNoRefAltref: 613 flags |= VP8_EFLAG_NO_REF_ARF; 614 // Deliberately no break here. 615 case kTemporalUpdateNone: 616 flags |= VP8_EFLAG_NO_UPD_GF; 617 flags |= VP8_EFLAG_NO_UPD_ARF; 618 flags |= VP8_EFLAG_NO_UPD_LAST; 619 flags |= VP8_EFLAG_NO_UPD_ENTROPY; 620 break; 621 case kTemporalUpdateNoneNoRefGoldenRefAltRef: 622 flags |= VP8_EFLAG_NO_REF_GF; 623 flags |= VP8_EFLAG_NO_UPD_GF; 624 flags |= VP8_EFLAG_NO_UPD_ARF; 625 flags |= VP8_EFLAG_NO_UPD_LAST; 626 flags |= VP8_EFLAG_NO_UPD_ENTROPY; 627 break; 628 case kTemporalUpdateGoldenWithoutDependencyRefAltRef: 629 flags |= VP8_EFLAG_NO_REF_GF; 630 flags |= VP8_EFLAG_NO_UPD_ARF; 631 flags |= VP8_EFLAG_NO_UPD_LAST; 632 break; 633 case kTemporalUpdateLastRefAltRef: 634 flags |= VP8_EFLAG_NO_UPD_GF; 635 flags |= VP8_EFLAG_NO_UPD_ARF; 636 flags |= VP8_EFLAG_NO_REF_GF; 637 break; 638 case kTemporalUpdateGoldenRefAltRef: 639 flags |= VP8_EFLAG_NO_UPD_ARF; 640 flags |= VP8_EFLAG_NO_UPD_LAST; 641 break; 642 case kTemporalUpdateLastAndGoldenRefAltRef: 643 flags |= VP8_EFLAG_NO_UPD_ARF; 644 flags |= VP8_EFLAG_NO_REF_GF; 645 break; 646 case kTemporalUpdateLastRefAll: 647 flags |= VP8_EFLAG_NO_UPD_ARF; 648 flags |= VP8_EFLAG_NO_UPD_GF; 649 break; 650 } 651 return flags; 652} 653 654void SoftVPXEncoder::onQueueFilled(OMX_U32 /* portIndex */) { 655 // Initialize encoder if not already 656 if (mCodecContext == NULL) { 657 if (OK != initEncoder()) { 658 ALOGE("Failed to initialize encoder"); 659 notify(OMX_EventError, 660 OMX_ErrorUndefined, 661 0, // Extra notification data 662 NULL); // Notification data pointer 663 return; 664 } 665 } 666 667 vpx_codec_err_t codec_return; 668 List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex); 669 List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex); 670 671 while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) { 672 BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin(); 673 OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader; 674 675 BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin(); 676 OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader; 677 678 if ((inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) && 679 inputBufferHeader->nFilledLen == 0) { 680 inputBufferInfoQueue.erase(inputBufferInfoQueue.begin()); 681 inputBufferInfo->mOwnedByUs = false; 682 notifyEmptyBufferDone(inputBufferHeader); 683 684 outputBufferHeader->nFilledLen = 0; 685 outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS; 686 687 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin()); 688 outputBufferInfo->mOwnedByUs = false; 689 notifyFillBufferDone(outputBufferHeader); 690 return; 691 } 692 693 const uint8_t *source = 694 inputBufferHeader->pBuffer + inputBufferHeader->nOffset; 695 696 if (mInputDataIsMeta) { 697 source = extractGraphicBuffer( 698 mConversionBuffer, mWidth * mHeight * 3 / 2, 699 source, inputBufferHeader->nFilledLen, 700 mWidth, mHeight); 701 if (source == NULL) { 702 ALOGE("Unable to extract gralloc buffer in metadata mode"); 703 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 704 return; 705 } 706 } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { 707 ConvertYUV420SemiPlanarToYUV420Planar( 708 source, mConversionBuffer, mWidth, mHeight); 709 710 source = mConversionBuffer; 711 } 712 vpx_image_t raw_frame; 713 vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight, 714 kInputBufferAlignment, (uint8_t *)source); 715 716 vpx_enc_frame_flags_t flags = 0; 717 if (mTemporalPatternLength > 0) { 718 flags = getEncodeFlags(); 719 } 720 if (mKeyFrameRequested) { 721 flags |= VPX_EFLAG_FORCE_KF; 722 mKeyFrameRequested = false; 723 } 724 725 if (mBitrateUpdated) { 726 mCodecConfiguration->rc_target_bitrate = mBitrate/1000; 727 vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext, 728 mCodecConfiguration); 729 if (res != VPX_CODEC_OK) { 730 ALOGE("vp8 encoder failed to update bitrate: %s", 731 vpx_codec_err_to_string(res)); 732 notify(OMX_EventError, 733 OMX_ErrorUndefined, 734 0, // Extra notification data 735 NULL); // Notification data pointer 736 } 737 mBitrateUpdated = false; 738 } 739 740 uint32_t frameDuration; 741 if (inputBufferHeader->nTimeStamp > mLastTimestamp) { 742 frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp); 743 } else { 744 frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate); 745 } 746 mLastTimestamp = inputBufferHeader->nTimeStamp; 747 codec_return = vpx_codec_encode( 748 mCodecContext, 749 &raw_frame, 750 inputBufferHeader->nTimeStamp, // in timebase units 751 frameDuration, // frame duration in timebase units 752 flags, // frame flags 753 VPX_DL_REALTIME); // encoding deadline 754 if (codec_return != VPX_CODEC_OK) { 755 ALOGE("vpx encoder failed to encode frame"); 756 notify(OMX_EventError, 757 OMX_ErrorUndefined, 758 0, // Extra notification data 759 NULL); // Notification data pointer 760 return; 761 } 762 763 vpx_codec_iter_t encoded_packet_iterator = NULL; 764 const vpx_codec_cx_pkt_t* encoded_packet; 765 766 while ((encoded_packet = vpx_codec_get_cx_data( 767 mCodecContext, &encoded_packet_iterator))) { 768 if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) { 769 outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts; 770 outputBufferHeader->nFlags = 0; 771 if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY) 772 outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; 773 outputBufferHeader->nOffset = 0; 774 outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz; 775 memcpy(outputBufferHeader->pBuffer, 776 encoded_packet->data.frame.buf, 777 encoded_packet->data.frame.sz); 778 outputBufferInfo->mOwnedByUs = false; 779 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin()); 780 if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) { 781 outputBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS; 782 } 783 notifyFillBufferDone(outputBufferHeader); 784 } 785 } 786 787 inputBufferInfo->mOwnedByUs = false; 788 inputBufferInfoQueue.erase(inputBufferInfoQueue.begin()); 789 notifyEmptyBufferDone(inputBufferHeader); 790 } 791} 792 793} // namespace android 794 795 796android::SoftOMXComponent *createSoftOMXComponent( 797 const char *name, const OMX_CALLBACKTYPE *callbacks, 798 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 799 return new android::SoftVPXEncoder(name, callbacks, appData, component); 800} 801