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