1 /* 2 * Copyright (c) 2009-2011 Intel Corporation. All rights reserved. 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 "PVSoftMPEG4Encoder" 19 #include <wrs_omxil_core/log.h> 20 21 #include "mp4enc_api.h" 22 #include "OMX_Video.h" 23 24 #include <media/stagefright/foundation/ADebug.h> 25 #include <media/stagefright/MediaDefs.h> 26 #include <media/stagefright/MediaErrors.h> 27 #include <media/stagefright/MetaData.h> 28 #include <media/stagefright/Utils.h> 29 30 #include <ui/GraphicBufferMapper.h> 31 #include <ui/Rect.h> 32 33 #include "PVSoftMPEG4Encoder.h" 34 #include "VideoEncoderLog.h" 35 36 #define ALIGN(x, align) (((x) + (align) - 1) & (~((align) - 1))) 37 38 inline static void ConvertYUV420SemiPlanarToYUV420Planar( 39 uint8_t *inyuv, uint8_t* outyuv, 40 int32_t width, int32_t height) { 41 42 int32_t outYsize = width * height; 43 uint32_t *outy = (uint32_t *) outyuv; 44 uint16_t *outcb = (uint16_t *) (outyuv + outYsize); 45 uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2)); 46 47 /* Y copying */ 48 memcpy(outy, inyuv, outYsize); 49 50 /* U & V copying */ 51 uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize); 52 for (int32_t i = height >> 1; i > 0; --i) { 53 for (int32_t j = width >> 2; j > 0; --j) { 54 uint32_t temp = *inyuv_4++; 55 uint32_t tempU = temp & 0xFF; 56 tempU = tempU | ((temp >> 8) & 0xFF00); 57 58 uint32_t tempV = (temp >> 8) & 0xFF; 59 tempV = tempV | ((temp >> 16) & 0xFF00); 60 61 // Flip U and V 62 *outcb++ = tempU; 63 *outcr++ = tempV; 64 } 65 } 66 } 67 68 inline static void trimBuffer(uint8_t *dataIn, uint8_t *dataOut, 69 int32_t width, int32_t height, 70 int32_t alignedHeight, int32_t stride) { 71 int32_t h; 72 uint8_t *y_start, *uv_start, *_y_start, *_uv_start; 73 y_start = dataOut; 74 uv_start = dataOut + width * height; 75 _y_start = dataIn; 76 _uv_start = dataIn + stride * alignedHeight; 77 78 for (h = 0; h < height; h++) 79 memcpy(y_start + h * width, _y_start + h * stride, width); 80 for (h = 0; h < height / 2; h++) 81 memcpy(uv_start + h * width, 82 _uv_start + h * stride, width); 83 } 84 85 PVSoftMPEG4Encoder::PVSoftMPEG4Encoder(const char *name) 86 : mEncodeMode(COMBINE_MODE_WITH_ERR_RES), 87 mVideoWidth(176), 88 mVideoHeight(144), 89 mVideoFrameRate(30), 90 mVideoBitRate(192000), 91 mVideoColorFormat(OMX_COLOR_FormatYUV420SemiPlanar), 92 mStoreMetaDataInBuffers(false), 93 mIDRFrameRefreshIntervalInSec(1), 94 mNumInputFrames(-1), 95 mStarted(false), 96 mSawInputEOS(false), 97 mSignalledError(false), 98 mHandle(new tagvideoEncControls), 99 mEncParams(new tagvideoEncOptions), 100 mInputFrameData(NULL) 101 { 102 103 if (!strcmp(name, "OMX.google.h263.encoder")) { 104 mEncodeMode = H263_MODE; 105 LOG_I("construct h263 encoder"); 106 } else { 107 CHECK(!strcmp(name, "OMX.google.mpeg4.encoder")); 108 LOG_I("construct mpeg4 encoder"); 109 } 110 111 setDefaultParams(); 112 #if NO_BUFFER_SHARE 113 mVASurfaceMappingAction |= MAPACT_COPY; 114 #endif 115 116 LOG_I("Construct PVSoftMPEG4Encoder"); 117 118 } 119 120 PVSoftMPEG4Encoder::~PVSoftMPEG4Encoder() { 121 LOG_I("Destruct PVSoftMPEG4Encoder"); 122 releaseEncoder(); 123 124 } 125 126 void PVSoftMPEG4Encoder::setDefaultParams() { 127 128 // Set default value for input parameters 129 mComParams.profile = VAProfileH264Baseline; 130 mComParams.level = 41; 131 mComParams.rawFormat = RAW_FORMAT_NV12; 132 mComParams.frameRate.frameRateNum = 30; 133 mComParams.frameRate.frameRateDenom = 1; 134 mComParams.resolution.width = 0; 135 mComParams.resolution.height = 0; 136 mComParams.intraPeriod = 30; 137 mComParams.rcMode = RATE_CONTROL_NONE; 138 mComParams.rcParams.initQP = 15; 139 mComParams.rcParams.minQP = 0; 140 mComParams.rcParams.bitRate = 640000; 141 mComParams.rcParams.targetPercentage= 0; 142 mComParams.rcParams.windowSize = 0; 143 mComParams.rcParams.disableFrameSkip = 0; 144 mComParams.rcParams.disableBitsStuffing = 1; 145 mComParams.cyclicFrameInterval = 30; 146 mComParams.refreshType = VIDEO_ENC_NONIR; 147 mComParams.airParams.airMBs = 0; 148 mComParams.airParams.airThreshold = 0; 149 mComParams.airParams.airAuto = 1; 150 mComParams.disableDeblocking = 2; 151 mComParams.syncEncMode = false; 152 mComParams.codedBufNum = 2; 153 154 } 155 156 Encode_Status PVSoftMPEG4Encoder::initEncParams() { 157 CHECK(mHandle != NULL); 158 memset(mHandle, 0, sizeof(tagvideoEncControls)); 159 160 CHECK(mEncParams != NULL); 161 memset(mEncParams, 0, sizeof(tagvideoEncOptions)); 162 if (!PVGetDefaultEncOption(mEncParams, 0)) { 163 LOG_E("Failed to get default encoding parameters"); 164 return ENCODE_FAIL; 165 } 166 mEncParams->encMode = mEncodeMode; 167 mEncParams->encWidth[0] = mVideoWidth; 168 mEncParams->encHeight[0] = mVideoHeight; 169 mEncParams->encFrameRate[0] = mVideoFrameRate; 170 mEncParams->rcType = VBR_1; 171 mEncParams->vbvDelay = 5.0f; 172 173 // FIXME: 174 // Add more profile and level support for MPEG4 encoder 175 mEncParams->profile_level = CORE_PROFILE_LEVEL2; 176 mEncParams->packetSize = 32; 177 mEncParams->rvlcEnable = PV_OFF; 178 mEncParams->numLayers = 1; 179 mEncParams->timeIncRes = 1000; 180 mEncParams->tickPerSrc = mEncParams->timeIncRes / mVideoFrameRate; 181 182 mEncParams->bitRate[0] = mVideoBitRate <= 2000000 ? mVideoBitRate : 2000000; 183 mEncParams->iQuant[0] = 15; 184 mEncParams->pQuant[0] = 12; 185 mEncParams->quantType[0] = 0; 186 mEncParams->noFrameSkipped = PV_OFF; 187 188 mTrimedInputData = 189 (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1); 190 CHECK(mTrimedInputData != NULL); 191 192 if (mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) { 193 // Color conversion is needed. 194 CHECK(mInputFrameData == NULL); 195 mInputFrameData = 196 (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1); 197 CHECK(mInputFrameData != NULL); 198 } 199 200 // PV's MPEG4 encoder requires the video dimension of multiple 201 if (mVideoWidth % 16 != 0 || mVideoHeight % 16 != 0) { 202 LOG_E("Video frame size %dx%d must be a multiple of 16", 203 mVideoWidth, mVideoHeight); 204 return ENCODE_INVALID_PARAMS; 205 } 206 207 // Set IDR frame refresh interval 208 if (mIDRFrameRefreshIntervalInSec < 0) { 209 mEncParams->intraPeriod = -1; 210 } else if (mIDRFrameRefreshIntervalInSec == 0) { 211 mEncParams->intraPeriod = 1; // All I frames 212 } else { 213 mEncParams->intraPeriod = 214 (mIDRFrameRefreshIntervalInSec * mVideoFrameRate); 215 } 216 217 mEncParams->numIntraMB = 0; 218 mEncParams->sceneDetect = PV_ON; 219 mEncParams->searchRange = 16; 220 mEncParams->mv8x8Enable = PV_OFF; 221 mEncParams->gobHeaderInterval = 0; 222 mEncParams->useACPred = PV_ON; 223 mEncParams->intraDCVlcTh = 0; 224 225 return ENCODE_SUCCESS; 226 } 227 228 Encode_Status PVSoftMPEG4Encoder::initEncoder() { 229 LOG_V("Begin\n"); 230 231 CHECK(!mStarted); 232 233 Encode_Status ret = ENCODE_SUCCESS; 234 if (ENCODE_SUCCESS != (ret = initEncParams())) { 235 LOG_E("Failed to initialized encoder params"); 236 mSignalledError = true; 237 return ret; 238 } 239 240 if (!PVInitVideoEncoder(mHandle, mEncParams)) { 241 LOG_E("Failed to initialize the encoder"); 242 mSignalledError = true; 243 return ENCODE_FAIL; 244 } 245 246 mNumInputFrames = -1; // 1st buffer for codec specific data 247 mStarted = true; 248 mCurTimestampUs = 0; 249 mLastTimestampUs = 0; 250 mVolHeaderLength = 256; 251 252 LOG_V("End\n"); 253 254 return ENCODE_SUCCESS; 255 } 256 257 Encode_Status PVSoftMPEG4Encoder::releaseEncoder() { 258 LOG_V("Begin\n"); 259 260 if (!mStarted) { 261 return ENCODE_SUCCESS; 262 } 263 264 PVCleanUpVideoEncoder(mHandle); 265 266 delete mTrimedInputData; 267 mTrimedInputData = NULL; 268 269 delete mInputFrameData; 270 mInputFrameData = NULL; 271 272 delete mEncParams; 273 mEncParams = NULL; 274 275 delete mHandle; 276 mHandle = NULL; 277 278 mStarted = false; 279 280 LOG_V("End\n"); 281 282 return ENCODE_SUCCESS; 283 } 284 285 Encode_Status PVSoftMPEG4Encoder::setParameters( 286 VideoParamConfigSet *videoEncParams) 287 { 288 289 Encode_Status ret = ENCODE_SUCCESS; 290 CHECK_NULL_RETURN_IFFAIL(videoEncParams); 291 LOG_I("Config type = %d\n", (int)videoEncParams->type); 292 293 if (mStarted) { 294 LOG_E("Encoder has been initialized, should use setConfig to change configurations\n"); 295 return ENCODE_ALREADY_INIT; 296 } 297 298 switch (videoEncParams->type) { 299 case VideoParamsTypeCommon: { 300 301 VideoParamsCommon *paramsCommon = 302 reinterpret_cast <VideoParamsCommon *> (videoEncParams); 303 if (paramsCommon->size != sizeof (VideoParamsCommon)) { 304 return ENCODE_INVALID_PARAMS; 305 } 306 if(paramsCommon->codedBufNum < 2) 307 paramsCommon->codedBufNum =2; 308 mComParams = *paramsCommon; 309 310 mVideoWidth = mComParams.resolution.width; 311 mVideoHeight = mComParams.resolution.height; 312 mVideoFrameRate = mComParams.frameRate.frameRateNum / \ 313 mComParams.frameRate.frameRateDenom; 314 mVideoBitRate = mComParams.rcParams.bitRate; 315 mVideoColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; 316 break; 317 } 318 319 case VideoParamsTypeStoreMetaDataInBuffers: { 320 VideoParamsStoreMetaDataInBuffers *metadata = 321 reinterpret_cast <VideoParamsStoreMetaDataInBuffers *> (videoEncParams); 322 323 if (metadata->size != sizeof (VideoParamsStoreMetaDataInBuffers)) { 324 return ENCODE_INVALID_PARAMS; 325 } 326 327 mStoreMetaDataInBuffers = metadata->isEnabled; 328 329 break; 330 } 331 332 default: { 333 LOG_I ("Wrong ParamType here\n"); 334 break; 335 } 336 } 337 338 return ret; 339 } 340 341 Encode_Status PVSoftMPEG4Encoder::getParameters( 342 VideoParamConfigSet *videoEncParams) { 343 344 Encode_Status ret = ENCODE_SUCCESS; 345 CHECK_NULL_RETURN_IFFAIL(videoEncParams); 346 LOG_I("Config type = %d\n", (int)videoEncParams->type); 347 348 switch (videoEncParams->type) { 349 case VideoParamsTypeCommon: { 350 351 VideoParamsCommon *paramsCommon = 352 reinterpret_cast <VideoParamsCommon *> (videoEncParams); 353 354 if (paramsCommon->size != sizeof (VideoParamsCommon)) { 355 return ENCODE_INVALID_PARAMS; 356 } 357 *paramsCommon = mComParams; 358 break; 359 } 360 361 case VideoParamsTypeStoreMetaDataInBuffers: { 362 VideoParamsStoreMetaDataInBuffers *metadata = 363 reinterpret_cast <VideoParamsStoreMetaDataInBuffers *> (videoEncParams); 364 365 if (metadata->size != sizeof (VideoParamsStoreMetaDataInBuffers)) { 366 return ENCODE_INVALID_PARAMS; 367 } 368 369 metadata->isEnabled = mStoreMetaDataInBuffers; 370 371 break; 372 } 373 374 default: { 375 LOG_I ("Wrong ParamType here\n"); 376 break; 377 } 378 379 } 380 return ret; 381 } 382 383 Encode_Status PVSoftMPEG4Encoder::encode(VideoEncRawBuffer *inBuffer, uint32_t timeout) 384 { 385 LOG_V("Begin\n"); 386 387 Encode_Status ret = ENCODE_SUCCESS; 388 389 if (mCurTimestampUs <= inBuffer->timeStamp) { 390 mLastTimestampUs = mCurTimestampUs; 391 mCurTimestampUs = inBuffer->timeStamp; 392 } 393 394 if (mNumInputFrames < 0) { 395 if (!PVGetVolHeader(mHandle, mVolHeader, &mVolHeaderLength, 0)) { 396 LOG_E("Failed to get VOL header"); 397 mSignalledError = true; 398 return ENCODE_FAIL; 399 } 400 LOG_I("Output VOL header: %d bytes", mVolHeaderLength); 401 mNumInputFrames++; 402 //return ENCODE_SUCCESS; 403 } 404 405 if (mStoreMetaDataInBuffers) { 406 IntelMetadataBuffer imb; 407 int32_t type; 408 int32_t value; 409 uint8_t *img; 410 const android::Rect rect(mVideoWidth, mVideoHeight); 411 android::status_t res; 412 ValueInfo vinfo; 413 ValueInfo *pvinfo = &vinfo; 414 CHECK(IMB_SUCCESS == imb.UnSerialize(inBuffer->data, inBuffer->size)); 415 imb.GetType((::IntelMetadataBufferType&)type); 416 imb.GetValue(value); 417 imb.GetValueInfo(pvinfo); 418 if(pvinfo == NULL) { 419 res = android::GraphicBufferMapper::get().lock((buffer_handle_t)value, 420 GRALLOC_USAGE_SW_READ_MASK, 421 rect, (void**)&img); 422 } else { 423 img = (uint8_t*)value; 424 } 425 if (pvinfo != NULL) 426 trimBuffer(img, mTrimedInputData, pvinfo->width, pvinfo->height, 427 pvinfo->height, pvinfo->lumaStride); 428 else { 429 //NV12 Y-TILED 430 trimBuffer(img, mTrimedInputData, mVideoWidth, mVideoHeight, 431 ALIGN(mVideoHeight, 32), ALIGN(mVideoWidth, 128)); 432 android::GraphicBufferMapper::get().unlock((buffer_handle_t)value); 433 } 434 } else { 435 memcpy(mTrimedInputData, inBuffer->data, 436 (mVideoWidth * mVideoHeight * 3 ) >> 1); 437 } 438 439 if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) { 440 ConvertYUV420SemiPlanarToYUV420Planar( 441 mTrimedInputData, mInputFrameData, mVideoWidth, mVideoHeight); 442 } else { 443 memcpy(mTrimedInputData, mInputFrameData, 444 (mVideoWidth * mVideoHeight * 3 ) >> 1); 445 } 446 447 LOG_V("End\n"); 448 449 return ret; 450 } 451 452 Encode_Status PVSoftMPEG4Encoder::getOutput(VideoEncOutputBuffer *outBuffer, uint32_t timeout) 453 { 454 LOG_V("Begin\n"); 455 456 Encode_Status ret = ENCODE_SUCCESS; 457 uint8_t *outPtr = outBuffer->data; 458 int32_t dataLength = outBuffer->bufferSize; 459 outBuffer->flag = 0; 460 461 if ((mEncodeMode == COMBINE_MODE_WITH_ERR_RES) && 462 (outBuffer->format == OUTPUT_CODEC_DATA)) { 463 memcpy(outPtr, mVolHeader, mVolHeaderLength); 464 ++mNumInputFrames; 465 outBuffer->flag |= ENCODE_BUFFERFLAG_CODECCONFIG; 466 outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME; 467 outBuffer->flag |= ENCODE_BUFFERFLAG_SYNCFRAME; 468 outBuffer->dataSize = mVolHeaderLength; 469 outBuffer->remainingSize = 0; 470 return ENCODE_SUCCESS; 471 } 472 473 outBuffer->timeStamp = mCurTimestampUs; 474 LOG_I("info.mTimeUs %lld\n", outBuffer->timeStamp); 475 476 VideoEncFrameIO vin, vout; 477 memset(&vin, 0, sizeof(vin)); 478 memset(&vout, 0, sizeof(vout)); 479 vin.height = ((mVideoHeight + 15) >> 4) << 4; 480 vin.pitch = ((mVideoWidth + 15) >> 4) << 4; 481 vin.timestamp = (outBuffer->timeStamp + 500) / 1000; // in ms 482 vin.yChan = mInputFrameData; 483 vin.uChan = vin.yChan + vin.height * vin.pitch; 484 vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2); 485 486 unsigned long modTimeMs = 0; 487 int32_t nLayer = 0; 488 MP4HintTrack hintTrack; 489 if (!PVEncodeVideoFrame(mHandle, &vin, &vout, 490 &modTimeMs, outPtr, &dataLength, &nLayer) || 491 !PVGetHintTrack(mHandle, &hintTrack)) { 492 LOG_E("Failed to encode frame or get hink track at frame %lld", 493 mNumInputFrames); 494 mSignalledError = true; 495 hintTrack.CodeType = 0; 496 ret = ENCODE_FAIL; 497 } 498 LOG_I("dataLength %d\n", dataLength); 499 CHECK(NULL == PVGetOverrunBuffer(mHandle)); 500 if (hintTrack.CodeType == 0) { // I-frame serves as sync frame 501 outBuffer->flag |= ENCODE_BUFFERFLAG_SYNCFRAME; 502 } 503 504 ++mNumInputFrames; 505 506 outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME; 507 outBuffer->dataSize = dataLength; 508 509 LOG_V("End\n"); 510 511 return ret; 512 } 513 514