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