SoftVPXEncoder.cpp revision 2edda09a2ad1d112c52acd37d323f63f0a492d67
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 23#include <media/hardware/HardwareAPI.h> 24#include <media/hardware/MetadataBufferType.h> 25#include <media/stagefright/foundation/ADebug.h> 26#include <media/stagefright/MediaDefs.h> 27 28namespace android { 29 30template<class T> 31static void InitOMXParams(T *params) { 32 params->nSize = sizeof(T); 33 // OMX IL 1.1.2 34 params->nVersion.s.nVersionMajor = 1; 35 params->nVersion.s.nVersionMinor = 1; 36 params->nVersion.s.nRevision = 2; 37 params->nVersion.s.nStep = 0; 38} 39 40 41static int GetCPUCoreCount() { 42 int cpuCoreCount = 1; 43#if defined(_SC_NPROCESSORS_ONLN) 44 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); 45#else 46 // _SC_NPROC_ONLN must be defined... 47 cpuCoreCount = sysconf(_SC_NPROC_ONLN); 48#endif 49 CHECK_GE(cpuCoreCount, 1); 50 return cpuCoreCount; 51} 52 53SoftVPXEncoder::SoftVPXEncoder(const char *name, 54 const OMX_CALLBACKTYPE *callbacks, 55 OMX_PTR appData, 56 OMX_COMPONENTTYPE **component) 57 : SoftVideoEncoderOMXComponent(name, callbacks, appData, component), 58 mCodecContext(NULL), 59 mCodecConfiguration(NULL), 60 mCodecInterface(NULL), 61 mWidth(176), 62 mHeight(144), 63 mBitrate(192000), // in bps 64 mFramerate(30 << 16), // in Q16 format 65 mBitrateUpdated(false), 66 mBitrateControlMode(VPX_VBR), // variable bitrate 67 mDCTPartitions(0), 68 mErrorResilience(OMX_FALSE), 69 mColorFormat(OMX_COLOR_FormatYUV420Planar), 70 mLevel(OMX_VIDEO_VP8Level_Version0), 71 mKeyFrameInterval(0), 72 mMinQuantizer(0), 73 mMaxQuantizer(0), 74 mTemporalLayers(0), 75 mTemporalPatternType(OMX_VIDEO_VPXTemporalLayerPatternNone), 76 mTemporalPatternLength(0), 77 mTemporalPatternIdx(0), 78 mLastTimestamp(0x7FFFFFFFFFFFFFFFLL), 79 mConversionBuffer(NULL), 80 mInputDataIsMeta(false), 81 mKeyFrameRequested(false) { 82 memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio)); 83 mTemporalLayerBitrateRatio[0] = 100; 84 initPorts(); 85} 86 87 88SoftVPXEncoder::~SoftVPXEncoder() { 89 releaseEncoder(); 90} 91 92 93void SoftVPXEncoder::initPorts() { 94 OMX_PARAM_PORTDEFINITIONTYPE inputPort; 95 OMX_PARAM_PORTDEFINITIONTYPE outputPort; 96 97 InitOMXParams(&inputPort); 98 InitOMXParams(&outputPort); 99 100 inputPort.nBufferCountMin = kNumBuffers; 101 inputPort.nBufferCountActual = inputPort.nBufferCountMin; 102 inputPort.bEnabled = OMX_TRUE; 103 inputPort.bPopulated = OMX_FALSE; 104 inputPort.eDomain = OMX_PortDomainVideo; 105 inputPort.bBuffersContiguous = OMX_FALSE; 106 inputPort.format.video.pNativeRender = NULL; 107 inputPort.format.video.nFrameWidth = mWidth; 108 inputPort.format.video.nFrameHeight = mHeight; 109 inputPort.format.video.nStride = inputPort.format.video.nFrameWidth; 110 inputPort.format.video.nSliceHeight = inputPort.format.video.nFrameHeight; 111 inputPort.format.video.nBitrate = 0; 112 // frameRate is in Q16 format. 113 inputPort.format.video.xFramerate = mFramerate; 114 inputPort.format.video.bFlagErrorConcealment = OMX_FALSE; 115 inputPort.nPortIndex = kInputPortIndex; 116 inputPort.eDir = OMX_DirInput; 117 inputPort.nBufferAlignment = kInputBufferAlignment; 118 inputPort.format.video.cMIMEType = 119 const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW); 120 inputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; 121 inputPort.format.video.eColorFormat = mColorFormat; 122 inputPort.format.video.pNativeWindow = NULL; 123 inputPort.nBufferSize = 124 (inputPort.format.video.nStride * 125 inputPort.format.video.nSliceHeight * 3) / 2; 126 127 addPort(inputPort); 128 129 outputPort.nBufferCountMin = kNumBuffers; 130 outputPort.nBufferCountActual = outputPort.nBufferCountMin; 131 outputPort.bEnabled = OMX_TRUE; 132 outputPort.bPopulated = OMX_FALSE; 133 outputPort.eDomain = OMX_PortDomainVideo; 134 outputPort.bBuffersContiguous = OMX_FALSE; 135 outputPort.format.video.pNativeRender = NULL; 136 outputPort.format.video.nFrameWidth = mWidth; 137 outputPort.format.video.nFrameHeight = mHeight; 138 outputPort.format.video.nStride = outputPort.format.video.nFrameWidth; 139 outputPort.format.video.nSliceHeight = outputPort.format.video.nFrameHeight; 140 outputPort.format.video.nBitrate = mBitrate; 141 outputPort.format.video.xFramerate = 0; 142 outputPort.format.video.bFlagErrorConcealment = OMX_FALSE; 143 outputPort.nPortIndex = kOutputPortIndex; 144 outputPort.eDir = OMX_DirOutput; 145 outputPort.nBufferAlignment = kOutputBufferAlignment; 146 outputPort.format.video.cMIMEType = 147 const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VP8); 148 outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVP8; 149 outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused; 150 outputPort.format.video.pNativeWindow = NULL; 151 outputPort.nBufferSize = 1024 * 1024; // arbitrary 152 153 addPort(outputPort); 154} 155 156 157status_t SoftVPXEncoder::initEncoder() { 158 vpx_codec_err_t codec_return; 159 160 mCodecContext = new vpx_codec_ctx_t; 161 mCodecConfiguration = new vpx_codec_enc_cfg_t; 162 mCodecInterface = vpx_codec_vp8_cx(); 163 164 if (mCodecInterface == NULL) { 165 return UNKNOWN_ERROR; 166 } 167 ALOGD("VP8: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u", 168 (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval, 169 mMinQuantizer, mMaxQuantizer); 170 codec_return = vpx_codec_enc_config_default(mCodecInterface, 171 mCodecConfiguration, 172 0); // Codec specific flags 173 174 if (codec_return != VPX_CODEC_OK) { 175 ALOGE("Error populating default configuration for vpx encoder."); 176 return UNKNOWN_ERROR; 177 } 178 179 mCodecConfiguration->g_w = mWidth; 180 mCodecConfiguration->g_h = mHeight; 181 mCodecConfiguration->g_threads = GetCPUCoreCount(); 182 mCodecConfiguration->g_error_resilient = mErrorResilience; 183 184 switch (mLevel) { 185 case OMX_VIDEO_VP8Level_Version0: 186 mCodecConfiguration->g_profile = 0; 187 break; 188 189 case OMX_VIDEO_VP8Level_Version1: 190 mCodecConfiguration->g_profile = 1; 191 break; 192 193 case OMX_VIDEO_VP8Level_Version2: 194 mCodecConfiguration->g_profile = 2; 195 break; 196 197 case OMX_VIDEO_VP8Level_Version3: 198 mCodecConfiguration->g_profile = 3; 199 break; 200 201 default: 202 mCodecConfiguration->g_profile = 0; 203 } 204 205 // OMX timebase unit is microsecond 206 // g_timebase is in seconds (i.e. 1/1000000 seconds) 207 mCodecConfiguration->g_timebase.num = 1; 208 mCodecConfiguration->g_timebase.den = 1000000; 209 // rc_target_bitrate is in kbps, mBitrate in bps 210 mCodecConfiguration->rc_target_bitrate = (mBitrate + 500) / 1000; 211 mCodecConfiguration->rc_end_usage = mBitrateControlMode; 212 // Disable frame drop - not allowed in MediaCodec now. 213 mCodecConfiguration->rc_dropframe_thresh = 0; 214 if (mBitrateControlMode == VPX_CBR) { 215 // Disable spatial resizing. 216 mCodecConfiguration->rc_resize_allowed = 0; 217 // Single-pass mode. 218 mCodecConfiguration->g_pass = VPX_RC_ONE_PASS; 219 // Maximum amount of bits that can be subtracted from the target 220 // bitrate - expressed as percentage of the target bitrate. 221 mCodecConfiguration->rc_undershoot_pct = 100; 222 // Maximum amount of bits that can be added to the target 223 // bitrate - expressed as percentage of the target bitrate. 224 mCodecConfiguration->rc_overshoot_pct = 15; 225 // Initial value of the buffer level in ms. 226 mCodecConfiguration->rc_buf_initial_sz = 500; 227 // Amount of data that the encoder should try to maintain in ms. 228 mCodecConfiguration->rc_buf_optimal_sz = 600; 229 // The amount of data that may be buffered by the decoding 230 // application in ms. 231 mCodecConfiguration->rc_buf_sz = 1000; 232 // Enable error resilience - needed for packet loss. 233 mCodecConfiguration->g_error_resilient = 1; 234 // Disable lagged encoding. 235 mCodecConfiguration->g_lag_in_frames = 0; 236 // Maximum key frame interval - for CBR boost to 3000 237 mCodecConfiguration->kf_max_dist = 3000; 238 // Encoder determines optimal key frame placement automatically. 239 mCodecConfiguration->kf_mode = VPX_KF_AUTO; 240 } 241 242 // Frames temporal pattern - for now WebRTC like pattern is only supported. 243 switch (mTemporalLayers) { 244 case 0: 245 { 246 mTemporalPatternLength = 0; 247 break; 248 } 249 case 1: 250 { 251 mCodecConfiguration->ts_number_layers = 1; 252 mCodecConfiguration->ts_rate_decimator[0] = 1; 253 mCodecConfiguration->ts_periodicity = 1; 254 mCodecConfiguration->ts_layer_id[0] = 0; 255 mTemporalPattern[0] = kTemporalUpdateLastRefAll; 256 mTemporalPatternLength = 1; 257 break; 258 } 259 case 2: 260 { 261 mCodecConfiguration->ts_number_layers = 2; 262 mCodecConfiguration->ts_rate_decimator[0] = 2; 263 mCodecConfiguration->ts_rate_decimator[1] = 1; 264 mCodecConfiguration->ts_periodicity = 2; 265 mCodecConfiguration->ts_layer_id[0] = 0; 266 mCodecConfiguration->ts_layer_id[1] = 1; 267 mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef; 268 mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef; 269 mTemporalPattern[2] = kTemporalUpdateLastRefAltRef; 270 mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef; 271 mTemporalPattern[4] = kTemporalUpdateLastRefAltRef; 272 mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef; 273 mTemporalPattern[6] = kTemporalUpdateLastRefAltRef; 274 mTemporalPattern[7] = kTemporalUpdateNone; 275 mTemporalPatternLength = 8; 276 break; 277 } 278 case 3: 279 { 280 mCodecConfiguration->ts_number_layers = 3; 281 mCodecConfiguration->ts_rate_decimator[0] = 4; 282 mCodecConfiguration->ts_rate_decimator[1] = 2; 283 mCodecConfiguration->ts_rate_decimator[2] = 1; 284 mCodecConfiguration->ts_periodicity = 4; 285 mCodecConfiguration->ts_layer_id[0] = 0; 286 mCodecConfiguration->ts_layer_id[1] = 2; 287 mCodecConfiguration->ts_layer_id[2] = 1; 288 mCodecConfiguration->ts_layer_id[3] = 2; 289 mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef; 290 mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef; 291 mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef; 292 mTemporalPattern[3] = kTemporalUpdateNone; 293 mTemporalPattern[4] = kTemporalUpdateLastRefAltRef; 294 mTemporalPattern[5] = kTemporalUpdateNone; 295 mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef; 296 mTemporalPattern[7] = kTemporalUpdateNone; 297 mTemporalPatternLength = 8; 298 break; 299 } 300 default: 301 { 302 ALOGE("Wrong number of temporal layers %zu", mTemporalLayers); 303 return UNKNOWN_ERROR; 304 } 305 } 306 307 // Set bitrate values for each layer 308 for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) { 309 mCodecConfiguration->ts_target_bitrate[i] = 310 mCodecConfiguration->rc_target_bitrate * 311 mTemporalLayerBitrateRatio[i] / 100; 312 } 313 if (mKeyFrameInterval > 0) { 314 mCodecConfiguration->kf_max_dist = mKeyFrameInterval; 315 mCodecConfiguration->kf_min_dist = mKeyFrameInterval; 316 mCodecConfiguration->kf_mode = VPX_KF_AUTO; 317 } 318 if (mMinQuantizer > 0) { 319 mCodecConfiguration->rc_min_quantizer = mMinQuantizer; 320 } 321 if (mMaxQuantizer > 0) { 322 mCodecConfiguration->rc_max_quantizer = mMaxQuantizer; 323 } 324 325 codec_return = vpx_codec_enc_init(mCodecContext, 326 mCodecInterface, 327 mCodecConfiguration, 328 0); // flags 329 330 if (codec_return != VPX_CODEC_OK) { 331 ALOGE("Error initializing vpx encoder"); 332 return UNKNOWN_ERROR; 333 } 334 335 codec_return = vpx_codec_control(mCodecContext, 336 VP8E_SET_TOKEN_PARTITIONS, 337 mDCTPartitions); 338 if (codec_return != VPX_CODEC_OK) { 339 ALOGE("Error setting dct partitions for vpx encoder."); 340 return UNKNOWN_ERROR; 341 } 342 343 // Extra CBR settings 344 if (mBitrateControlMode == VPX_CBR) { 345 codec_return = vpx_codec_control(mCodecContext, 346 VP8E_SET_STATIC_THRESHOLD, 347 1); 348 if (codec_return == VPX_CODEC_OK) { 349 uint32_t rc_max_intra_target = 350 mCodecConfiguration->rc_buf_optimal_sz * (mFramerate >> 17) / 10; 351 // Don't go below 3 times per frame bandwidth. 352 if (rc_max_intra_target < 300) { 353 rc_max_intra_target = 300; 354 } 355 codec_return = vpx_codec_control(mCodecContext, 356 VP8E_SET_MAX_INTRA_BITRATE_PCT, 357 rc_max_intra_target); 358 } 359 if (codec_return == VPX_CODEC_OK) { 360 codec_return = vpx_codec_control(mCodecContext, 361 VP8E_SET_CPUUSED, 362 -8); 363 } 364 if (codec_return != VPX_CODEC_OK) { 365 ALOGE("Error setting cbr parameters for vpx encoder."); 366 return UNKNOWN_ERROR; 367 } 368 } 369 370 if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) { 371 free(mConversionBuffer); 372 mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2); 373 if (mConversionBuffer == NULL) { 374 ALOGE("Allocating conversion buffer failed."); 375 return UNKNOWN_ERROR; 376 } 377 } 378 return OK; 379} 380 381 382status_t SoftVPXEncoder::releaseEncoder() { 383 if (mCodecContext != NULL) { 384 vpx_codec_destroy(mCodecContext); 385 delete mCodecContext; 386 mCodecContext = NULL; 387 } 388 389 if (mCodecConfiguration != NULL) { 390 delete mCodecConfiguration; 391 mCodecConfiguration = NULL; 392 } 393 394 if (mConversionBuffer != NULL) { 395 free(mConversionBuffer); 396 mConversionBuffer = NULL; 397 } 398 399 // this one is not allocated by us 400 mCodecInterface = NULL; 401 402 return OK; 403} 404 405 406OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index, 407 OMX_PTR param) { 408 // can include extension index OMX_INDEXEXTTYPE 409 const int32_t indexFull = index; 410 411 switch (indexFull) { 412 case OMX_IndexParamVideoPortFormat: { 413 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 414 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param; 415 416 if (formatParams->nPortIndex == kInputPortIndex) { 417 if (formatParams->nIndex >= kNumberOfSupportedColorFormats) { 418 return OMX_ErrorNoMore; 419 } 420 421 // Color formats, in order of preference 422 if (formatParams->nIndex == 0) { 423 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar; 424 } else if (formatParams->nIndex == 1) { 425 formatParams->eColorFormat = 426 OMX_COLOR_FormatYUV420SemiPlanar; 427 } else { 428 formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque; 429 } 430 431 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; 432 formatParams->xFramerate = mFramerate; 433 return OMX_ErrorNone; 434 } else if (formatParams->nPortIndex == kOutputPortIndex) { 435 formatParams->eCompressionFormat = OMX_VIDEO_CodingVP8; 436 formatParams->eColorFormat = OMX_COLOR_FormatUnused; 437 formatParams->xFramerate = 0; 438 return OMX_ErrorNone; 439 } else { 440 return OMX_ErrorBadPortIndex; 441 } 442 } 443 444 case OMX_IndexParamVideoBitrate: { 445 OMX_VIDEO_PARAM_BITRATETYPE *bitrate = 446 (OMX_VIDEO_PARAM_BITRATETYPE *)param; 447 448 if (bitrate->nPortIndex != kOutputPortIndex) { 449 return OMX_ErrorUnsupportedIndex; 450 } 451 452 bitrate->nTargetBitrate = mBitrate; 453 454 if (mBitrateControlMode == VPX_VBR) { 455 bitrate->eControlRate = OMX_Video_ControlRateVariable; 456 } else if (mBitrateControlMode == VPX_CBR) { 457 bitrate->eControlRate = OMX_Video_ControlRateConstant; 458 } else { 459 return OMX_ErrorUnsupportedSetting; 460 } 461 return OMX_ErrorNone; 462 } 463 464 // VP8 specific parameters that use extension headers 465 case OMX_IndexParamVideoVp8: { 466 OMX_VIDEO_PARAM_VP8TYPE *vp8Params = 467 (OMX_VIDEO_PARAM_VP8TYPE *)param; 468 469 if (vp8Params->nPortIndex != kOutputPortIndex) { 470 return OMX_ErrorUnsupportedIndex; 471 } 472 473 vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain; 474 vp8Params->eLevel = mLevel; 475 vp8Params->nDCTPartitions = mDCTPartitions; 476 vp8Params->bErrorResilientMode = mErrorResilience; 477 return OMX_ErrorNone; 478 } 479 480 case OMX_IndexParamVideoAndroidVp8Encoder: { 481 OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vp8AndroidParams = 482 (OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param; 483 484 if (vp8AndroidParams->nPortIndex != kOutputPortIndex) { 485 return OMX_ErrorUnsupportedIndex; 486 } 487 488 vp8AndroidParams->nKeyFrameInterval = mKeyFrameInterval; 489 vp8AndroidParams->eTemporalPattern = mTemporalPatternType; 490 vp8AndroidParams->nTemporalLayerCount = mTemporalLayers; 491 vp8AndroidParams->nMinQuantizer = mMinQuantizer; 492 vp8AndroidParams->nMaxQuantizer = mMaxQuantizer; 493 memcpy(vp8AndroidParams->nTemporalLayerBitrateRatio, 494 mTemporalLayerBitrateRatio, sizeof(mTemporalLayerBitrateRatio)); 495 return OMX_ErrorNone; 496 } 497 498 case OMX_IndexParamVideoProfileLevelQuerySupported: { 499 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel = 500 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param; 501 502 if (profileAndLevel->nPortIndex != kOutputPortIndex) { 503 return OMX_ErrorUnsupportedIndex; 504 } 505 506 switch (profileAndLevel->nProfileIndex) { 507 case 0: 508 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version0; 509 break; 510 511 case 1: 512 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version1; 513 break; 514 515 case 2: 516 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version2; 517 break; 518 519 case 3: 520 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version3; 521 break; 522 523 default: 524 return OMX_ErrorNoMore; 525 } 526 527 profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain; 528 return OMX_ErrorNone; 529 } 530 531 case OMX_IndexParamVideoProfileLevelCurrent: { 532 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel = 533 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param; 534 535 if (profileAndLevel->nPortIndex != kOutputPortIndex) { 536 return OMX_ErrorUnsupportedIndex; 537 } 538 539 profileAndLevel->eLevel = mLevel; 540 profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain; 541 return OMX_ErrorNone; 542 } 543 544 default: 545 return SimpleSoftOMXComponent::internalGetParameter(index, param); 546 } 547} 548 549 550OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index, 551 const OMX_PTR param) { 552 // can include extension index OMX_INDEXEXTTYPE 553 const int32_t indexFull = index; 554 555 switch (indexFull) { 556 case OMX_IndexParamStandardComponentRole: 557 return internalSetRoleParams( 558 (const OMX_PARAM_COMPONENTROLETYPE *)param); 559 560 case OMX_IndexParamVideoBitrate: 561 return internalSetBitrateParams( 562 (const OMX_VIDEO_PARAM_BITRATETYPE *)param); 563 564 case OMX_IndexParamPortDefinition: 565 { 566 OMX_ERRORTYPE err = internalSetPortParams( 567 (const OMX_PARAM_PORTDEFINITIONTYPE *)param); 568 569 if (err != OMX_ErrorNone) { 570 return err; 571 } 572 573 return SimpleSoftOMXComponent::internalSetParameter(index, param); 574 } 575 576 case OMX_IndexParamVideoPortFormat: 577 return internalSetFormatParams( 578 (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param); 579 580 case OMX_IndexParamVideoVp8: 581 return internalSetVp8Params( 582 (const OMX_VIDEO_PARAM_VP8TYPE *)param); 583 584 case OMX_IndexParamVideoAndroidVp8Encoder: 585 return internalSetAndroidVp8Params( 586 (const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param); 587 588 case OMX_IndexParamVideoProfileLevelCurrent: 589 return internalSetProfileLevel( 590 (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param); 591 592 case kStoreMetaDataExtensionIndex: 593 { 594 // storeMetaDataInBuffers 595 const StoreMetaDataInBuffersParams *storeParam = 596 (const StoreMetaDataInBuffersParams *)param; 597 598 if (storeParam->nPortIndex != kInputPortIndex) { 599 return OMX_ErrorBadPortIndex; 600 } 601 602 mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE); 603 604 return OMX_ErrorNone; 605 } 606 607 default: 608 return SimpleSoftOMXComponent::internalSetParameter(index, param); 609 } 610} 611 612OMX_ERRORTYPE SoftVPXEncoder::setConfig( 613 OMX_INDEXTYPE index, const OMX_PTR _params) { 614 switch (index) { 615 case OMX_IndexConfigVideoIntraVOPRefresh: 616 { 617 OMX_CONFIG_INTRAREFRESHVOPTYPE *params = 618 (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params; 619 620 if (params->nPortIndex != kOutputPortIndex) { 621 return OMX_ErrorBadPortIndex; 622 } 623 624 mKeyFrameRequested = params->IntraRefreshVOP; 625 return OMX_ErrorNone; 626 } 627 628 case OMX_IndexConfigVideoBitrate: 629 { 630 OMX_VIDEO_CONFIG_BITRATETYPE *params = 631 (OMX_VIDEO_CONFIG_BITRATETYPE *)_params; 632 633 if (params->nPortIndex != kOutputPortIndex) { 634 return OMX_ErrorBadPortIndex; 635 } 636 637 if (mBitrate != params->nEncodeBitrate) { 638 mBitrate = params->nEncodeBitrate; 639 mBitrateUpdated = true; 640 } 641 return OMX_ErrorNone; 642 } 643 644 default: 645 return SimpleSoftOMXComponent::setConfig(index, _params); 646 } 647} 648 649OMX_ERRORTYPE SoftVPXEncoder::internalSetProfileLevel( 650 const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel) { 651 if (profileAndLevel->nPortIndex != kOutputPortIndex) { 652 return OMX_ErrorUnsupportedIndex; 653 } 654 655 if (profileAndLevel->eProfile != OMX_VIDEO_VP8ProfileMain) { 656 return OMX_ErrorBadParameter; 657 } 658 659 if (profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version0 || 660 profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version1 || 661 profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version2 || 662 profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version3) { 663 mLevel = (OMX_VIDEO_VP8LEVELTYPE)profileAndLevel->eLevel; 664 } else { 665 return OMX_ErrorBadParameter; 666 } 667 668 return OMX_ErrorNone; 669} 670 671 672OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params( 673 const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) { 674 if (vp8Params->nPortIndex != kOutputPortIndex) { 675 return OMX_ErrorUnsupportedIndex; 676 } 677 678 if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) { 679 return OMX_ErrorBadParameter; 680 } 681 682 if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 || 683 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 || 684 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 || 685 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) { 686 mLevel = vp8Params->eLevel; 687 } else { 688 return OMX_ErrorBadParameter; 689 } 690 691 if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) { 692 mDCTPartitions = vp8Params->nDCTPartitions; 693 } else { 694 return OMX_ErrorBadParameter; 695 } 696 697 mErrorResilience = vp8Params->bErrorResilientMode; 698 return OMX_ErrorNone; 699} 700 701OMX_ERRORTYPE SoftVPXEncoder::internalSetAndroidVp8Params( 702 const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams) { 703 if (vp8AndroidParams->nPortIndex != kOutputPortIndex) { 704 return OMX_ErrorUnsupportedIndex; 705 } 706 if (vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternNone && 707 vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternWebRTC) { 708 return OMX_ErrorBadParameter; 709 } 710 if (vp8AndroidParams->nTemporalLayerCount > OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) { 711 return OMX_ErrorBadParameter; 712 } 713 if (vp8AndroidParams->nMinQuantizer > vp8AndroidParams->nMaxQuantizer) { 714 return OMX_ErrorBadParameter; 715 } 716 717 mTemporalPatternType = vp8AndroidParams->eTemporalPattern; 718 if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) { 719 mTemporalLayers = vp8AndroidParams->nTemporalLayerCount; 720 } else if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternNone) { 721 mTemporalLayers = 0; 722 } 723 // Check the bitrate distribution between layers is in increasing order 724 if (mTemporalLayers > 1) { 725 for (size_t i = 0; i < mTemporalLayers - 1; i++) { 726 if (vp8AndroidParams->nTemporalLayerBitrateRatio[i + 1] <= 727 vp8AndroidParams->nTemporalLayerBitrateRatio[i]) { 728 ALOGE("Wrong bitrate ratio - should be in increasing order."); 729 return OMX_ErrorBadParameter; 730 } 731 } 732 } 733 mKeyFrameInterval = vp8AndroidParams->nKeyFrameInterval; 734 mMinQuantizer = vp8AndroidParams->nMinQuantizer; 735 mMaxQuantizer = vp8AndroidParams->nMaxQuantizer; 736 memcpy(mTemporalLayerBitrateRatio, vp8AndroidParams->nTemporalLayerBitrateRatio, 737 sizeof(mTemporalLayerBitrateRatio)); 738 ALOGD("VP8: internalSetAndroidVp8Params. BRMode: %u. TS: %zu. KF: %u." 739 " QP: %u - %u BR0: %u. BR1: %u. BR2: %u", 740 (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval, 741 mMinQuantizer, mMaxQuantizer, mTemporalLayerBitrateRatio[0], 742 mTemporalLayerBitrateRatio[1], mTemporalLayerBitrateRatio[2]); 743 return OMX_ErrorNone; 744} 745 746OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams( 747 const OMX_VIDEO_PARAM_PORTFORMATTYPE* format) { 748 if (format->nPortIndex == kInputPortIndex) { 749 if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar || 750 format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || 751 format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) { 752 mColorFormat = format->eColorFormat; 753 754 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; 755 def->format.video.eColorFormat = mColorFormat; 756 757 return OMX_ErrorNone; 758 } else { 759 ALOGE("Unsupported color format %i", format->eColorFormat); 760 return OMX_ErrorUnsupportedSetting; 761 } 762 } else if (format->nPortIndex == kOutputPortIndex) { 763 if (format->eCompressionFormat == OMX_VIDEO_CodingVP8) { 764 return OMX_ErrorNone; 765 } else { 766 return OMX_ErrorUnsupportedSetting; 767 } 768 } else { 769 return OMX_ErrorBadPortIndex; 770 } 771} 772 773 774OMX_ERRORTYPE SoftVPXEncoder::internalSetRoleParams( 775 const OMX_PARAM_COMPONENTROLETYPE* role) { 776 const char* roleText = (const char*)role->cRole; 777 const size_t roleTextMaxSize = OMX_MAX_STRINGNAME_SIZE - 1; 778 779 if (strncmp(roleText, "video_encoder.vp8", roleTextMaxSize)) { 780 ALOGE("Unsupported component role"); 781 return OMX_ErrorBadParameter; 782 } 783 784 return OMX_ErrorNone; 785} 786 787 788OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams( 789 const OMX_PARAM_PORTDEFINITIONTYPE* port) { 790 if (port->nPortIndex == kInputPortIndex) { 791 mWidth = port->format.video.nFrameWidth; 792 mHeight = port->format.video.nFrameHeight; 793 794 // xFramerate comes in Q16 format, in frames per second unit 795 mFramerate = port->format.video.xFramerate; 796 797 if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar || 798 port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || 799 port->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) { 800 mColorFormat = port->format.video.eColorFormat; 801 } else { 802 return OMX_ErrorUnsupportedSetting; 803 } 804 805 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; 806 def->format.video.nFrameWidth = mWidth; 807 def->format.video.nFrameHeight = mHeight; 808 def->format.video.xFramerate = mFramerate; 809 def->format.video.eColorFormat = mColorFormat; 810 def = &editPortInfo(kOutputPortIndex)->mDef; 811 def->format.video.nFrameWidth = mWidth; 812 def->format.video.nFrameHeight = mHeight; 813 814 return OMX_ErrorNone; 815 } else if (port->nPortIndex == kOutputPortIndex) { 816 mBitrate = port->format.video.nBitrate; 817 mWidth = port->format.video.nFrameWidth; 818 mHeight = port->format.video.nFrameHeight; 819 820 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef; 821 def->format.video.nFrameWidth = mWidth; 822 def->format.video.nFrameHeight = mHeight; 823 def->format.video.nBitrate = mBitrate; 824 return OMX_ErrorNone; 825 } else { 826 return OMX_ErrorBadPortIndex; 827 } 828} 829 830 831OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams( 832 const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) { 833 if (bitrate->nPortIndex != kOutputPortIndex) { 834 return OMX_ErrorUnsupportedIndex; 835 } 836 837 mBitrate = bitrate->nTargetBitrate; 838 839 if (bitrate->eControlRate == OMX_Video_ControlRateVariable) { 840 mBitrateControlMode = VPX_VBR; 841 } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) { 842 mBitrateControlMode = VPX_CBR; 843 } else { 844 return OMX_ErrorUnsupportedSetting; 845 } 846 847 return OMX_ErrorNone; 848} 849 850vpx_enc_frame_flags_t SoftVPXEncoder::getEncodeFlags() { 851 vpx_enc_frame_flags_t flags = 0; 852 int patternIdx = mTemporalPatternIdx % mTemporalPatternLength; 853 mTemporalPatternIdx++; 854 switch (mTemporalPattern[patternIdx]) { 855 case kTemporalUpdateLast: 856 flags |= VP8_EFLAG_NO_UPD_GF; 857 flags |= VP8_EFLAG_NO_UPD_ARF; 858 flags |= VP8_EFLAG_NO_REF_GF; 859 flags |= VP8_EFLAG_NO_REF_ARF; 860 break; 861 case kTemporalUpdateGoldenWithoutDependency: 862 flags |= VP8_EFLAG_NO_REF_GF; 863 // Deliberately no break here. 864 case kTemporalUpdateGolden: 865 flags |= VP8_EFLAG_NO_REF_ARF; 866 flags |= VP8_EFLAG_NO_UPD_ARF; 867 flags |= VP8_EFLAG_NO_UPD_LAST; 868 break; 869 case kTemporalUpdateAltrefWithoutDependency: 870 flags |= VP8_EFLAG_NO_REF_ARF; 871 flags |= VP8_EFLAG_NO_REF_GF; 872 // Deliberately no break here. 873 case kTemporalUpdateAltref: 874 flags |= VP8_EFLAG_NO_UPD_GF; 875 flags |= VP8_EFLAG_NO_UPD_LAST; 876 break; 877 case kTemporalUpdateNoneNoRefAltref: 878 flags |= VP8_EFLAG_NO_REF_ARF; 879 // Deliberately no break here. 880 case kTemporalUpdateNone: 881 flags |= VP8_EFLAG_NO_UPD_GF; 882 flags |= VP8_EFLAG_NO_UPD_ARF; 883 flags |= VP8_EFLAG_NO_UPD_LAST; 884 flags |= VP8_EFLAG_NO_UPD_ENTROPY; 885 break; 886 case kTemporalUpdateNoneNoRefGoldenRefAltRef: 887 flags |= VP8_EFLAG_NO_REF_GF; 888 flags |= VP8_EFLAG_NO_UPD_GF; 889 flags |= VP8_EFLAG_NO_UPD_ARF; 890 flags |= VP8_EFLAG_NO_UPD_LAST; 891 flags |= VP8_EFLAG_NO_UPD_ENTROPY; 892 break; 893 case kTemporalUpdateGoldenWithoutDependencyRefAltRef: 894 flags |= VP8_EFLAG_NO_REF_GF; 895 flags |= VP8_EFLAG_NO_UPD_ARF; 896 flags |= VP8_EFLAG_NO_UPD_LAST; 897 break; 898 case kTemporalUpdateLastRefAltRef: 899 flags |= VP8_EFLAG_NO_UPD_GF; 900 flags |= VP8_EFLAG_NO_UPD_ARF; 901 flags |= VP8_EFLAG_NO_REF_GF; 902 break; 903 case kTemporalUpdateGoldenRefAltRef: 904 flags |= VP8_EFLAG_NO_UPD_ARF; 905 flags |= VP8_EFLAG_NO_UPD_LAST; 906 break; 907 case kTemporalUpdateLastAndGoldenRefAltRef: 908 flags |= VP8_EFLAG_NO_UPD_ARF; 909 flags |= VP8_EFLAG_NO_REF_GF; 910 break; 911 case kTemporalUpdateLastRefAll: 912 flags |= VP8_EFLAG_NO_UPD_ARF; 913 flags |= VP8_EFLAG_NO_UPD_GF; 914 break; 915 } 916 return flags; 917} 918 919void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { 920 // Initialize encoder if not already 921 if (mCodecContext == NULL) { 922 if (OK != initEncoder()) { 923 ALOGE("Failed to initialize encoder"); 924 notify(OMX_EventError, 925 OMX_ErrorUndefined, 926 0, // Extra notification data 927 NULL); // Notification data pointer 928 return; 929 } 930 } 931 932 vpx_codec_err_t codec_return; 933 List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex); 934 List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex); 935 936 while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) { 937 BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin(); 938 OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader; 939 940 BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin(); 941 OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader; 942 943 if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) { 944 inputBufferInfoQueue.erase(inputBufferInfoQueue.begin()); 945 inputBufferInfo->mOwnedByUs = false; 946 notifyEmptyBufferDone(inputBufferHeader); 947 948 outputBufferHeader->nFilledLen = 0; 949 outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS; 950 951 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin()); 952 outputBufferInfo->mOwnedByUs = false; 953 notifyFillBufferDone(outputBufferHeader); 954 return; 955 } 956 957 const uint8_t *source = 958 inputBufferHeader->pBuffer + inputBufferHeader->nOffset; 959 960 if (mInputDataIsMeta) { 961 source = extractGraphicBuffer( 962 mConversionBuffer, mWidth * mHeight * 3 / 2, 963 source, inputBufferHeader->nFilledLen, 964 mWidth, mHeight); 965 if (source == NULL) { 966 ALOGE("Unable to extract gralloc buffer in metadata mode"); 967 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 968 return; 969 } 970 } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { 971 ConvertYUV420SemiPlanarToYUV420Planar( 972 source, mConversionBuffer, mWidth, mHeight); 973 974 source = mConversionBuffer; 975 } 976 vpx_image_t raw_frame; 977 vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight, 978 kInputBufferAlignment, (uint8_t *)source); 979 980 vpx_enc_frame_flags_t flags = 0; 981 if (mTemporalPatternLength > 0) { 982 flags = getEncodeFlags(); 983 } 984 if (mKeyFrameRequested) { 985 flags |= VPX_EFLAG_FORCE_KF; 986 mKeyFrameRequested = false; 987 } 988 989 if (mBitrateUpdated) { 990 mCodecConfiguration->rc_target_bitrate = mBitrate/1000; 991 vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext, 992 mCodecConfiguration); 993 if (res != VPX_CODEC_OK) { 994 ALOGE("vp8 encoder failed to update bitrate: %s", 995 vpx_codec_err_to_string(res)); 996 notify(OMX_EventError, 997 OMX_ErrorUndefined, 998 0, // Extra notification data 999 NULL); // Notification data pointer 1000 } 1001 mBitrateUpdated = false; 1002 } 1003 1004 uint32_t frameDuration; 1005 if (inputBufferHeader->nTimeStamp > mLastTimestamp) { 1006 frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp); 1007 } else { 1008 frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate); 1009 } 1010 mLastTimestamp = inputBufferHeader->nTimeStamp; 1011 codec_return = vpx_codec_encode( 1012 mCodecContext, 1013 &raw_frame, 1014 inputBufferHeader->nTimeStamp, // in timebase units 1015 frameDuration, // frame duration in timebase units 1016 flags, // frame flags 1017 VPX_DL_REALTIME); // encoding deadline 1018 if (codec_return != VPX_CODEC_OK) { 1019 ALOGE("vpx encoder failed to encode frame"); 1020 notify(OMX_EventError, 1021 OMX_ErrorUndefined, 1022 0, // Extra notification data 1023 NULL); // Notification data pointer 1024 return; 1025 } 1026 1027 vpx_codec_iter_t encoded_packet_iterator = NULL; 1028 const vpx_codec_cx_pkt_t* encoded_packet; 1029 1030 while ((encoded_packet = vpx_codec_get_cx_data( 1031 mCodecContext, &encoded_packet_iterator))) { 1032 if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) { 1033 outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts; 1034 outputBufferHeader->nFlags = 0; 1035 if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY) 1036 outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; 1037 outputBufferHeader->nOffset = 0; 1038 outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz; 1039 memcpy(outputBufferHeader->pBuffer, 1040 encoded_packet->data.frame.buf, 1041 encoded_packet->data.frame.sz); 1042 outputBufferInfo->mOwnedByUs = false; 1043 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin()); 1044 notifyFillBufferDone(outputBufferHeader); 1045 } 1046 } 1047 1048 inputBufferInfo->mOwnedByUs = false; 1049 inputBufferInfoQueue.erase(inputBufferInfoQueue.begin()); 1050 notifyEmptyBufferDone(inputBufferHeader); 1051 } 1052} 1053 1054} // namespace android 1055 1056 1057android::SoftOMXComponent *createSoftOMXComponent( 1058 const char *name, const OMX_CALLBACKTYPE *callbacks, 1059 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 1060 return new android::SoftVPXEncoder(name, callbacks, appData, component); 1061} 1062