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#include <utils/misc.h> 21 22#include "mp4enc_api.h" 23#include "OMX_Video.h" 24 25#include <HardwareAPI.h> 26#include <MetadataBufferType.h> 27#include <media/stagefright/foundation/ADebug.h> 28#include <media/stagefright/foundation/AUtils.h> 29#include <media/stagefright/MediaDefs.h> 30#include <media/stagefright/MediaErrors.h> 31#include <media/stagefright/MetaData.h> 32#include <media/stagefright/Utils.h> 33#include <ui/Rect.h> 34#include <ui/GraphicBufferMapper.h> 35 36#include "SoftMPEG4Encoder.h" 37 38#include <inttypes.h> 39 40#ifndef INT32_MAX 41#define INT32_MAX 2147483647 42#endif 43 44namespace android { 45 46template<class T> 47static void InitOMXParams(T *params) { 48 params->nSize = sizeof(T); 49 params->nVersion.s.nVersionMajor = 1; 50 params->nVersion.s.nVersionMinor = 0; 51 params->nVersion.s.nRevision = 0; 52 params->nVersion.s.nStep = 0; 53} 54 55static const CodecProfileLevel kMPEG4ProfileLevels[] = { 56 { OMX_VIDEO_MPEG4ProfileCore, OMX_VIDEO_MPEG4Level2 }, 57}; 58 59static const CodecProfileLevel kH263ProfileLevels[] = { 60 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 }, 61}; 62 63SoftMPEG4Encoder::SoftMPEG4Encoder( 64 const char *name, 65 const char *componentRole, 66 OMX_VIDEO_CODINGTYPE codingType, 67 const char *mime, 68 const CodecProfileLevel *profileLevels, 69 size_t numProfileLevels, 70 const OMX_CALLBACKTYPE *callbacks, 71 OMX_PTR appData, 72 OMX_COMPONENTTYPE **component) 73 : SoftVideoEncoderOMXComponent( 74 name, componentRole, codingType, 75 profileLevels, numProfileLevels, 76 176 /* width */, 144 /* height */, 77 callbacks, appData, component), 78 mEncodeMode(COMBINE_MODE_WITH_ERR_RES), 79 mIDRFrameRefreshIntervalInSec(1), 80 mNumInputFrames(-1), 81 mStarted(false), 82 mSawInputEOS(false), 83 mSignalledError(false), 84 mHandle(new tagvideoEncControls), 85 mEncParams(new tagvideoEncOptions), 86 mInputFrameData(NULL) { 87 88 if (codingType == OMX_VIDEO_CodingH263) { 89 mEncodeMode = H263_MODE; 90 } 91 92 // 256 * 1024 is a magic number for PV's encoder, not sure why 93 const size_t kOutputBufferSize = 256 * 1024; 94 95 initPorts(kNumBuffers, kNumBuffers, kOutputBufferSize, mime); 96 97 ALOGI("Construct SoftMPEG4Encoder"); 98} 99 100SoftMPEG4Encoder::~SoftMPEG4Encoder() { 101 ALOGV("Destruct SoftMPEG4Encoder"); 102 releaseEncoder(); 103 List<BufferInfo *> &outQueue = getPortQueue(1); 104 List<BufferInfo *> &inQueue = getPortQueue(0); 105 CHECK(outQueue.empty()); 106 CHECK(inQueue.empty()); 107} 108 109OMX_ERRORTYPE SoftMPEG4Encoder::initEncParams() { 110 CHECK(mHandle != NULL); 111 memset(mHandle, 0, sizeof(tagvideoEncControls)); 112 113 CHECK(mEncParams != NULL); 114 memset(mEncParams, 0, sizeof(tagvideoEncOptions)); 115 if (!PVGetDefaultEncOption(mEncParams, 0)) { 116 ALOGE("Failed to get default encoding parameters"); 117 return OMX_ErrorUndefined; 118 } 119 mEncParams->encMode = mEncodeMode; 120 mEncParams->encWidth[0] = mWidth; 121 mEncParams->encHeight[0] = mHeight; 122 mEncParams->encFrameRate[0] = mFramerate >> 16; // mFramerate is in Q16 format 123 mEncParams->rcType = VBR_1; 124 mEncParams->vbvDelay = 5.0f; 125 126 // FIXME: 127 // Add more profile and level support for MPEG4 encoder 128 mEncParams->profile_level = CORE_PROFILE_LEVEL2; 129 mEncParams->packetSize = 32; 130 mEncParams->rvlcEnable = PV_OFF; 131 mEncParams->numLayers = 1; 132 mEncParams->timeIncRes = 1000; 133 mEncParams->tickPerSrc = ((int64_t)mEncParams->timeIncRes << 16) / mFramerate; 134 135 mEncParams->bitRate[0] = mBitrate; 136 mEncParams->iQuant[0] = 15; 137 mEncParams->pQuant[0] = 12; 138 mEncParams->quantType[0] = 0; 139 mEncParams->noFrameSkipped = PV_OFF; 140 141 if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) { 142 // Color conversion is needed. 143 free(mInputFrameData); 144 mInputFrameData = NULL; 145 if (((uint64_t)mWidth * mHeight) > ((uint64_t)INT32_MAX / 3)) { 146 ALOGE("b/25812794, Buffer size is too big."); 147 return OMX_ErrorBadParameter; 148 } 149 mInputFrameData = 150 (uint8_t *) malloc((mWidth * mHeight * 3 ) >> 1); 151 CHECK(mInputFrameData != NULL); 152 } 153 154 // PV's MPEG4 encoder requires the video dimension of multiple 155 if (mWidth % 16 != 0 || mHeight % 16 != 0) { 156 ALOGE("Video frame size %dx%d must be a multiple of 16", 157 mWidth, mHeight); 158 return OMX_ErrorBadParameter; 159 } 160 161 // Set IDR frame refresh interval 162 if (mIDRFrameRefreshIntervalInSec < 0) { 163 mEncParams->intraPeriod = -1; 164 } else if (mIDRFrameRefreshIntervalInSec == 0) { 165 mEncParams->intraPeriod = 1; // All I frames 166 } else { 167 mEncParams->intraPeriod = 168 (mIDRFrameRefreshIntervalInSec * mFramerate) >> 16; 169 } 170 171 mEncParams->numIntraMB = 0; 172 mEncParams->sceneDetect = PV_ON; 173 mEncParams->searchRange = 16; 174 mEncParams->mv8x8Enable = PV_OFF; 175 mEncParams->gobHeaderInterval = 0; 176 mEncParams->useACPred = PV_ON; 177 mEncParams->intraDCVlcTh = 0; 178 179 return OMX_ErrorNone; 180} 181 182OMX_ERRORTYPE SoftMPEG4Encoder::initEncoder() { 183 CHECK(!mStarted); 184 185 OMX_ERRORTYPE errType = OMX_ErrorNone; 186 if (OMX_ErrorNone != (errType = initEncParams())) { 187 ALOGE("Failed to initialized encoder params"); 188 mSignalledError = true; 189 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 190 return errType; 191 } 192 193 if (!PVInitVideoEncoder(mHandle, mEncParams)) { 194 ALOGE("Failed to initialize the encoder"); 195 mSignalledError = true; 196 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 197 return OMX_ErrorUndefined; 198 } 199 200 mNumInputFrames = -1; // 1st buffer for codec specific data 201 mStarted = true; 202 203 return OMX_ErrorNone; 204} 205 206OMX_ERRORTYPE SoftMPEG4Encoder::releaseEncoder() { 207 if (!mStarted) { 208 return OMX_ErrorNone; 209 } 210 211 PVCleanUpVideoEncoder(mHandle); 212 213 free(mInputFrameData); 214 mInputFrameData = NULL; 215 216 delete mEncParams; 217 mEncParams = NULL; 218 219 delete mHandle; 220 mHandle = NULL; 221 222 mStarted = false; 223 224 return OMX_ErrorNone; 225} 226 227OMX_ERRORTYPE SoftMPEG4Encoder::internalGetParameter( 228 OMX_INDEXTYPE index, OMX_PTR params) { 229 switch (index) { 230 case OMX_IndexParamVideoBitrate: 231 { 232 OMX_VIDEO_PARAM_BITRATETYPE *bitRate = 233 (OMX_VIDEO_PARAM_BITRATETYPE *) params; 234 235 if (!isValidOMXParam(bitRate)) { 236 return OMX_ErrorBadParameter; 237 } 238 239 if (bitRate->nPortIndex != 1) { 240 return OMX_ErrorUndefined; 241 } 242 243 bitRate->eControlRate = OMX_Video_ControlRateVariable; 244 bitRate->nTargetBitrate = mBitrate; 245 return OMX_ErrorNone; 246 } 247 248 case OMX_IndexParamVideoH263: 249 { 250 OMX_VIDEO_PARAM_H263TYPE *h263type = 251 (OMX_VIDEO_PARAM_H263TYPE *)params; 252 253 if (!isValidOMXParam(h263type)) { 254 return OMX_ErrorBadParameter; 255 } 256 257 if (h263type->nPortIndex != 1) { 258 return OMX_ErrorUndefined; 259 } 260 261 h263type->nAllowedPictureTypes = 262 (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP); 263 h263type->eProfile = OMX_VIDEO_H263ProfileBaseline; 264 h263type->eLevel = OMX_VIDEO_H263Level45; 265 h263type->bPLUSPTYPEAllowed = OMX_FALSE; 266 h263type->bForceRoundingTypeToZero = OMX_FALSE; 267 h263type->nPictureHeaderRepetition = 0; 268 h263type->nGOBHeaderInterval = 0; 269 270 return OMX_ErrorNone; 271 } 272 273 case OMX_IndexParamVideoMpeg4: 274 { 275 OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type = 276 (OMX_VIDEO_PARAM_MPEG4TYPE *)params; 277 278 if (!isValidOMXParam(mpeg4type)) { 279 return OMX_ErrorBadParameter; 280 } 281 282 if (mpeg4type->nPortIndex != 1) { 283 return OMX_ErrorUndefined; 284 } 285 286 mpeg4type->eProfile = OMX_VIDEO_MPEG4ProfileCore; 287 mpeg4type->eLevel = OMX_VIDEO_MPEG4Level2; 288 mpeg4type->nAllowedPictureTypes = 289 (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP); 290 mpeg4type->nBFrames = 0; 291 mpeg4type->nIDCVLCThreshold = 0; 292 mpeg4type->bACPred = OMX_TRUE; 293 mpeg4type->nMaxPacketSize = 256; 294 mpeg4type->nTimeIncRes = 1000; 295 mpeg4type->nHeaderExtension = 0; 296 mpeg4type->bReversibleVLC = OMX_FALSE; 297 298 return OMX_ErrorNone; 299 } 300 301 default: 302 return SoftVideoEncoderOMXComponent::internalGetParameter(index, params); 303 } 304} 305 306OMX_ERRORTYPE SoftMPEG4Encoder::internalSetParameter( 307 OMX_INDEXTYPE index, const OMX_PTR params) { 308 int32_t indexFull = index; 309 310 switch (indexFull) { 311 case OMX_IndexParamVideoBitrate: 312 { 313 OMX_VIDEO_PARAM_BITRATETYPE *bitRate = 314 (OMX_VIDEO_PARAM_BITRATETYPE *) params; 315 316 if (!isValidOMXParam(bitRate)) { 317 return OMX_ErrorBadParameter; 318 } 319 320 if (bitRate->nPortIndex != 1 || 321 bitRate->eControlRate != OMX_Video_ControlRateVariable) { 322 return OMX_ErrorUndefined; 323 } 324 325 mBitrate = bitRate->nTargetBitrate; 326 return OMX_ErrorNone; 327 } 328 329 case OMX_IndexParamVideoH263: 330 { 331 OMX_VIDEO_PARAM_H263TYPE *h263type = 332 (OMX_VIDEO_PARAM_H263TYPE *)params; 333 334 if (!isValidOMXParam(h263type)) { 335 return OMX_ErrorBadParameter; 336 } 337 338 if (h263type->nPortIndex != 1) { 339 return OMX_ErrorUndefined; 340 } 341 342 if (h263type->eProfile != OMX_VIDEO_H263ProfileBaseline || 343 h263type->eLevel != OMX_VIDEO_H263Level45 || 344 (h263type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) || 345 h263type->bPLUSPTYPEAllowed != OMX_FALSE || 346 h263type->bForceRoundingTypeToZero != OMX_FALSE || 347 h263type->nPictureHeaderRepetition != 0 || 348 h263type->nGOBHeaderInterval != 0) { 349 return OMX_ErrorUndefined; 350 } 351 352 return OMX_ErrorNone; 353 } 354 355 case OMX_IndexParamVideoMpeg4: 356 { 357 OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type = 358 (OMX_VIDEO_PARAM_MPEG4TYPE *)params; 359 360 if (!isValidOMXParam(mpeg4type)) { 361 return OMX_ErrorBadParameter; 362 } 363 364 if (mpeg4type->nPortIndex != 1) { 365 return OMX_ErrorUndefined; 366 } 367 368 if (mpeg4type->eProfile != OMX_VIDEO_MPEG4ProfileCore || 369 mpeg4type->eLevel != OMX_VIDEO_MPEG4Level2 || 370 (mpeg4type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) || 371 mpeg4type->nBFrames != 0 || 372 mpeg4type->nIDCVLCThreshold != 0 || 373 mpeg4type->bACPred != OMX_TRUE || 374 mpeg4type->nMaxPacketSize != 256 || 375 mpeg4type->nTimeIncRes != 1000 || 376 mpeg4type->nHeaderExtension != 0 || 377 mpeg4type->bReversibleVLC != OMX_FALSE) { 378 return OMX_ErrorUndefined; 379 } 380 381 return OMX_ErrorNone; 382 } 383 384 default: 385 return SoftVideoEncoderOMXComponent::internalSetParameter(index, params); 386 } 387} 388 389void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { 390 if (mSignalledError || mSawInputEOS) { 391 return; 392 } 393 394 if (!mStarted) { 395 if (OMX_ErrorNone != initEncoder()) { 396 return; 397 } 398 } 399 400 List<BufferInfo *> &inQueue = getPortQueue(0); 401 List<BufferInfo *> &outQueue = getPortQueue(1); 402 403 while (!mSawInputEOS && !inQueue.empty() && !outQueue.empty()) { 404 BufferInfo *inInfo = *inQueue.begin(); 405 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 406 BufferInfo *outInfo = *outQueue.begin(); 407 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 408 409 outHeader->nTimeStamp = 0; 410 outHeader->nFlags = 0; 411 outHeader->nOffset = 0; 412 outHeader->nFilledLen = 0; 413 outHeader->nOffset = 0; 414 415 uint8_t *outPtr = (uint8_t *) outHeader->pBuffer; 416 int32_t dataLength = outHeader->nAllocLen; 417 418 if (mNumInputFrames < 0) { 419 if (!PVGetVolHeader(mHandle, outPtr, &dataLength, 0)) { 420 ALOGE("Failed to get VOL header"); 421 mSignalledError = true; 422 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 423 return; 424 } 425 ALOGV("Output VOL header: %d bytes", dataLength); 426 ++mNumInputFrames; 427 outHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; 428 outHeader->nFilledLen = dataLength; 429 outQueue.erase(outQueue.begin()); 430 outInfo->mOwnedByUs = false; 431 notifyFillBufferDone(outHeader); 432 return; 433 } 434 435 // Save the input buffer info so that it can be 436 // passed to an output buffer 437 InputBufferInfo info; 438 info.mTimeUs = inHeader->nTimeStamp; 439 info.mFlags = inHeader->nFlags; 440 mInputBufferInfoVec.push(info); 441 442 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 443 mSawInputEOS = true; 444 } 445 446 if (inHeader->nFilledLen > 0) { 447 const uint8_t *inputData = NULL; 448 if (mInputDataIsMeta) { 449 inputData = 450 extractGraphicBuffer( 451 mInputFrameData, (mWidth * mHeight * 3) >> 1, 452 inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen, 453 mWidth, mHeight); 454 if (inputData == NULL) { 455 ALOGE("Unable to extract gralloc buffer in metadata mode"); 456 mSignalledError = true; 457 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 458 return; 459 } 460 } else { 461 inputData = (const uint8_t *)inHeader->pBuffer + inHeader->nOffset; 462 if (mColorFormat != OMX_COLOR_FormatYUV420Planar) { 463 ConvertYUV420SemiPlanarToYUV420Planar( 464 inputData, mInputFrameData, mWidth, mHeight); 465 inputData = mInputFrameData; 466 } 467 } 468 469 CHECK(inputData != NULL); 470 471 VideoEncFrameIO vin, vout; 472 memset(&vin, 0, sizeof(vin)); 473 memset(&vout, 0, sizeof(vout)); 474 vin.height = align(mHeight, 16); 475 vin.pitch = align(mWidth, 16); 476 vin.timestamp = (inHeader->nTimeStamp + 500) / 1000; // in ms 477 vin.yChan = (uint8_t *)inputData; 478 vin.uChan = vin.yChan + vin.height * vin.pitch; 479 vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2); 480 481 ULong modTimeMs = 0; 482 int32_t nLayer = 0; 483 MP4HintTrack hintTrack; 484 if (!PVEncodeVideoFrame(mHandle, &vin, &vout, 485 &modTimeMs, outPtr, &dataLength, &nLayer) || 486 !PVGetHintTrack(mHandle, &hintTrack)) { 487 ALOGE("Failed to encode frame or get hink track at frame %" PRId64, 488 mNumInputFrames); 489 mSignalledError = true; 490 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 491 } 492 CHECK(NULL == PVGetOverrunBuffer(mHandle)); 493 if (hintTrack.CodeType == 0) { // I-frame serves as sync frame 494 outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; 495 } 496 497 ++mNumInputFrames; 498 } else { 499 dataLength = 0; 500 } 501 502 inQueue.erase(inQueue.begin()); 503 inInfo->mOwnedByUs = false; 504 notifyEmptyBufferDone(inHeader); 505 506 outQueue.erase(outQueue.begin()); 507 CHECK(!mInputBufferInfoVec.empty()); 508 InputBufferInfo *inputBufInfo = mInputBufferInfoVec.begin(); 509 outHeader->nTimeStamp = inputBufInfo->mTimeUs; 510 outHeader->nFlags |= (inputBufInfo->mFlags | OMX_BUFFERFLAG_ENDOFFRAME); 511 outHeader->nFilledLen = dataLength; 512 mInputBufferInfoVec.erase(mInputBufferInfoVec.begin()); 513 outInfo->mOwnedByUs = false; 514 notifyFillBufferDone(outHeader); 515 } 516} 517 518} // namespace android 519 520android::SoftOMXComponent *createSoftOMXComponent( 521 const char *name, const OMX_CALLBACKTYPE *callbacks, 522 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 523 using namespace android; 524 if (!strcmp(name, "OMX.google.h263.encoder")) { 525 return new android::SoftMPEG4Encoder( 526 name, "video_encoder.h263", OMX_VIDEO_CodingH263, MEDIA_MIMETYPE_VIDEO_H263, 527 kH263ProfileLevels, NELEM(kH263ProfileLevels), 528 callbacks, appData, component); 529 } else if (!strcmp(name, "OMX.google.mpeg4.encoder")) { 530 return new android::SoftMPEG4Encoder( 531 name, "video_encoder.mpeg4", OMX_VIDEO_CodingMPEG4, MEDIA_MIMETYPE_VIDEO_MPEG4, 532 kMPEG4ProfileLevels, NELEM(kMPEG4ProfileLevels), 533 callbacks, appData, component); 534 } else { 535 CHECK(!"Unknown component"); 536 } 537 return NULL; 538} 539