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