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