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