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