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