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