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 28 namespace android { 29 30 31 template<class T> 32 static 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 42 static 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 56 inline 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 86 static 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 133 SoftVPXEncoder::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 mBitrateUpdated(false), 145 mBitrateControlMode(VPX_VBR), // variable bitrate 146 mFrameDurationUs(33333), // Defaults to 30 fps 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 159 SoftVPXEncoder::~SoftVPXEncoder() { 160 releaseEncoder(); 161 } 162 163 164 void 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 reciprocal of frameDuration, which is 184 // in microseconds. It is also in Q16 format. 185 inputPort.format.video.xFramerate = (1000000/mFrameDurationUs) << 16; 186 inputPort.format.video.bFlagErrorConcealment = OMX_FALSE; 187 inputPort.nPortIndex = kInputPortIndex; 188 inputPort.eDir = OMX_DirInput; 189 inputPort.nBufferAlignment = kInputBufferAlignment; 190 inputPort.format.video.cMIMEType = 191 const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW); 192 inputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; 193 inputPort.format.video.eColorFormat = mColorFormat; 194 inputPort.format.video.pNativeWindow = NULL; 195 inputPort.nBufferSize = 196 (inputPort.format.video.nStride * 197 inputPort.format.video.nSliceHeight * 3) / 2; 198 199 addPort(inputPort); 200 201 outputPort.nBufferCountMin = kNumBuffers; 202 outputPort.nBufferCountActual = outputPort.nBufferCountMin; 203 outputPort.bEnabled = OMX_TRUE; 204 outputPort.bPopulated = OMX_FALSE; 205 outputPort.eDomain = OMX_PortDomainVideo; 206 outputPort.bBuffersContiguous = OMX_FALSE; 207 outputPort.format.video.pNativeRender = NULL; 208 outputPort.format.video.nFrameWidth = mWidth; 209 outputPort.format.video.nFrameHeight = mHeight; 210 outputPort.format.video.nStride = outputPort.format.video.nFrameWidth; 211 outputPort.format.video.nSliceHeight = outputPort.format.video.nFrameHeight; 212 outputPort.format.video.nBitrate = mBitrate; 213 outputPort.format.video.xFramerate = 0; 214 outputPort.format.video.bFlagErrorConcealment = OMX_FALSE; 215 outputPort.nPortIndex = kOutputPortIndex; 216 outputPort.eDir = OMX_DirOutput; 217 outputPort.nBufferAlignment = kOutputBufferAlignment; 218 outputPort.format.video.cMIMEType = 219 const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VP8); 220 outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVP8; 221 outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused; 222 outputPort.format.video.pNativeWindow = NULL; 223 outputPort.nBufferSize = 256 * 1024; // arbitrary 224 225 addPort(outputPort); 226 } 227 228 229 status_t SoftVPXEncoder::initEncoder() { 230 vpx_codec_err_t codec_return; 231 232 mCodecContext = new vpx_codec_ctx_t; 233 mCodecConfiguration = new vpx_codec_enc_cfg_t; 234 mCodecInterface = vpx_codec_vp8_cx(); 235 236 if (mCodecInterface == NULL) { 237 return UNKNOWN_ERROR; 238 } 239 240 codec_return = vpx_codec_enc_config_default(mCodecInterface, 241 mCodecConfiguration, 242 0); // Codec specific flags 243 244 if (codec_return != VPX_CODEC_OK) { 245 ALOGE("Error populating default configuration for vpx encoder."); 246 return UNKNOWN_ERROR; 247 } 248 249 mCodecConfiguration->g_w = mWidth; 250 mCodecConfiguration->g_h = mHeight; 251 mCodecConfiguration->g_threads = GetCPUCoreCount(); 252 mCodecConfiguration->g_error_resilient = mErrorResilience; 253 254 switch (mLevel) { 255 case OMX_VIDEO_VP8Level_Version0: 256 mCodecConfiguration->g_profile = 0; 257 break; 258 259 case OMX_VIDEO_VP8Level_Version1: 260 mCodecConfiguration->g_profile = 1; 261 break; 262 263 case OMX_VIDEO_VP8Level_Version2: 264 mCodecConfiguration->g_profile = 2; 265 break; 266 267 case OMX_VIDEO_VP8Level_Version3: 268 mCodecConfiguration->g_profile = 3; 269 break; 270 271 default: 272 mCodecConfiguration->g_profile = 0; 273 } 274 275 // OMX timebase unit is microsecond 276 // g_timebase is in seconds (i.e. 1/1000000 seconds) 277 mCodecConfiguration->g_timebase.num = 1; 278 mCodecConfiguration->g_timebase.den = 1000000; 279 // rc_target_bitrate is in kbps, mBitrate in bps 280 mCodecConfiguration->rc_target_bitrate = mBitrate/1000; 281 mCodecConfiguration->rc_end_usage = mBitrateControlMode; 282 283 codec_return = vpx_codec_enc_init(mCodecContext, 284 mCodecInterface, 285 mCodecConfiguration, 286 0); // flags 287 288 if (codec_return != VPX_CODEC_OK) { 289 ALOGE("Error initializing vpx encoder"); 290 return UNKNOWN_ERROR; 291 } 292 293 codec_return = vpx_codec_control(mCodecContext, 294 VP8E_SET_TOKEN_PARTITIONS, 295 mDCTPartitions); 296 if (codec_return != VPX_CODEC_OK) { 297 ALOGE("Error setting dct partitions for vpx encoder."); 298 return UNKNOWN_ERROR; 299 } 300 301 if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) { 302 if (mConversionBuffer == NULL) { 303 mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2); 304 if (mConversionBuffer == NULL) { 305 ALOGE("Allocating conversion buffer failed."); 306 return UNKNOWN_ERROR; 307 } 308 } 309 } 310 return OK; 311 } 312 313 314 status_t SoftVPXEncoder::releaseEncoder() { 315 if (mCodecContext != NULL) { 316 vpx_codec_destroy(mCodecContext); 317 delete mCodecContext; 318 mCodecContext = NULL; 319 } 320 321 if (mCodecConfiguration != NULL) { 322 delete mCodecConfiguration; 323 mCodecConfiguration = NULL; 324 } 325 326 if (mConversionBuffer != NULL) { 327 delete mConversionBuffer; 328 mConversionBuffer = NULL; 329 } 330 331 // this one is not allocated by us 332 mCodecInterface = NULL; 333 334 return OK; 335 } 336 337 338 OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index, 339 OMX_PTR param) { 340 // can include extension index OMX_INDEXEXTTYPE 341 const int32_t indexFull = index; 342 343 switch (indexFull) { 344 case OMX_IndexParamVideoPortFormat: { 345 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 346 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param; 347 348 if (formatParams->nPortIndex == kInputPortIndex) { 349 if (formatParams->nIndex >= kNumberOfSupportedColorFormats) { 350 return OMX_ErrorNoMore; 351 } 352 353 // Color formats, in order of preference 354 if (formatParams->nIndex == 0) { 355 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar; 356 } else if (formatParams->nIndex == 1) { 357 formatParams->eColorFormat = 358 OMX_COLOR_FormatYUV420SemiPlanar; 359 } else { 360 formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque; 361 } 362 363 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; 364 // Converting from microseconds 365 // Also converting to Q16 format 366 formatParams->xFramerate = (1000000/mFrameDurationUs) << 16; 367 return OMX_ErrorNone; 368 } else if (formatParams->nPortIndex == kOutputPortIndex) { 369 formatParams->eCompressionFormat = OMX_VIDEO_CodingVP8; 370 formatParams->eColorFormat = OMX_COLOR_FormatUnused; 371 formatParams->xFramerate = 0; 372 return OMX_ErrorNone; 373 } else { 374 return OMX_ErrorBadPortIndex; 375 } 376 } 377 378 case OMX_IndexParamVideoBitrate: { 379 OMX_VIDEO_PARAM_BITRATETYPE *bitrate = 380 (OMX_VIDEO_PARAM_BITRATETYPE *)param; 381 382 if (bitrate->nPortIndex != kOutputPortIndex) { 383 return OMX_ErrorUnsupportedIndex; 384 } 385 386 bitrate->nTargetBitrate = mBitrate; 387 388 if (mBitrateControlMode == VPX_VBR) { 389 bitrate->eControlRate = OMX_Video_ControlRateVariable; 390 } else if (mBitrateControlMode == VPX_CBR) { 391 bitrate->eControlRate = OMX_Video_ControlRateConstant; 392 } else { 393 return OMX_ErrorUnsupportedSetting; 394 } 395 return OMX_ErrorNone; 396 } 397 398 // VP8 specific parameters that use extension headers 399 case OMX_IndexParamVideoVp8: { 400 OMX_VIDEO_PARAM_VP8TYPE *vp8Params = 401 (OMX_VIDEO_PARAM_VP8TYPE *)param; 402 403 if (vp8Params->nPortIndex != kOutputPortIndex) { 404 return OMX_ErrorUnsupportedIndex; 405 } 406 407 vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain; 408 vp8Params->eLevel = mLevel; 409 vp8Params->nDCTPartitions = mDCTPartitions; 410 vp8Params->bErrorResilientMode = mErrorResilience; 411 return OMX_ErrorNone; 412 } 413 414 case OMX_IndexParamVideoProfileLevelQuerySupported: { 415 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel = 416 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param; 417 418 if (profileAndLevel->nPortIndex != kOutputPortIndex) { 419 return OMX_ErrorUnsupportedIndex; 420 } 421 422 switch (profileAndLevel->nProfileIndex) { 423 case 0: 424 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version0; 425 break; 426 427 case 1: 428 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version1; 429 break; 430 431 case 2: 432 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version2; 433 break; 434 435 case 3: 436 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version3; 437 break; 438 439 default: 440 return OMX_ErrorNoMore; 441 } 442 443 profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain; 444 return OMX_ErrorNone; 445 } 446 447 case OMX_IndexParamVideoProfileLevelCurrent: { 448 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel = 449 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param; 450 451 if (profileAndLevel->nPortIndex != kOutputPortIndex) { 452 return OMX_ErrorUnsupportedIndex; 453 } 454 455 profileAndLevel->eLevel = mLevel; 456 profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain; 457 return OMX_ErrorNone; 458 } 459 460 default: 461 return SimpleSoftOMXComponent::internalGetParameter(index, param); 462 } 463 } 464 465 466 OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index, 467 const OMX_PTR param) { 468 // can include extension index OMX_INDEXEXTTYPE 469 const int32_t indexFull = index; 470 471 switch (indexFull) { 472 case OMX_IndexParamStandardComponentRole: 473 return internalSetRoleParams( 474 (const OMX_PARAM_COMPONENTROLETYPE *)param); 475 476 case OMX_IndexParamVideoBitrate: 477 return internalSetBitrateParams( 478 (const OMX_VIDEO_PARAM_BITRATETYPE *)param); 479 480 case OMX_IndexParamPortDefinition: 481 { 482 OMX_ERRORTYPE err = internalSetPortParams( 483 (const OMX_PARAM_PORTDEFINITIONTYPE *)param); 484 485 if (err != OMX_ErrorNone) { 486 return err; 487 } 488 489 return SimpleSoftOMXComponent::internalSetParameter(index, param); 490 } 491 492 case OMX_IndexParamVideoPortFormat: 493 return internalSetFormatParams( 494 (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param); 495 496 case OMX_IndexParamVideoVp8: 497 return internalSetVp8Params( 498 (const OMX_VIDEO_PARAM_VP8TYPE *)param); 499 500 case OMX_IndexParamVideoProfileLevelCurrent: 501 return internalSetProfileLevel( 502 (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param); 503 504 case OMX_IndexVendorStartUnused: 505 { 506 // storeMetaDataInBuffers 507 const StoreMetaDataInBuffersParams *storeParam = 508 (const StoreMetaDataInBuffersParams *)param; 509 510 if (storeParam->nPortIndex != kInputPortIndex) { 511 return OMX_ErrorBadPortIndex; 512 } 513 514 mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE); 515 516 return OMX_ErrorNone; 517 } 518 519 default: 520 return SimpleSoftOMXComponent::internalSetParameter(index, param); 521 } 522 } 523 524 OMX_ERRORTYPE SoftVPXEncoder::setConfig( 525 OMX_INDEXTYPE index, const OMX_PTR _params) { 526 switch (index) { 527 case OMX_IndexConfigVideoIntraVOPRefresh: 528 { 529 OMX_CONFIG_INTRAREFRESHVOPTYPE *params = 530 (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params; 531 532 if (params->nPortIndex != kOutputPortIndex) { 533 return OMX_ErrorBadPortIndex; 534 } 535 536 mKeyFrameRequested = params->IntraRefreshVOP; 537 return OMX_ErrorNone; 538 } 539 540 case OMX_IndexConfigVideoBitrate: 541 { 542 OMX_VIDEO_CONFIG_BITRATETYPE *params = 543 (OMX_VIDEO_CONFIG_BITRATETYPE *)_params; 544 545 if (params->nPortIndex != kOutputPortIndex) { 546 return OMX_ErrorBadPortIndex; 547 } 548 549 if (mBitrate != params->nEncodeBitrate) { 550 mBitrate = params->nEncodeBitrate; 551 mBitrateUpdated = true; 552 } 553 return OMX_ErrorNone; 554 } 555 556 default: 557 return SimpleSoftOMXComponent::setConfig(index, _params); 558 } 559 } 560 561 OMX_ERRORTYPE SoftVPXEncoder::internalSetProfileLevel( 562 const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel) { 563 if (profileAndLevel->nPortIndex != kOutputPortIndex) { 564 return OMX_ErrorUnsupportedIndex; 565 } 566 567 if (profileAndLevel->eProfile != OMX_VIDEO_VP8ProfileMain) { 568 return OMX_ErrorBadParameter; 569 } 570 571 if (profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version0 || 572 profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version1 || 573 profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version2 || 574 profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version3) { 575 mLevel = (OMX_VIDEO_VP8LEVELTYPE)profileAndLevel->eLevel; 576 } else { 577 return OMX_ErrorBadParameter; 578 } 579 580 return OMX_ErrorNone; 581 } 582 583 584 OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params( 585 const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) { 586 if (vp8Params->nPortIndex != kOutputPortIndex) { 587 return OMX_ErrorUnsupportedIndex; 588 } 589 590 if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) { 591 return OMX_ErrorBadParameter; 592 } 593 594 if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 || 595 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 || 596 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 || 597 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) { 598 mLevel = vp8Params->eLevel; 599 } else { 600 return OMX_ErrorBadParameter; 601 } 602 603 if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) { 604 mDCTPartitions = vp8Params->nDCTPartitions; 605 } else { 606 return OMX_ErrorBadParameter; 607 } 608 609 mErrorResilience = vp8Params->bErrorResilientMode; 610 return OMX_ErrorNone; 611 } 612 613 614 OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams( 615 const OMX_VIDEO_PARAM_PORTFORMATTYPE* format) { 616 if (format->nPortIndex == kInputPortIndex) { 617 if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar || 618 format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || 619 format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) { 620 mColorFormat = format->eColorFormat; 621 622 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; 623 def->format.video.eColorFormat = mColorFormat; 624 625 return OMX_ErrorNone; 626 } else { 627 ALOGE("Unsupported color format %i", format->eColorFormat); 628 return OMX_ErrorUnsupportedSetting; 629 } 630 } else if (format->nPortIndex == kOutputPortIndex) { 631 if (format->eCompressionFormat == OMX_VIDEO_CodingVP8) { 632 return OMX_ErrorNone; 633 } else { 634 return OMX_ErrorUnsupportedSetting; 635 } 636 } else { 637 return OMX_ErrorBadPortIndex; 638 } 639 } 640 641 642 OMX_ERRORTYPE SoftVPXEncoder::internalSetRoleParams( 643 const OMX_PARAM_COMPONENTROLETYPE* role) { 644 const char* roleText = (const char*)role->cRole; 645 const size_t roleTextMaxSize = OMX_MAX_STRINGNAME_SIZE - 1; 646 647 if (strncmp(roleText, "video_encoder.vp8", roleTextMaxSize)) { 648 ALOGE("Unsupported component role"); 649 return OMX_ErrorBadParameter; 650 } 651 652 return OMX_ErrorNone; 653 } 654 655 656 OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams( 657 const OMX_PARAM_PORTDEFINITIONTYPE* port) { 658 if (port->nPortIndex == kInputPortIndex) { 659 mWidth = port->format.video.nFrameWidth; 660 mHeight = port->format.video.nFrameHeight; 661 662 // xFramerate comes in Q16 format, in frames per second unit 663 const uint32_t framerate = port->format.video.xFramerate >> 16; 664 // frame duration is in microseconds 665 mFrameDurationUs = (1000000/framerate); 666 667 if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar || 668 port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || 669 port->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) { 670 mColorFormat = port->format.video.eColorFormat; 671 } else { 672 return OMX_ErrorUnsupportedSetting; 673 } 674 675 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef; 676 def->format.video.nFrameWidth = mWidth; 677 def->format.video.nFrameHeight = mHeight; 678 def->format.video.xFramerate = port->format.video.xFramerate; 679 def->format.video.eColorFormat = mColorFormat; 680 681 return OMX_ErrorNone; 682 } else if (port->nPortIndex == kOutputPortIndex) { 683 mBitrate = port->format.video.nBitrate; 684 return OMX_ErrorNone; 685 } else { 686 return OMX_ErrorBadPortIndex; 687 } 688 } 689 690 691 OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams( 692 const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) { 693 if (bitrate->nPortIndex != kOutputPortIndex) { 694 return OMX_ErrorUnsupportedIndex; 695 } 696 697 mBitrate = bitrate->nTargetBitrate; 698 699 if (bitrate->eControlRate == OMX_Video_ControlRateVariable) { 700 mBitrateControlMode = VPX_VBR; 701 } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) { 702 mBitrateControlMode = VPX_CBR; 703 } else { 704 return OMX_ErrorUnsupportedSetting; 705 } 706 707 return OMX_ErrorNone; 708 } 709 710 711 void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { 712 // Initialize encoder if not already 713 if (mCodecContext == NULL) { 714 if (OK != initEncoder()) { 715 ALOGE("Failed to initialize encoder"); 716 notify(OMX_EventError, 717 OMX_ErrorUndefined, 718 0, // Extra notification data 719 NULL); // Notification data pointer 720 return; 721 } 722 } 723 724 vpx_codec_err_t codec_return; 725 List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex); 726 List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex); 727 728 while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) { 729 BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin(); 730 OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader; 731 732 BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin(); 733 OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader; 734 735 if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) { 736 inputBufferInfoQueue.erase(inputBufferInfoQueue.begin()); 737 inputBufferInfo->mOwnedByUs = false; 738 notifyEmptyBufferDone(inputBufferHeader); 739 740 outputBufferHeader->nFilledLen = 0; 741 outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS; 742 743 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin()); 744 outputBufferInfo->mOwnedByUs = false; 745 notifyFillBufferDone(outputBufferHeader); 746 return; 747 } 748 749 uint8_t *source = 750 inputBufferHeader->pBuffer + inputBufferHeader->nOffset; 751 752 if (mInputDataIsMeta) { 753 CHECK_GE(inputBufferHeader->nFilledLen, 754 4 + sizeof(buffer_handle_t)); 755 756 uint32_t bufferType = *(uint32_t *)source; 757 CHECK_EQ(bufferType, kMetadataBufferTypeGrallocSource); 758 759 if (mGrallocModule == NULL) { 760 CHECK_EQ(0, hw_get_module( 761 GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule)); 762 } 763 764 const gralloc_module_t *grmodule = 765 (const gralloc_module_t *)mGrallocModule; 766 767 buffer_handle_t handle = *(buffer_handle_t *)(source + 4); 768 769 void *bits; 770 CHECK_EQ(0, 771 grmodule->lock( 772 grmodule, handle, 773 GRALLOC_USAGE_SW_READ_OFTEN 774 | GRALLOC_USAGE_SW_WRITE_NEVER, 775 0, 0, mWidth, mHeight, &bits)); 776 777 ConvertRGB32ToPlanar( 778 (const uint8_t *)bits, mConversionBuffer, mWidth, mHeight); 779 780 source = mConversionBuffer; 781 782 CHECK_EQ(0, grmodule->unlock(grmodule, handle)); 783 } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { 784 ConvertSemiPlanarToPlanar( 785 source, mConversionBuffer, mWidth, mHeight); 786 787 source = mConversionBuffer; 788 } 789 vpx_image_t raw_frame; 790 vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight, 791 kInputBufferAlignment, source); 792 793 vpx_enc_frame_flags_t flags = 0; 794 if (mKeyFrameRequested) { 795 flags |= VPX_EFLAG_FORCE_KF; 796 mKeyFrameRequested = false; 797 } 798 799 if (mBitrateUpdated) { 800 mCodecConfiguration->rc_target_bitrate = mBitrate/1000; 801 vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext, 802 mCodecConfiguration); 803 if (res != VPX_CODEC_OK) { 804 ALOGE("vp8 encoder failed to update bitrate: %s", 805 vpx_codec_err_to_string(res)); 806 notify(OMX_EventError, 807 OMX_ErrorUndefined, 808 0, // Extra notification data 809 NULL); // Notification data pointer 810 } 811 mBitrateUpdated = false; 812 } 813 814 codec_return = vpx_codec_encode( 815 mCodecContext, 816 &raw_frame, 817 inputBufferHeader->nTimeStamp, // in timebase units 818 mFrameDurationUs, // frame duration in timebase units 819 flags, // frame flags 820 VPX_DL_REALTIME); // encoding deadline 821 if (codec_return != VPX_CODEC_OK) { 822 ALOGE("vpx encoder failed to encode frame"); 823 notify(OMX_EventError, 824 OMX_ErrorUndefined, 825 0, // Extra notification data 826 NULL); // Notification data pointer 827 return; 828 } 829 830 vpx_codec_iter_t encoded_packet_iterator = NULL; 831 const vpx_codec_cx_pkt_t* encoded_packet; 832 833 while ((encoded_packet = vpx_codec_get_cx_data( 834 mCodecContext, &encoded_packet_iterator))) { 835 if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) { 836 outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts; 837 outputBufferHeader->nFlags = 0; 838 if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY) 839 outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; 840 outputBufferHeader->nOffset = 0; 841 outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz; 842 memcpy(outputBufferHeader->pBuffer, 843 encoded_packet->data.frame.buf, 844 encoded_packet->data.frame.sz); 845 outputBufferInfo->mOwnedByUs = false; 846 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin()); 847 notifyFillBufferDone(outputBufferHeader); 848 } 849 } 850 851 inputBufferInfo->mOwnedByUs = false; 852 inputBufferInfoQueue.erase(inputBufferInfoQueue.begin()); 853 notifyEmptyBufferDone(inputBufferHeader); 854 } 855 } 856 857 OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex( 858 const char *name, OMX_INDEXTYPE *index) { 859 if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) { 860 *index = OMX_IndexVendorStartUnused; 861 return OMX_ErrorNone; 862 } 863 864 return SimpleSoftOMXComponent::getExtensionIndex(name, index); 865 } 866 867 } // namespace android 868 869 870 android::SoftOMXComponent *createSoftOMXComponent( 871 const char *name, const OMX_CALLBACKTYPE *callbacks, 872 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 873 return new android::SoftVPXEncoder(name, callbacks, appData, component); 874 } 875