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