SoftVPXEncoder.cpp revision 6c6bb9873f55853fe74d8f45ad3ae116636d8be7
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/stagefright/foundation/ADebug.h> 24#include <media/stagefright/MediaDefs.h> 25 26namespace android { 27 28 29template<class T> 30static void InitOMXParams(T *params) { 31 params->nSize = sizeof(T); 32 // OMX IL 1.1.2 33 params->nVersion.s.nVersionMajor = 1; 34 params->nVersion.s.nVersionMinor = 1; 35 params->nVersion.s.nRevision = 2; 36 params->nVersion.s.nStep = 0; 37} 38 39 40static int GetCPUCoreCount() { 41 int cpuCoreCount = 1; 42#if defined(_SC_NPROCESSORS_ONLN) 43 cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN); 44#else 45 // _SC_NPROC_ONLN must be defined... 46 cpuCoreCount = sysconf(_SC_NPROC_ONLN); 47#endif 48 CHECK_GE(cpuCoreCount, 1); 49 return cpuCoreCount; 50} 51 52 53// This color conversion utility is copied from SoftMPEG4Encoder.cpp 54inline static void ConvertSemiPlanarToPlanar(uint8_t *inyuv, 55 uint8_t* outyuv, 56 int32_t width, 57 int32_t height) { 58 int32_t outYsize = width * height; 59 uint32_t *outy = (uint32_t *) outyuv; 60 uint16_t *outcb = (uint16_t *) (outyuv + outYsize); 61 uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2)); 62 63 /* Y copying */ 64 memcpy(outy, inyuv, outYsize); 65 66 /* U & V copying */ 67 uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize); 68 for (int32_t i = height >> 1; i > 0; --i) { 69 for (int32_t j = width >> 2; j > 0; --j) { 70 uint32_t temp = *inyuv_4++; 71 uint32_t tempU = temp & 0xFF; 72 tempU = tempU | ((temp >> 8) & 0xFF00); 73 74 uint32_t tempV = (temp >> 8) & 0xFF; 75 tempV = tempV | ((temp >> 16) & 0xFF00); 76 77 // Flip U and V 78 *outcb++ = tempV; 79 *outcr++ = tempU; 80 } 81 } 82} 83 84 85SoftVPXEncoder::SoftVPXEncoder(const char *name, 86 const OMX_CALLBACKTYPE *callbacks, 87 OMX_PTR appData, 88 OMX_COMPONENTTYPE **component) 89 : SimpleSoftOMXComponent(name, callbacks, appData, component), 90 mCodecContext(NULL), 91 mCodecConfiguration(NULL), 92 mCodecInterface(NULL), 93 mWidth(176), 94 mHeight(144), 95 mBitrate(192000), // in bps 96 mBitrateControlMode(VPX_VBR), // variable bitrate 97 mFrameDurationUs(33333), // Defaults to 30 fps 98 mDCTPartitions(0), 99 mErrorResilience(OMX_FALSE), 100 mColorFormat(OMX_COLOR_FormatYUV420Planar), 101 mLevel(OMX_VIDEO_VP8Level_Version0), 102 mConversionBuffer(NULL) { 103 104 initPorts(); 105} 106 107 108SoftVPXEncoder::~SoftVPXEncoder() { 109 releaseEncoder(); 110} 111 112 113void SoftVPXEncoder::initPorts() { 114 OMX_PARAM_PORTDEFINITIONTYPE inputPort; 115 OMX_PARAM_PORTDEFINITIONTYPE outputPort; 116 117 InitOMXParams(&inputPort); 118 InitOMXParams(&outputPort); 119 120 inputPort.nBufferCountMin = kNumBuffers; 121 inputPort.nBufferCountActual = inputPort.nBufferCountMin; 122 inputPort.bEnabled = OMX_TRUE; 123 inputPort.bPopulated = OMX_FALSE; 124 inputPort.eDomain = OMX_PortDomainVideo; 125 inputPort.bBuffersContiguous = OMX_FALSE; 126 inputPort.format.video.pNativeRender = NULL; 127 inputPort.format.video.nFrameWidth = mWidth; 128 inputPort.format.video.nFrameHeight = mHeight; 129 inputPort.format.video.nStride = inputPort.format.video.nFrameWidth; 130 inputPort.format.video.nSliceHeight = inputPort.format.video.nFrameHeight; 131 inputPort.format.video.nBitrate = 0; 132 // frameRate is reciprocal of frameDuration, which is 133 // in microseconds. It is also in Q16 format. 134 inputPort.format.video.xFramerate = (1000000/mFrameDurationUs) << 16; 135 inputPort.format.video.bFlagErrorConcealment = OMX_FALSE; 136 inputPort.nPortIndex = kInputPortIndex; 137 inputPort.eDir = OMX_DirInput; 138 inputPort.nBufferAlignment = kInputBufferAlignment; 139 inputPort.format.video.cMIMEType = 140 const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW); 141 inputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; 142 inputPort.format.video.eColorFormat = mColorFormat; 143 inputPort.format.video.pNativeWindow = NULL; 144 inputPort.nBufferSize = 145 (inputPort.format.video.nStride * 146 inputPort.format.video.nSliceHeight * 3) / 2; 147 148 addPort(inputPort); 149 150 outputPort.nBufferCountMin = kNumBuffers; 151 outputPort.nBufferCountActual = outputPort.nBufferCountMin; 152 outputPort.bEnabled = OMX_TRUE; 153 outputPort.bPopulated = OMX_FALSE; 154 outputPort.eDomain = OMX_PortDomainVideo; 155 outputPort.bBuffersContiguous = OMX_FALSE; 156 outputPort.format.video.pNativeRender = NULL; 157 outputPort.format.video.nFrameWidth = mWidth; 158 outputPort.format.video.nFrameHeight = mHeight; 159 outputPort.format.video.nStride = outputPort.format.video.nFrameWidth; 160 outputPort.format.video.nSliceHeight = outputPort.format.video.nFrameHeight; 161 outputPort.format.video.nBitrate = mBitrate; 162 outputPort.format.video.xFramerate = 0; 163 outputPort.format.video.bFlagErrorConcealment = OMX_FALSE; 164 outputPort.nPortIndex = kOutputPortIndex; 165 outputPort.eDir = OMX_DirOutput; 166 outputPort.nBufferAlignment = kOutputBufferAlignment; 167 outputPort.format.video.cMIMEType = 168 const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VPX); 169 outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVPX; 170 outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused; 171 outputPort.format.video.pNativeWindow = NULL; 172 outputPort.nBufferSize = 256 * 1024; // arbitrary 173 174 addPort(outputPort); 175} 176 177 178status_t SoftVPXEncoder::initEncoder() { 179 vpx_codec_err_t codec_return; 180 181 mCodecContext = new vpx_codec_ctx_t; 182 mCodecConfiguration = new vpx_codec_enc_cfg_t; 183 mCodecInterface = vpx_codec_vp8_cx(); 184 185 if (mCodecInterface == NULL) { 186 return UNKNOWN_ERROR; 187 } 188 189 codec_return = vpx_codec_enc_config_default(mCodecInterface, 190 mCodecConfiguration, 191 0); // Codec specific flags 192 193 if (codec_return != VPX_CODEC_OK) { 194 ALOGE("Error populating default configuration for vpx encoder."); 195 return UNKNOWN_ERROR; 196 } 197 198 mCodecConfiguration->g_w = mWidth; 199 mCodecConfiguration->g_h = mHeight; 200 mCodecConfiguration->g_threads = GetCPUCoreCount(); 201 mCodecConfiguration->g_error_resilient = mErrorResilience; 202 203 switch (mLevel) { 204 case OMX_VIDEO_VP8Level_Version0: 205 mCodecConfiguration->g_profile = 0; 206 break; 207 208 case OMX_VIDEO_VP8Level_Version1: 209 mCodecConfiguration->g_profile = 1; 210 break; 211 212 case OMX_VIDEO_VP8Level_Version2: 213 mCodecConfiguration->g_profile = 2; 214 break; 215 216 case OMX_VIDEO_VP8Level_Version3: 217 mCodecConfiguration->g_profile = 3; 218 break; 219 220 default: 221 mCodecConfiguration->g_profile = 0; 222 } 223 224 // OMX timebase unit is microsecond 225 // g_timebase is in seconds (i.e. 1/1000000 seconds) 226 mCodecConfiguration->g_timebase.num = 1; 227 mCodecConfiguration->g_timebase.den = 1000000; 228 // rc_target_bitrate is in kbps, mBitrate in bps 229 mCodecConfiguration->rc_target_bitrate = mBitrate/1000; 230 mCodecConfiguration->rc_end_usage = mBitrateControlMode; 231 232 codec_return = vpx_codec_enc_init(mCodecContext, 233 mCodecInterface, 234 mCodecConfiguration, 235 0); // flags 236 237 if (codec_return != VPX_CODEC_OK) { 238 ALOGE("Error initializing vpx encoder"); 239 return UNKNOWN_ERROR; 240 } 241 242 codec_return = vpx_codec_control(mCodecContext, 243 VP8E_SET_TOKEN_PARTITIONS, 244 mDCTPartitions); 245 if (codec_return != VPX_CODEC_OK) { 246 ALOGE("Error setting dct partitions for vpx encoder."); 247 return UNKNOWN_ERROR; 248 } 249 250 if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { 251 if (mConversionBuffer == NULL) { 252 mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2); 253 if (mConversionBuffer == NULL) { 254 ALOGE("Allocating conversion buffer failed."); 255 return UNKNOWN_ERROR; 256 } 257 } 258 } 259 return OK; 260} 261 262 263status_t SoftVPXEncoder::releaseEncoder() { 264 if (mCodecContext != NULL) { 265 vpx_codec_destroy(mCodecContext); 266 delete mCodecContext; 267 mCodecContext = NULL; 268 } 269 270 if (mCodecConfiguration != NULL) { 271 delete mCodecConfiguration; 272 mCodecConfiguration = NULL; 273 } 274 275 if (mConversionBuffer != NULL) { 276 delete mConversionBuffer; 277 mConversionBuffer = NULL; 278 } 279 280 // this one is not allocated by us 281 mCodecInterface = NULL; 282 283 return OK; 284} 285 286 287OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index, 288 OMX_PTR param) { 289 // can include extension index OMX_INDEXEXTTYPE 290 const int32_t indexFull = index; 291 292 switch (indexFull) { 293 case OMX_IndexParamVideoPortFormat: { 294 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 295 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param; 296 297 if (formatParams->nPortIndex == kInputPortIndex) { 298 if (formatParams->nIndex >= kNumberOfSupportedColorFormats) { 299 return OMX_ErrorNoMore; 300 } 301 302 // Color formats, in order of preference 303 if (formatParams->nIndex == 0) { 304 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar; 305 } else if (formatParams->nIndex == 1) { 306 formatParams->eColorFormat = 307 OMX_COLOR_FormatYUV420SemiPlanar; 308 } else { 309 formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque; 310 } 311 312 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; 313 // Converting from microseconds 314 // Also converting to Q16 format 315 formatParams->xFramerate = (1000000/mFrameDurationUs) << 16; 316 return OMX_ErrorNone; 317 } else if (formatParams->nPortIndex == kOutputPortIndex) { 318 formatParams->eCompressionFormat = OMX_VIDEO_CodingVPX; 319 formatParams->eColorFormat = OMX_COLOR_FormatUnused; 320 formatParams->xFramerate = 0; 321 return OMX_ErrorNone; 322 } else { 323 return OMX_ErrorBadPortIndex; 324 } 325 } 326 327 case OMX_IndexParamVideoBitrate: { 328 OMX_VIDEO_PARAM_BITRATETYPE *bitrate = 329 (OMX_VIDEO_PARAM_BITRATETYPE *)param; 330 331 if (bitrate->nPortIndex != kOutputPortIndex) { 332 return OMX_ErrorUnsupportedIndex; 333 } 334 335 bitrate->nTargetBitrate = mBitrate; 336 337 if (mBitrateControlMode == VPX_VBR) { 338 bitrate->eControlRate = OMX_Video_ControlRateVariable; 339 } else if (mBitrateControlMode == VPX_CBR) { 340 bitrate->eControlRate = OMX_Video_ControlRateConstant; 341 } else { 342 return OMX_ErrorUnsupportedSetting; 343 } 344 return OMX_ErrorNone; 345 } 346 347 // VP8 specific parameters that use extension headers 348 case OMX_IndexParamVideoVp8: { 349 OMX_VIDEO_PARAM_VP8TYPE *vp8Params = 350 (OMX_VIDEO_PARAM_VP8TYPE *)param; 351 352 if (vp8Params->nPortIndex != kOutputPortIndex) { 353 return OMX_ErrorUnsupportedIndex; 354 } 355 356 vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain; 357 vp8Params->eLevel = mLevel; 358 vp8Params->nDCTPartitions = mDCTPartitions; 359 vp8Params->bErrorResilientMode = mErrorResilience; 360 return OMX_ErrorNone; 361 } 362 363 case OMX_IndexParamVideoProfileLevelQuerySupported: { 364 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel = 365 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param; 366 367 if (profileAndLevel->nPortIndex != kOutputPortIndex) { 368 return OMX_ErrorUnsupportedIndex; 369 } 370 371 switch (profileAndLevel->nProfileIndex) { 372 case 0: 373 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version0; 374 break; 375 376 case 1: 377 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version1; 378 break; 379 380 case 2: 381 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version2; 382 break; 383 384 case 3: 385 profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version3; 386 break; 387 388 default: 389 return OMX_ErrorNoMore; 390 } 391 392 profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain; 393 return OMX_ErrorNone; 394 } 395 396 case OMX_IndexParamVideoProfileLevelCurrent: { 397 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel = 398 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param; 399 400 if (profileAndLevel->nPortIndex != kOutputPortIndex) { 401 return OMX_ErrorUnsupportedIndex; 402 } 403 404 profileAndLevel->eLevel = mLevel; 405 profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain; 406 return OMX_ErrorNone; 407 } 408 409 default: 410 return SimpleSoftOMXComponent::internalGetParameter(index, param); 411 } 412} 413 414 415OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index, 416 const OMX_PTR param) { 417 // can include extension index OMX_INDEXEXTTYPE 418 const int32_t indexFull = index; 419 420 switch (indexFull) { 421 case OMX_IndexParamStandardComponentRole: 422 return internalSetRoleParams( 423 (const OMX_PARAM_COMPONENTROLETYPE *)param); 424 425 case OMX_IndexParamVideoBitrate: 426 return internalSetBitrateParams( 427 (const OMX_VIDEO_PARAM_BITRATETYPE *)param); 428 429 case OMX_IndexParamPortDefinition: 430 return internalSetPortParams( 431 (const OMX_PARAM_PORTDEFINITIONTYPE *)param); 432 433 case OMX_IndexParamVideoPortFormat: 434 return internalSetFormatParams( 435 (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param); 436 437 case OMX_IndexParamVideoVp8: 438 return internalSetVp8Params( 439 (const OMX_VIDEO_PARAM_VP8TYPE *)param); 440 441 case OMX_IndexParamVideoProfileLevelCurrent: 442 return internalSetProfileLevel( 443 (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param); 444 445 default: 446 return SimpleSoftOMXComponent::internalSetParameter(index, param); 447 } 448} 449 450OMX_ERRORTYPE SoftVPXEncoder::internalSetProfileLevel( 451 const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel) { 452 if (profileAndLevel->nPortIndex != kOutputPortIndex) { 453 return OMX_ErrorUnsupportedIndex; 454 } 455 456 if (profileAndLevel->eProfile != OMX_VIDEO_VP8ProfileMain) { 457 return OMX_ErrorBadParameter; 458 } 459 460 if (profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version0 || 461 profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version1 || 462 profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version2 || 463 profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version3) { 464 mLevel = (OMX_VIDEO_VP8LEVELTYPE)profileAndLevel->eLevel; 465 } else { 466 return OMX_ErrorBadParameter; 467 } 468 469 return OMX_ErrorNone; 470} 471 472 473OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params( 474 const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) { 475 if (vp8Params->nPortIndex != kOutputPortIndex) { 476 return OMX_ErrorUnsupportedIndex; 477 } 478 479 if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) { 480 return OMX_ErrorBadParameter; 481 } 482 483 if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 || 484 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 || 485 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 || 486 vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) { 487 mLevel = vp8Params->eLevel; 488 } else { 489 return OMX_ErrorBadParameter; 490 } 491 492 if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) { 493 mDCTPartitions = vp8Params->nDCTPartitions; 494 } else { 495 return OMX_ErrorBadParameter; 496 } 497 498 mErrorResilience = vp8Params->bErrorResilientMode; 499 return OMX_ErrorNone; 500} 501 502 503OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams( 504 const OMX_VIDEO_PARAM_PORTFORMATTYPE* format) { 505 if (format->nPortIndex == kInputPortIndex) { 506 if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar || 507 format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || 508 format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) { 509 mColorFormat = format->eColorFormat; 510 return OMX_ErrorNone; 511 } else { 512 ALOGE("Unsupported color format %i", format->eColorFormat); 513 return OMX_ErrorUnsupportedSetting; 514 } 515 } else if (format->nPortIndex == kOutputPortIndex) { 516 if (format->eCompressionFormat == OMX_VIDEO_CodingVPX) { 517 return OMX_ErrorNone; 518 } else { 519 return OMX_ErrorUnsupportedSetting; 520 } 521 } else { 522 return OMX_ErrorBadPortIndex; 523 } 524} 525 526 527OMX_ERRORTYPE SoftVPXEncoder::internalSetRoleParams( 528 const OMX_PARAM_COMPONENTROLETYPE* role) { 529 const char* roleText = (const char*)role->cRole; 530 const size_t roleTextMaxSize = OMX_MAX_STRINGNAME_SIZE - 1; 531 532 if (strncmp(roleText, "video_encoder.vpx", roleTextMaxSize)) { 533 ALOGE("Unsupported component role"); 534 return OMX_ErrorBadParameter; 535 } 536 537 return OMX_ErrorNone; 538} 539 540 541OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams( 542 const OMX_PARAM_PORTDEFINITIONTYPE* port) { 543 if (port->nPortIndex == kInputPortIndex) { 544 mWidth = port->format.video.nFrameWidth; 545 mHeight = port->format.video.nFrameHeight; 546 547 // xFramerate comes in Q16 format, in frames per second unit 548 const uint32_t framerate = port->format.video.xFramerate >> 16; 549 // frame duration is in microseconds 550 mFrameDurationUs = (1000000/framerate); 551 552 if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar || 553 port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || 554 port->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) { 555 mColorFormat = port->format.video.eColorFormat; 556 } else { 557 return OMX_ErrorUnsupportedSetting; 558 } 559 560 return OMX_ErrorNone; 561 } else if (port->nPortIndex == kOutputPortIndex) { 562 mBitrate = port->format.video.nBitrate; 563 return OMX_ErrorNone; 564 } else { 565 return OMX_ErrorBadPortIndex; 566 } 567} 568 569 570OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams( 571 const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) { 572 if (bitrate->nPortIndex != kOutputPortIndex) { 573 return OMX_ErrorUnsupportedIndex; 574 } 575 576 mBitrate = bitrate->nTargetBitrate; 577 578 if (bitrate->eControlRate == OMX_Video_ControlRateVariable) { 579 mBitrateControlMode = VPX_VBR; 580 } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) { 581 mBitrateControlMode = VPX_CBR; 582 } else { 583 return OMX_ErrorUnsupportedSetting; 584 } 585 586 return OMX_ErrorNone; 587} 588 589 590void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) { 591 // Initialize encoder if not already 592 if (mCodecContext == NULL) { 593 if (OK != initEncoder()) { 594 ALOGE("Failed to initialize encoder"); 595 notify(OMX_EventError, 596 OMX_ErrorUndefined, 597 0, // Extra notification data 598 NULL); // Notification data pointer 599 return; 600 } 601 } 602 603 vpx_codec_err_t codec_return; 604 List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex); 605 List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex); 606 607 while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) { 608 BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin(); 609 OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader; 610 611 BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin(); 612 OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader; 613 614 if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) { 615 inputBufferInfoQueue.erase(inputBufferInfoQueue.begin()); 616 inputBufferInfo->mOwnedByUs = false; 617 notifyEmptyBufferDone(inputBufferHeader); 618 619 outputBufferHeader->nFilledLen = 0; 620 outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS; 621 622 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin()); 623 outputBufferInfo->mOwnedByUs = false; 624 notifyFillBufferDone(outputBufferHeader); 625 return; 626 } 627 628 uint8_t* source = inputBufferHeader->pBuffer + inputBufferHeader->nOffset; 629 630 // NOTE: As much as nothing is known about color format 631 // when it is denoted as AndroidOpaque, it is at least 632 // assumed to be planar. 633 if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { 634 ConvertSemiPlanarToPlanar(source, mConversionBuffer, mWidth, mHeight); 635 source = mConversionBuffer; 636 } 637 vpx_image_t raw_frame; 638 vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight, 639 kInputBufferAlignment, source); 640 codec_return = vpx_codec_encode(mCodecContext, 641 &raw_frame, 642 inputBufferHeader->nTimeStamp, // in timebase units 643 mFrameDurationUs, // frame duration in timebase units 644 0, // frame flags 645 VPX_DL_REALTIME); // encoding deadline 646 if (codec_return != VPX_CODEC_OK) { 647 ALOGE("vpx encoder failed to encode frame"); 648 notify(OMX_EventError, 649 OMX_ErrorUndefined, 650 0, // Extra notification data 651 NULL); // Notification data pointer 652 return; 653 } 654 655 vpx_codec_iter_t encoded_packet_iterator = NULL; 656 const vpx_codec_cx_pkt_t* encoded_packet; 657 658 while (encoded_packet = vpx_codec_get_cx_data(mCodecContext, &encoded_packet_iterator)) { 659 if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) { 660 outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts; 661 outputBufferHeader->nFlags = 0; 662 outputBufferHeader->nOffset = 0; 663 outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz; 664 memcpy(outputBufferHeader->pBuffer, 665 encoded_packet->data.frame.buf, 666 encoded_packet->data.frame.sz); 667 outputBufferInfo->mOwnedByUs = false; 668 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin()); 669 notifyFillBufferDone(outputBufferHeader); 670 } 671 } 672 673 inputBufferInfo->mOwnedByUs = false; 674 inputBufferInfoQueue.erase(inputBufferInfoQueue.begin()); 675 notifyEmptyBufferDone(inputBufferHeader); 676 } 677} 678} // namespace android 679 680 681android::SoftOMXComponent *createSoftOMXComponent( 682 const char *name, const OMX_CALLBACKTYPE *callbacks, 683 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 684 return new android::SoftVPXEncoder(name, callbacks, appData, component); 685} 686