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