SoftMPEG4Encoder.cpp revision 87f8cbb223ee516803dbb99699320c2484cbf3ba
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 (bitRate->nPortIndex != 1) { 236 return OMX_ErrorUndefined; 237 } 238 239 bitRate->eControlRate = OMX_Video_ControlRateVariable; 240 bitRate->nTargetBitrate = mBitrate; 241 return OMX_ErrorNone; 242 } 243 244 case OMX_IndexParamVideoH263: 245 { 246 OMX_VIDEO_PARAM_H263TYPE *h263type = 247 (OMX_VIDEO_PARAM_H263TYPE *)params; 248 249 if (h263type->nPortIndex != 1) { 250 return OMX_ErrorUndefined; 251 } 252 253 h263type->nAllowedPictureTypes = 254 (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP); 255 h263type->eProfile = OMX_VIDEO_H263ProfileBaseline; 256 h263type->eLevel = OMX_VIDEO_H263Level45; 257 h263type->bPLUSPTYPEAllowed = OMX_FALSE; 258 h263type->bForceRoundingTypeToZero = OMX_FALSE; 259 h263type->nPictureHeaderRepetition = 0; 260 h263type->nGOBHeaderInterval = 0; 261 262 return OMX_ErrorNone; 263 } 264 265 case OMX_IndexParamVideoMpeg4: 266 { 267 OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type = 268 (OMX_VIDEO_PARAM_MPEG4TYPE *)params; 269 270 if (mpeg4type->nPortIndex != 1) { 271 return OMX_ErrorUndefined; 272 } 273 274 mpeg4type->eProfile = OMX_VIDEO_MPEG4ProfileCore; 275 mpeg4type->eLevel = OMX_VIDEO_MPEG4Level2; 276 mpeg4type->nAllowedPictureTypes = 277 (OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP); 278 mpeg4type->nBFrames = 0; 279 mpeg4type->nIDCVLCThreshold = 0; 280 mpeg4type->bACPred = OMX_TRUE; 281 mpeg4type->nMaxPacketSize = 256; 282 mpeg4type->nTimeIncRes = 1000; 283 mpeg4type->nHeaderExtension = 0; 284 mpeg4type->bReversibleVLC = OMX_FALSE; 285 286 return OMX_ErrorNone; 287 } 288 289 default: 290 return SoftVideoEncoderOMXComponent::internalGetParameter(index, params); 291 } 292} 293 294OMX_ERRORTYPE SoftMPEG4Encoder::internalSetParameter( 295 OMX_INDEXTYPE index, const OMX_PTR params) { 296 int32_t indexFull = index; 297 298 switch (indexFull) { 299 case OMX_IndexParamVideoBitrate: 300 { 301 OMX_VIDEO_PARAM_BITRATETYPE *bitRate = 302 (OMX_VIDEO_PARAM_BITRATETYPE *) params; 303 304 if (bitRate->nPortIndex != 1 || 305 bitRate->eControlRate != OMX_Video_ControlRateVariable) { 306 return OMX_ErrorUndefined; 307 } 308 309 mBitrate = bitRate->nTargetBitrate; 310 return OMX_ErrorNone; 311 } 312 313 case OMX_IndexParamVideoH263: 314 { 315 OMX_VIDEO_PARAM_H263TYPE *h263type = 316 (OMX_VIDEO_PARAM_H263TYPE *)params; 317 318 if (h263type->nPortIndex != 1) { 319 return OMX_ErrorUndefined; 320 } 321 322 if (h263type->eProfile != OMX_VIDEO_H263ProfileBaseline || 323 h263type->eLevel != OMX_VIDEO_H263Level45 || 324 (h263type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) || 325 h263type->bPLUSPTYPEAllowed != OMX_FALSE || 326 h263type->bForceRoundingTypeToZero != OMX_FALSE || 327 h263type->nPictureHeaderRepetition != 0 || 328 h263type->nGOBHeaderInterval != 0) { 329 return OMX_ErrorUndefined; 330 } 331 332 return OMX_ErrorNone; 333 } 334 335 case OMX_IndexParamVideoMpeg4: 336 { 337 OMX_VIDEO_PARAM_MPEG4TYPE *mpeg4type = 338 (OMX_VIDEO_PARAM_MPEG4TYPE *)params; 339 340 if (mpeg4type->nPortIndex != 1) { 341 return OMX_ErrorUndefined; 342 } 343 344 if (mpeg4type->eProfile != OMX_VIDEO_MPEG4ProfileCore || 345 mpeg4type->eLevel != OMX_VIDEO_MPEG4Level2 || 346 (mpeg4type->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) || 347 mpeg4type->nBFrames != 0 || 348 mpeg4type->nIDCVLCThreshold != 0 || 349 mpeg4type->bACPred != OMX_TRUE || 350 mpeg4type->nMaxPacketSize != 256 || 351 mpeg4type->nTimeIncRes != 1000 || 352 mpeg4type->nHeaderExtension != 0 || 353 mpeg4type->bReversibleVLC != OMX_FALSE) { 354 return OMX_ErrorUndefined; 355 } 356 357 return OMX_ErrorNone; 358 } 359 360 default: 361 return SoftVideoEncoderOMXComponent::internalSetParameter(index, params); 362 } 363} 364 365void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) { 366 if (mSignalledError || mSawInputEOS) { 367 return; 368 } 369 370 if (!mStarted) { 371 if (OMX_ErrorNone != initEncoder()) { 372 return; 373 } 374 } 375 376 List<BufferInfo *> &inQueue = getPortQueue(0); 377 List<BufferInfo *> &outQueue = getPortQueue(1); 378 379 while (!mSawInputEOS && !inQueue.empty() && !outQueue.empty()) { 380 BufferInfo *inInfo = *inQueue.begin(); 381 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 382 BufferInfo *outInfo = *outQueue.begin(); 383 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader; 384 385 outHeader->nTimeStamp = 0; 386 outHeader->nFlags = 0; 387 outHeader->nOffset = 0; 388 outHeader->nFilledLen = 0; 389 outHeader->nOffset = 0; 390 391 uint8_t *outPtr = (uint8_t *) outHeader->pBuffer; 392 int32_t dataLength = outHeader->nAllocLen; 393 394 if (mNumInputFrames < 0) { 395 if (!PVGetVolHeader(mHandle, outPtr, &dataLength, 0)) { 396 ALOGE("Failed to get VOL header"); 397 mSignalledError = true; 398 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 399 return; 400 } 401 ALOGV("Output VOL header: %d bytes", dataLength); 402 ++mNumInputFrames; 403 outHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; 404 outHeader->nFilledLen = dataLength; 405 outQueue.erase(outQueue.begin()); 406 outInfo->mOwnedByUs = false; 407 notifyFillBufferDone(outHeader); 408 return; 409 } 410 411 // Save the input buffer info so that it can be 412 // passed to an output buffer 413 InputBufferInfo info; 414 info.mTimeUs = inHeader->nTimeStamp; 415 info.mFlags = inHeader->nFlags; 416 mInputBufferInfoVec.push(info); 417 418 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 419 mSawInputEOS = true; 420 } 421 422 if (inHeader->nFilledLen > 0) { 423 const uint8_t *inputData = NULL; 424 if (mInputDataIsMeta) { 425 inputData = 426 extractGraphicBuffer( 427 mInputFrameData, (mWidth * mHeight * 3) >> 1, 428 inHeader->pBuffer + inHeader->nOffset, inHeader->nFilledLen, 429 mWidth, mHeight); 430 if (inputData == NULL) { 431 ALOGE("Unable to extract gralloc buffer in metadata mode"); 432 mSignalledError = true; 433 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 434 return; 435 } 436 } else { 437 inputData = (const uint8_t *)inHeader->pBuffer + inHeader->nOffset; 438 if (mColorFormat != OMX_COLOR_FormatYUV420Planar) { 439 ConvertYUV420SemiPlanarToYUV420Planar( 440 inputData, mInputFrameData, mWidth, mHeight); 441 inputData = mInputFrameData; 442 } 443 } 444 445 CHECK(inputData != NULL); 446 447 VideoEncFrameIO vin, vout; 448 memset(&vin, 0, sizeof(vin)); 449 memset(&vout, 0, sizeof(vout)); 450 vin.height = align(mHeight, 16); 451 vin.pitch = align(mWidth, 16); 452 vin.timestamp = (inHeader->nTimeStamp + 500) / 1000; // in ms 453 vin.yChan = (uint8_t *)inputData; 454 vin.uChan = vin.yChan + vin.height * vin.pitch; 455 vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2); 456 457 ULong modTimeMs = 0; 458 int32_t nLayer = 0; 459 MP4HintTrack hintTrack; 460 if (!PVEncodeVideoFrame(mHandle, &vin, &vout, 461 &modTimeMs, outPtr, &dataLength, &nLayer) || 462 !PVGetHintTrack(mHandle, &hintTrack)) { 463 ALOGE("Failed to encode frame or get hink track at frame %" PRId64, 464 mNumInputFrames); 465 mSignalledError = true; 466 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0); 467 } 468 CHECK(NULL == PVGetOverrunBuffer(mHandle)); 469 if (hintTrack.CodeType == 0) { // I-frame serves as sync frame 470 outHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME; 471 } 472 473 ++mNumInputFrames; 474 } else { 475 dataLength = 0; 476 } 477 478 inQueue.erase(inQueue.begin()); 479 inInfo->mOwnedByUs = false; 480 notifyEmptyBufferDone(inHeader); 481 482 outQueue.erase(outQueue.begin()); 483 CHECK(!mInputBufferInfoVec.empty()); 484 InputBufferInfo *inputBufInfo = mInputBufferInfoVec.begin(); 485 outHeader->nTimeStamp = inputBufInfo->mTimeUs; 486 outHeader->nFlags |= (inputBufInfo->mFlags | OMX_BUFFERFLAG_ENDOFFRAME); 487 outHeader->nFilledLen = dataLength; 488 mInputBufferInfoVec.erase(mInputBufferInfoVec.begin()); 489 outInfo->mOwnedByUs = false; 490 notifyFillBufferDone(outHeader); 491 } 492} 493 494} // namespace android 495 496android::SoftOMXComponent *createSoftOMXComponent( 497 const char *name, const OMX_CALLBACKTYPE *callbacks, 498 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 499 using namespace android; 500 if (!strcmp(name, "OMX.google.h263.encoder")) { 501 return new android::SoftMPEG4Encoder( 502 name, "video_encoder.h263", OMX_VIDEO_CodingH263, MEDIA_MIMETYPE_VIDEO_H263, 503 kH263ProfileLevels, NELEM(kH263ProfileLevels), 504 callbacks, appData, component); 505 } else if (!strcmp(name, "OMX.google.mpeg4.encoder")) { 506 return new android::SoftMPEG4Encoder( 507 name, "video_encoder.mpeg4", OMX_VIDEO_CodingMPEG4, MEDIA_MIMETYPE_VIDEO_MPEG4, 508 kMPEG4ProfileLevels, NELEM(kMPEG4ProfileLevels), 509 callbacks, appData, component); 510 } else { 511 CHECK(!"Unknown component"); 512 } 513 return NULL; 514} 515