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