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