SoftMPEG4Encoder.cpp revision 2edda09a2ad1d112c52acd37d323f63f0a492d67
1/* 2 * Copyright (C) 2012 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 "SoftMPEG4Encoder" 19#include <utils/Log.h> 20 21#include "mp4enc_api.h" 22#include "OMX_Video.h" 23 24#include <HardwareAPI.h> 25#include <MetadataBufferType.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/MediaDefs.h> 28#include <media/stagefright/MediaErrors.h> 29#include <media/stagefright/MetaData.h> 30#include <media/stagefright/Utils.h> 31#include <ui/Rect.h> 32#include <ui/GraphicBufferMapper.h> 33 34#include "SoftMPEG4Encoder.h" 35 36#include <inttypes.h> 37 38namespace android { 39 40template<class T> 41static void InitOMXParams(T *params) { 42 params->nSize = sizeof(T); 43 params->nVersion.s.nVersionMajor = 1; 44 params->nVersion.s.nVersionMinor = 0; 45 params->nVersion.s.nRevision = 0; 46 params->nVersion.s.nStep = 0; 47} 48 49SoftMPEG4Encoder::SoftMPEG4Encoder( 50 const char *name, 51 const OMX_CALLBACKTYPE *callbacks, 52 OMX_PTR appData, 53 OMX_COMPONENTTYPE **component) 54 : SoftVideoEncoderOMXComponent(name, callbacks, appData, component), 55 mEncodeMode(COMBINE_MODE_WITH_ERR_RES), 56 mVideoWidth(176), 57 mVideoHeight(144), 58 mVideoFrameRate(30), 59 mVideoBitRate(192000), 60 mVideoColorFormat(OMX_COLOR_FormatYUV420Planar), 61 mStoreMetaDataInBuffers(false), 62 mIDRFrameRefreshIntervalInSec(1), 63 mNumInputFrames(-1), 64 mStarted(false), 65 mSawInputEOS(false), 66 mSignalledError(false), 67 mHandle(new tagvideoEncControls), 68 mEncParams(new tagvideoEncOptions), 69 mInputFrameData(NULL) { 70 71 if (!strcmp(name, "OMX.google.h263.encoder")) { 72 mEncodeMode = H263_MODE; 73 } else { 74 CHECK(!strcmp(name, "OMX.google.mpeg4.encoder")); 75 } 76 77 initPorts(); 78 ALOGI("Construct SoftMPEG4Encoder"); 79} 80 81SoftMPEG4Encoder::~SoftMPEG4Encoder() { 82 ALOGV("Destruct SoftMPEG4Encoder"); 83 releaseEncoder(); 84 List<BufferInfo *> &outQueue = getPortQueue(1); 85 List<BufferInfo *> &inQueue = getPortQueue(0); 86 CHECK(outQueue.empty()); 87 CHECK(inQueue.empty()); 88} 89 90OMX_ERRORTYPE SoftMPEG4Encoder::initEncParams() { 91 CHECK(mHandle != NULL); 92 memset(mHandle, 0, sizeof(tagvideoEncControls)); 93 94 CHECK(mEncParams != NULL); 95 memset(mEncParams, 0, sizeof(tagvideoEncOptions)); 96 if (!PVGetDefaultEncOption(mEncParams, 0)) { 97 ALOGE("Failed to get default encoding parameters"); 98 return OMX_ErrorUndefined; 99 } 100 mEncParams->encMode = mEncodeMode; 101 mEncParams->encWidth[0] = mVideoWidth; 102 mEncParams->encHeight[0] = mVideoHeight; 103 mEncParams->encFrameRate[0] = mVideoFrameRate; 104 mEncParams->rcType = VBR_1; 105 mEncParams->vbvDelay = 5.0f; 106 107 // FIXME: 108 // Add more profile and level support for MPEG4 encoder 109 mEncParams->profile_level = CORE_PROFILE_LEVEL2; 110 mEncParams->packetSize = 32; 111 mEncParams->rvlcEnable = PV_OFF; 112 mEncParams->numLayers = 1; 113 mEncParams->timeIncRes = 1000; 114 mEncParams->tickPerSrc = mEncParams->timeIncRes / mVideoFrameRate; 115 116 mEncParams->bitRate[0] = mVideoBitRate; 117 mEncParams->iQuant[0] = 15; 118 mEncParams->pQuant[0] = 12; 119 mEncParams->quantType[0] = 0; 120 mEncParams->noFrameSkipped = PV_OFF; 121 122 if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar 123 || mStoreMetaDataInBuffers) { 124 // Color conversion is needed. 125 free(mInputFrameData); 126 mInputFrameData = 127 (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1); 128 CHECK(mInputFrameData != NULL); 129 } 130 131 // PV's MPEG4 encoder requires the video dimension of multiple 132 if (mVideoWidth % 16 != 0 || mVideoHeight % 16 != 0) { 133 ALOGE("Video frame size %dx%d must be a multiple of 16", 134 mVideoWidth, mVideoHeight); 135 return OMX_ErrorBadParameter; 136 } 137 138 // Set IDR frame refresh interval 139 if (mIDRFrameRefreshIntervalInSec < 0) { 140 mEncParams->intraPeriod = -1; 141 } else if (mIDRFrameRefreshIntervalInSec == 0) { 142 mEncParams->intraPeriod = 1; // All I frames 143 } else { 144 mEncParams->intraPeriod = 145 (mIDRFrameRefreshIntervalInSec * mVideoFrameRate); 146 } 147 148 mEncParams->numIntraMB = 0; 149 mEncParams->sceneDetect = PV_ON; 150 mEncParams->searchRange = 16; 151 mEncParams->mv8x8Enable = PV_OFF; 152 mEncParams->gobHeaderInterval = 0; 153 mEncParams->useACPred = PV_ON; 154 mEncParams->intraDCVlcTh = 0; 155 156 return OMX_ErrorNone; 157} 158 159OMX_ERRORTYPE SoftMPEG4Encoder::initEncoder() { 160 CHECK(!mStarted); 161 162 OMX_ERRORTYPE errType = OMX_ErrorNone; 163 if (OMX_ErrorNone != (errType = initEncParams())) { 164 ALOGE("Failed to initialized encoder params"); 165 mSignalledError = true; 166 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 167 return errType; 168 } 169 170 if (!PVInitVideoEncoder(mHandle, mEncParams)) { 171 ALOGE("Failed to initialize the encoder"); 172 mSignalledError = true; 173 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 174 return OMX_ErrorUndefined; 175 } 176 177 mNumInputFrames = -1; // 1st buffer for codec specific data 178 mStarted = true; 179 180 return OMX_ErrorNone; 181} 182 183OMX_ERRORTYPE SoftMPEG4Encoder::releaseEncoder() { 184 if (!mStarted) { 185 return OMX_ErrorNone; 186 } 187 188 PVCleanUpVideoEncoder(mHandle); 189 190 free(mInputFrameData); 191 mInputFrameData = NULL; 192 193 delete mEncParams; 194 mEncParams = NULL; 195 196 delete mHandle; 197 mHandle = NULL; 198 199 mStarted = false; 200 201 return OMX_ErrorNone; 202} 203 204void SoftMPEG4Encoder::initPorts() { 205 OMX_PARAM_PORTDEFINITIONTYPE def; 206 InitOMXParams(&def); 207 208 const size_t kInputBufferSize = (mVideoWidth * mVideoHeight * 3) >> 1; 209 210 // 256 * 1024 is a magic number for PV's encoder, not sure why 211 const size_t kOutputBufferSize = 212 (kInputBufferSize > 256 * 1024) 213 ? kInputBufferSize: 256 * 1024; 214 215 def.nPortIndex = 0; 216 def.eDir = OMX_DirInput; 217 def.nBufferCountMin = kNumBuffers; 218 def.nBufferCountActual = def.nBufferCountMin; 219 def.nBufferSize = kInputBufferSize; 220 def.bEnabled = OMX_TRUE; 221 def.bPopulated = OMX_FALSE; 222 def.eDomain = OMX_PortDomainVideo; 223 def.bBuffersContiguous = OMX_FALSE; 224 def.nBufferAlignment = 1; 225 226 def.format.video.cMIMEType = const_cast<char *>("video/raw"); 227 228 def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; 229 def.format.video.eColorFormat = OMX_COLOR_FormatYUV420Planar; 230 def.format.video.xFramerate = (mVideoFrameRate << 16); // Q16 format 231 def.format.video.nBitrate = mVideoBitRate; 232 def.format.video.nFrameWidth = mVideoWidth; 233 def.format.video.nFrameHeight = mVideoHeight; 234 def.format.video.nStride = mVideoWidth; 235 def.format.video.nSliceHeight = mVideoHeight; 236 237 addPort(def); 238 239 def.nPortIndex = 1; 240 def.eDir = OMX_DirOutput; 241 def.nBufferCountMin = kNumBuffers; 242 def.nBufferCountActual = def.nBufferCountMin; 243 def.nBufferSize = kOutputBufferSize; 244 def.bEnabled = OMX_TRUE; 245 def.bPopulated = OMX_FALSE; 246 def.eDomain = OMX_PortDomainVideo; 247 def.bBuffersContiguous = OMX_FALSE; 248 def.nBufferAlignment = 2; 249 250 def.format.video.cMIMEType = 251 (mEncodeMode == COMBINE_MODE_WITH_ERR_RES) 252 ? const_cast<char *>(MEDIA_MIMETYPE_VIDEO_MPEG4) 253 : const_cast<char *>(MEDIA_MIMETYPE_VIDEO_H263); 254 255 def.format.video.eCompressionFormat = 256 (mEncodeMode == COMBINE_MODE_WITH_ERR_RES) 257 ? OMX_VIDEO_CodingMPEG4 258 : OMX_VIDEO_CodingH263; 259 260 def.format.video.eColorFormat = OMX_COLOR_FormatUnused; 261 def.format.video.xFramerate = (0 << 16); // Q16 format 262 def.format.video.nBitrate = mVideoBitRate; 263 def.format.video.nFrameWidth = mVideoWidth; 264 def.format.video.nFrameHeight = mVideoHeight; 265 def.format.video.nStride = mVideoWidth; 266 def.format.video.nSliceHeight = mVideoHeight; 267 268 addPort(def); 269} 270 271OMX_ERRORTYPE SoftMPEG4Encoder::internalGetParameter( 272 OMX_INDEXTYPE index, OMX_PTR params) { 273 switch (index) { 274 case OMX_IndexParamVideoErrorCorrection: 275 { 276 return OMX_ErrorNotImplemented; 277 } 278 279 case OMX_IndexParamVideoBitrate: 280 { 281 OMX_VIDEO_PARAM_BITRATETYPE *bitRate = 282 (OMX_VIDEO_PARAM_BITRATETYPE *) params; 283 284 if (bitRate->nPortIndex != 1) { 285 return OMX_ErrorUndefined; 286 } 287 288 bitRate->eControlRate = OMX_Video_ControlRateVariable; 289 bitRate->nTargetBitrate = mVideoBitRate; 290 return OMX_ErrorNone; 291 } 292 293 case OMX_IndexParamVideoPortFormat: 294 { 295 OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 296 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; 297 298 if (formatParams->nPortIndex > 1) { 299 return OMX_ErrorUndefined; 300 } 301 302 if (formatParams->nIndex > 2) { 303 return OMX_ErrorNoMore; 304 } 305 306 if (formatParams->nPortIndex == 0) { 307 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused; 308 if (formatParams->nIndex == 0) { 309 formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar; 310 } else if (formatParams->nIndex == 1) { 311 formatParams->eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; 312 } else { 313 formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque; 314 } 315 } else { 316 formatParams->eCompressionFormat = 317 (mEncodeMode == COMBINE_MODE_WITH_ERR_RES) 318 ? OMX_VIDEO_CodingMPEG4 319 : OMX_VIDEO_CodingH263; 320 321 formatParams->eColorFormat = OMX_COLOR_FormatUnused; 322 } 323 324 return OMX_ErrorNone; 325 } 326 327 case OMX_IndexParamVideoH263: 328 { 329 OMX_VIDEO_PARAM_H263TYPE *h263type = 330 (OMX_VIDEO_PARAM_H263TYPE *)params; 331 332 if (h263type->nPortIndex != 1) { 333 return OMX_ErrorUndefined; 334 } 335 336 h263type->nAllowedPictureTypes = 337 (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP); 338 h263type->eProfile = OMX_VIDEO_H263ProfileBaseline; 339 h263type->eLevel = OMX_VIDEO_H263Level45; 340 h263type->bPLUSPTYPEAllowed = OMX_FALSE; 341 h263type->bForceRoundingTypeToZero = OMX_FALSE; 342 h263type->nPictureHeaderRepetition = 0; 343 h263type->nGOBHeaderInterval = 0; 344 345 return OMX_ErrorNone; 346 } 347 348 case OMX_IndexParamVideoMpeg4: 349 { 350 OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type = 351 (OMX_VIDEO_PARAM_MPEG4TYPE *)params; 352 353 if (mpeg4type->nPortIndex != 1) { 354 return OMX_ErrorUndefined; 355 } 356 357 mpeg4type->eProfile = OMX_VIDEO_MPEG4ProfileCore; 358 mpeg4type->eLevel = OMX_VIDEO_MPEG4Level2; 359 mpeg4type->nAllowedPictureTypes = 360 (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP); 361 mpeg4type->nBFrames = 0; 362 mpeg4type->nIDCVLCThreshold = 0; 363 mpeg4type->bACPred = OMX_TRUE; 364 mpeg4type->nMaxPacketSize = 256; 365 mpeg4type->nTimeIncRes = 1000; 366 mpeg4type->nHeaderExtension = 0; 367 mpeg4type->bReversibleVLC = OMX_FALSE; 368 369 return OMX_ErrorNone; 370 } 371 372 case OMX_IndexParamVideoProfileLevelQuerySupported: 373 { 374 OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel = 375 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)params; 376 377 if (profileLevel->nPortIndex != 1) { 378 return OMX_ErrorUndefined; 379 } 380 381 if (profileLevel->nProfileIndex > 0) { 382 return OMX_ErrorNoMore; 383 } 384 385 if (mEncodeMode == H263_MODE) { 386 profileLevel->eProfile = OMX_VIDEO_H263ProfileBaseline; 387 profileLevel->eLevel = OMX_VIDEO_H263Level45; 388 } else { 389 profileLevel->eProfile = OMX_VIDEO_MPEG4ProfileCore; 390 profileLevel->eLevel = OMX_VIDEO_MPEG4Level2; 391 } 392 393 return OMX_ErrorNone; 394 } 395 396 default: 397 return SimpleSoftOMXComponent::internalGetParameter(index, params); 398 } 399} 400 401OMX_ERRORTYPE SoftMPEG4Encoder::internalSetParameter( 402 OMX_INDEXTYPE index, const OMX_PTR params) { 403 int32_t indexFull = index; 404 405 switch (indexFull) { 406 case OMX_IndexParamVideoErrorCorrection: 407 { 408 return OMX_ErrorNotImplemented; 409 } 410 411 case OMX_IndexParamVideoBitrate: 412 { 413 OMX_VIDEO_PARAM_BITRATETYPE *bitRate = 414 (OMX_VIDEO_PARAM_BITRATETYPE *) params; 415 416 if (bitRate->nPortIndex != 1 || 417 bitRate->eControlRate != OMX_Video_ControlRateVariable) { 418 return OMX_ErrorUndefined; 419 } 420 421 mVideoBitRate = bitRate->nTargetBitrate; 422 return OMX_ErrorNone; 423 } 424 425 case OMX_IndexParamPortDefinition: 426 { 427 OMX_PARAM_PORTDEFINITIONTYPE *def = 428 (OMX_PARAM_PORTDEFINITIONTYPE *)params; 429 if (def->nPortIndex > 1) { 430 return OMX_ErrorUndefined; 431 } 432 433 if (def->nPortIndex == 0) { 434 if (def->format.video.eCompressionFormat != OMX_VIDEO_CodingUnused || 435 (def->format.video.eColorFormat != OMX_COLOR_FormatYUV420Planar && 436 def->format.video.eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar && 437 def->format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque)) { 438 return OMX_ErrorUndefined; 439 } 440 } else { 441 if ((mEncodeMode == COMBINE_MODE_WITH_ERR_RES && 442 def->format.video.eCompressionFormat != OMX_VIDEO_CodingMPEG4) || 443 (mEncodeMode == H263_MODE && 444 def->format.video.eCompressionFormat != OMX_VIDEO_CodingH263) || 445 (def->format.video.eColorFormat != OMX_COLOR_FormatUnused)) { 446 return OMX_ErrorUndefined; 447 } 448 } 449 450 OMX_ERRORTYPE err = SimpleSoftOMXComponent::internalSetParameter(index, params); 451 if (OMX_ErrorNone != err) { 452 return err; 453 } 454 455 if (def->nPortIndex == 0) { 456 mVideoWidth = def->format.video.nFrameWidth; 457 mVideoHeight = def->format.video.nFrameHeight; 458 mVideoFrameRate = def->format.video.xFramerate >> 16; 459 mVideoColorFormat = def->format.video.eColorFormat; 460 461 OMX_PARAM_PORTDEFINITIONTYPE *portDef = 462 &editPortInfo(0)->mDef; 463 portDef->format.video.nFrameWidth = mVideoWidth; 464 portDef->format.video.nFrameHeight = mVideoHeight; 465 portDef->format.video.xFramerate = def->format.video.xFramerate; 466 portDef->format.video.eColorFormat = 467 (OMX_COLOR_FORMATTYPE) mVideoColorFormat; 468 portDef = &editPortInfo(1)->mDef; 469 portDef->format.video.nFrameWidth = mVideoWidth; 470 portDef->format.video.nFrameHeight = mVideoHeight; 471 } else { 472 mVideoBitRate = def->format.video.nBitrate; 473 } 474 475 return OMX_ErrorNone; 476 } 477 478 case OMX_IndexParamStandardComponentRole: 479 { 480 const OMX_PARAM_COMPONENTROLETYPE *roleParams = 481 (const OMX_PARAM_COMPONENTROLETYPE *)params; 482 483 if (strncmp((const char *)roleParams->cRole, 484 (mEncodeMode == H263_MODE) 485 ? "video_encoder.h263": "video_encoder.mpeg4", 486 OMX_MAX_STRINGNAME_SIZE - 1)) { 487 return OMX_ErrorUndefined; 488 } 489 490 return OMX_ErrorNone; 491 } 492 493 case OMX_IndexParamVideoPortFormat: 494 { 495 const OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams = 496 (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)params; 497 498 if (formatParams->nPortIndex > 1) { 499 return OMX_ErrorUndefined; 500 } 501 502 if (formatParams->nIndex > 2) { 503 return OMX_ErrorNoMore; 504 } 505 506 if (formatParams->nPortIndex == 0) { 507 if (formatParams->eCompressionFormat != OMX_VIDEO_CodingUnused || 508 ((formatParams->nIndex == 0 && 509 formatParams->eColorFormat != OMX_COLOR_FormatYUV420Planar) || 510 (formatParams->nIndex == 1 && 511 formatParams->eColorFormat != OMX_COLOR_FormatYUV420SemiPlanar) || 512 (formatParams->nIndex == 2 && 513 formatParams->eColorFormat != OMX_COLOR_FormatAndroidOpaque) )) { 514 return OMX_ErrorUndefined; 515 } 516 mVideoColorFormat = formatParams->eColorFormat; 517 } else { 518 if ((mEncodeMode == H263_MODE && 519 formatParams->eCompressionFormat != OMX_VIDEO_CodingH263) || 520 (mEncodeMode == COMBINE_MODE_WITH_ERR_RES && 521 formatParams->eCompressionFormat != OMX_VIDEO_CodingMPEG4) || 522 formatParams->eColorFormat != OMX_COLOR_FormatUnused) { 523 return OMX_ErrorUndefined; 524 } 525 } 526 527 return OMX_ErrorNone; 528 } 529 530 case OMX_IndexParamVideoH263: 531 { 532 OMX_VIDEO_PARAM_H263TYPE *h263type = 533 (OMX_VIDEO_PARAM_H263TYPE *)params; 534 535 if (h263type->nPortIndex != 1) { 536 return OMX_ErrorUndefined; 537 } 538 539 if (h263type->eProfile != OMX_VIDEO_H263ProfileBaseline || 540 h263type->eLevel != OMX_VIDEO_H263Level45 || 541 (h263type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) || 542 h263type->bPLUSPTYPEAllowed != OMX_FALSE || 543 h263type->bForceRoundingTypeToZero != OMX_FALSE || 544 h263type->nPictureHeaderRepetition != 0 || 545 h263type->nGOBHeaderInterval != 0) { 546 return OMX_ErrorUndefined; 547 } 548 549 return OMX_ErrorNone; 550 } 551 552 case OMX_IndexParamVideoMpeg4: 553 { 554 OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type = 555 (OMX_VIDEO_PARAM_MPEG4TYPE *)params; 556 557 if (mpeg4type->nPortIndex != 1) { 558 return OMX_ErrorUndefined; 559 } 560 561 if (mpeg4type->eProfile != OMX_VIDEO_MPEG4ProfileCore || 562 mpeg4type->eLevel != OMX_VIDEO_MPEG4Level2 || 563 (mpeg4type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) || 564 mpeg4type->nBFrames != 0 || 565 mpeg4type->nIDCVLCThreshold != 0 || 566 mpeg4type->bACPred != OMX_TRUE || 567 mpeg4type->nMaxPacketSize != 256 || 568 mpeg4type->nTimeIncRes != 1000 || 569 mpeg4type->nHeaderExtension != 0 || 570 mpeg4type->bReversibleVLC != OMX_FALSE) { 571 return OMX_ErrorUndefined; 572 } 573 574 return OMX_ErrorNone; 575 } 576 577 case kStoreMetaDataExtensionIndex: 578 { 579 StoreMetaDataInBuffersParams *storeParams = 580 (StoreMetaDataInBuffersParams*)params; 581 if (storeParams->nPortIndex != 0) { 582 ALOGE("%s: StoreMetadataInBuffersParams.nPortIndex not zero!", 583 __FUNCTION__); 584 return OMX_ErrorUndefined; 585 } 586 587 mStoreMetaDataInBuffers = storeParams->bStoreMetaData; 588 ALOGV("StoreMetaDataInBuffers set to: %s", 589 mStoreMetaDataInBuffers ? " true" : "false"); 590 591 if (mStoreMetaDataInBuffers) { 592 mVideoColorFormat = OMX_COLOR_FormatAndroidOpaque; 593 } 594 595 return OMX_ErrorNone; 596 } 597 598 default: 599 return SimpleSoftOMXComponent::internalSetParameter(index, params); 600 } 601} 602 603void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { 604 if (mSignalledError || mSawInputEOS) { 605 return; 606 } 607 608 if (!mStarted) { 609 if (OMX_ErrorNone != initEncoder()) { 610 return; 611 } 612 } 613 614 List<BufferInfo *> &inQueue = getPortQueue(0); 615 List<BufferInfo *> &outQueue = getPortQueue(1); 616 617 while (!mSawInputEOS && !inQueue.empty() && !outQueue.empty()) { 618 BufferInfo *inInfo = *inQueue.begin(); 619 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 620 BufferInfo *outInfo = *outQueue.begin(); 621 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 622 623 outHeader->nTimeStamp = 0; 624 outHeader->nFlags = 0; 625 outHeader->nOffset = 0; 626 outHeader->nFilledLen = 0; 627 outHeader->nOffset = 0; 628 629 uint8_t *outPtr = (uint8_t *) outHeader->pBuffer; 630 int32_t dataLength = outHeader->nAllocLen; 631 632 if (mNumInputFrames < 0) { 633 if (!PVGetVolHeader(mHandle, outPtr, &dataLength, 0)) { 634 ALOGE("Failed to get VOL header"); 635 mSignalledError = true; 636 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 637 return; 638 } 639 ALOGV("Output VOL header: %d bytes", dataLength); 640 ++mNumInputFrames; 641 outHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; 642 outHeader->nFilledLen = dataLength; 643 outQueue.erase(outQueue.begin()); 644 outInfo->mOwnedByUs = false; 645 notifyFillBufferDone(outHeader); 646 return; 647 } 648 649 // Save the input buffer info so that it can be 650 // passed to an output buffer 651 InputBufferInfo info; 652 info.mTimeUs = inHeader->nTimeStamp; 653 info.mFlags = inHeader->nFlags; 654 mInputBufferInfoVec.push(info); 655 656 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 657 mSawInputEOS = true; 658 } 659 660 if (inHeader->nFilledLen > 0) { 661 const uint8_t *inputData = NULL; 662 if (mStoreMetaDataInBuffers) { 663 if (inHeader->nFilledLen != 8) { 664 ALOGE("MetaData buffer is wrong size! " 665 "(got %u bytes, expected 8)", inHeader->nFilledLen); 666 mSignalledError = true; 667 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 668 return; 669 } 670 inputData = 671 extractGraphicBuffer( 672 mInputFrameData, (mVideoWidth * mVideoHeight * 3) >> 1, 673 inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen, 674 mVideoWidth, mVideoHeight); 675 if (inputData == NULL) { 676 ALOGE("Unable to extract gralloc buffer in metadata mode"); 677 mSignalledError = true; 678 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 679 return; 680 } 681 } else { 682 inputData = (const uint8_t *)inHeader->pBuffer + inHeader->nOffset; 683 if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) { 684 ConvertYUV420SemiPlanarToYUV420Planar( 685 inputData, mInputFrameData, mVideoWidth, mVideoHeight); 686 inputData = mInputFrameData; 687 } 688 } 689 690 CHECK(inputData != NULL); 691 692 VideoEncFrameIO vin, vout; 693 memset(&vin, 0, sizeof(vin)); 694 memset(&vout, 0, sizeof(vout)); 695 vin.height = ((mVideoHeight + 15) >> 4) << 4; 696 vin.pitch = ((mVideoWidth + 15) >> 4) << 4; 697 vin.timestamp = (inHeader->nTimeStamp + 500) / 1000; // in ms 698 vin.yChan = (uint8_t *)inputData; 699 vin.uChan = vin.yChan + vin.height * vin.pitch; 700 vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2); 701 702 ULong modTimeMs = 0; 703 int32_t nLayer = 0; 704 MP4HintTrack hintTrack; 705 if (!PVEncodeVideoFrame(mHandle, &vin, &vout, 706 &modTimeMs, outPtr, &dataLength, &nLayer) || 707 !PVGetHintTrack(mHandle, &hintTrack)) { 708 ALOGE("Failed to encode frame or get hink track at frame %" PRId64, 709 mNumInputFrames); 710 mSignalledError = true; 711 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 712 } 713 CHECK(NULL == PVGetOverrunBuffer(mHandle)); 714 if (hintTrack.CodeType == 0) { // I-frame serves as sync frame 715 outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; 716 } 717 718 ++mNumInputFrames; 719 } else { 720 dataLength = 0; 721 } 722 723 inQueue.erase(inQueue.begin()); 724 inInfo->mOwnedByUs = false; 725 notifyEmptyBufferDone(inHeader); 726 727 outQueue.erase(outQueue.begin()); 728 CHECK(!mInputBufferInfoVec.empty()); 729 InputBufferInfo *inputBufInfo = mInputBufferInfoVec.begin(); 730 outHeader->nTimeStamp = inputBufInfo->mTimeUs; 731 outHeader->nFlags |= (inputBufInfo->mFlags | OMX_BUFFERFLAG_ENDOFFRAME); 732 outHeader->nFilledLen = dataLength; 733 mInputBufferInfoVec.erase(mInputBufferInfoVec.begin()); 734 outInfo->mOwnedByUs = false; 735 notifyFillBufferDone(outHeader); 736 } 737} 738 739} // namespace android 740 741android::SoftOMXComponent *createSoftOMXComponent( 742 const char *name, const OMX_CALLBACKTYPE *callbacks, 743 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 744 return new android::SoftMPEG4Encoder(name, callbacks, appData, component); 745} 746