1 /* 2 * Copyright (C) 2010 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 "M4vH263Encoder" 19 #include <utils/Log.h> 20 21 #include "M4vH263Encoder.h" 22 23 #include "mp4enc_api.h" 24 #include "OMX_Video.h" 25 26 #include <media/stagefright/MediaBufferGroup.h> 27 #include <media/stagefright/MediaDebug.h> 28 #include <media/stagefright/MediaDefs.h> 29 #include <media/stagefright/MediaErrors.h> 30 #include <media/stagefright/MetaData.h> 31 #include <media/stagefright/Utils.h> 32 33 namespace android { 34 35 inline static void ConvertYUV420SemiPlanarToYUV420Planar( 36 uint8_t *inyuv, uint8_t* outyuv, 37 int32_t width, int32_t height) { 38 39 int32_t outYsize = width * height; 40 uint32_t *outy = (uint32_t *) outyuv; 41 uint16_t *outcb = (uint16_t *) (outyuv + outYsize); 42 uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2)); 43 44 /* Y copying */ 45 memcpy(outy, inyuv, outYsize); 46 47 /* U & V copying */ 48 uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize); 49 for (int32_t i = height >> 1; i > 0; --i) { 50 for (int32_t j = width >> 2; j > 0; --j) { 51 uint32_t temp = *inyuv_4++; 52 uint32_t tempU = temp & 0xFF; 53 tempU = tempU | ((temp >> 8) & 0xFF00); 54 55 uint32_t tempV = (temp >> 8) & 0xFF; 56 tempV = tempV | ((temp >> 16) & 0xFF00); 57 58 // Flip U and V 59 *outcb++ = tempV; 60 *outcr++ = tempU; 61 } 62 } 63 } 64 65 M4vH263Encoder::M4vH263Encoder( 66 const sp<MediaSource>& source, 67 const sp<MetaData>& meta) 68 : mSource(source), 69 mMeta(meta), 70 mNumInputFrames(-1), 71 mNextModTimeUs(0), 72 mPrevTimestampUs(-1), 73 mStarted(false), 74 mInputBuffer(NULL), 75 mInputFrameData(NULL), 76 mGroup(NULL) { 77 78 LOGV("Construct software M4vH263Encoder"); 79 80 mHandle = new tagvideoEncControls; 81 memset(mHandle, 0, sizeof(tagvideoEncControls)); 82 83 mInitCheck = initCheck(meta); 84 } 85 86 M4vH263Encoder::~M4vH263Encoder() { 87 LOGV("Destruct software M4vH263Encoder"); 88 if (mStarted) { 89 stop(); 90 } 91 92 delete mEncParams; 93 delete mHandle; 94 } 95 96 status_t M4vH263Encoder::initCheck(const sp<MetaData>& meta) { 97 LOGV("initCheck"); 98 CHECK(meta->findInt32(kKeyWidth, &mVideoWidth)); 99 CHECK(meta->findInt32(kKeyHeight, &mVideoHeight)); 100 CHECK(meta->findInt32(kKeySampleRate, &mVideoFrameRate)); 101 CHECK(meta->findInt32(kKeyBitRate, &mVideoBitRate)); 102 103 // XXX: Add more color format support 104 CHECK(meta->findInt32(kKeyColorFormat, &mVideoColorFormat)); 105 if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) { 106 if (mVideoColorFormat != OMX_COLOR_FormatYUV420SemiPlanar) { 107 LOGE("Color format %d is not supported", mVideoColorFormat); 108 return BAD_VALUE; 109 } 110 // Allocate spare buffer only when color conversion is needed. 111 // Assume the color format is OMX_COLOR_FormatYUV420SemiPlanar. 112 mInputFrameData = 113 (uint8_t *) malloc((mVideoWidth * mVideoHeight * 3 ) >> 1); 114 CHECK(mInputFrameData); 115 } 116 117 // XXX: Remove this restriction 118 if (mVideoWidth % 16 != 0 || mVideoHeight % 16 != 0) { 119 LOGE("Video frame size %dx%d must be a multiple of 16", 120 mVideoWidth, mVideoHeight); 121 return BAD_VALUE; 122 } 123 124 mEncParams = new tagvideoEncOptions; 125 memset(mEncParams, 0, sizeof(tagvideoEncOptions)); 126 if (!PVGetDefaultEncOption(mEncParams, 0)) { 127 LOGE("Failed to get default encoding parameters"); 128 return BAD_VALUE; 129 } 130 131 // Need to know which role the encoder is in. 132 // XXX: Set the mode proper for other types of applications 133 // like streaming or video conference 134 const char *mime; 135 CHECK(meta->findCString(kKeyMIMEType, &mime)); 136 CHECK(!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || 137 !strcmp(mime, MEDIA_MIMETYPE_VIDEO_H263)); 138 if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) { 139 mEncParams->encMode = COMBINE_MODE_WITH_ERR_RES; 140 } else { 141 mEncParams->encMode = H263_MODE; 142 } 143 mEncParams->encWidth[0] = mVideoWidth; 144 mEncParams->encHeight[0] = mVideoHeight; 145 mEncParams->encFrameRate[0] = mVideoFrameRate; 146 mEncParams->rcType = VBR_1; 147 mEncParams->vbvDelay = (float)5.0; 148 149 // Set profile and level 150 // If profile and level setting is not correct, failure 151 // is reported when the encoder is initialized. 152 mEncParams->profile_level = CORE_PROFILE_LEVEL2; 153 int32_t profileLevel; 154 if (meta->findInt32(kKeyVideoLevel, &profileLevel)) { 155 mEncParams->profile_level = (ProfileLevelType)profileLevel; 156 } 157 158 mEncParams->packetSize = 32; 159 mEncParams->rvlcEnable = PV_OFF; 160 mEncParams->numLayers = 1; 161 mEncParams->timeIncRes = 1000; 162 mEncParams->tickPerSrc = mEncParams->timeIncRes / mVideoFrameRate; 163 164 mEncParams->bitRate[0] = mVideoBitRate; 165 mEncParams->iQuant[0] = 15; 166 mEncParams->pQuant[0] = 12; 167 mEncParams->quantType[0] = 0; 168 mEncParams->noFrameSkipped = PV_OFF; 169 170 // Set IDR frame refresh interval 171 int32_t iFramesIntervalSec; 172 CHECK(meta->findInt32(kKeyIFramesInterval, &iFramesIntervalSec)); 173 if (iFramesIntervalSec < 0) { 174 mEncParams->intraPeriod = -1; 175 } else if (iFramesIntervalSec == 0) { 176 mEncParams->intraPeriod = 1; // All I frames 177 } else { 178 mEncParams->intraPeriod = 179 (iFramesIntervalSec * mVideoFrameRate); 180 } 181 182 mEncParams->numIntraMB = 0; 183 mEncParams->sceneDetect = PV_ON; 184 mEncParams->searchRange = 16; 185 mEncParams->mv8x8Enable = PV_OFF; 186 mEncParams->gobHeaderInterval = 0; 187 mEncParams->useACPred = PV_ON; 188 mEncParams->intraDCVlcTh = 0; 189 190 mFormat = new MetaData; 191 mFormat->setInt32(kKeyWidth, mVideoWidth); 192 mFormat->setInt32(kKeyHeight, mVideoHeight); 193 mFormat->setInt32(kKeyBitRate, mVideoBitRate); 194 mFormat->setInt32(kKeySampleRate, mVideoFrameRate); 195 mFormat->setInt32(kKeyColorFormat, mVideoColorFormat); 196 197 mFormat->setCString(kKeyMIMEType, mime); 198 mFormat->setCString(kKeyDecoderComponent, "M4vH263Encoder"); 199 return OK; 200 } 201 202 status_t M4vH263Encoder::start(MetaData *params) { 203 LOGV("start"); 204 if (mInitCheck != OK) { 205 return mInitCheck; 206 } 207 208 if (mStarted) { 209 LOGW("Call start() when encoder already started"); 210 return OK; 211 } 212 213 if (!PVInitVideoEncoder(mHandle, mEncParams)) { 214 LOGE("Failed to initialize the encoder"); 215 return UNKNOWN_ERROR; 216 } 217 218 mGroup = new MediaBufferGroup(); 219 int32_t maxSize; 220 if (!PVGetMaxVideoFrameSize(mHandle, &maxSize)) { 221 maxSize = 256 * 1024; // Magic # 222 } 223 LOGV("Max output buffer size: %d", maxSize); 224 mGroup->add_buffer(new MediaBuffer(maxSize)); 225 226 mSource->start(params); 227 mNumInputFrames = -1; // 1st frame contains codec specific data 228 mStarted = true; 229 230 return OK; 231 } 232 233 status_t M4vH263Encoder::stop() { 234 LOGV("stop"); 235 if (!mStarted) { 236 LOGW("Call stop() when encoder has not started"); 237 return OK; 238 } 239 240 if (mInputBuffer) { 241 mInputBuffer->release(); 242 mInputBuffer = NULL; 243 } 244 245 if (mGroup) { 246 delete mGroup; 247 mGroup = NULL; 248 } 249 250 if (mInputFrameData) { 251 delete mInputFrameData; 252 mInputFrameData = NULL; 253 } 254 255 CHECK(PVCleanUpVideoEncoder(mHandle)); 256 257 mSource->stop(); 258 mStarted = false; 259 260 return OK; 261 } 262 263 sp<MetaData> M4vH263Encoder::getFormat() { 264 LOGV("getFormat"); 265 return mFormat; 266 } 267 268 status_t M4vH263Encoder::read( 269 MediaBuffer **out, const ReadOptions *options) { 270 271 *out = NULL; 272 273 MediaBuffer *outputBuffer; 274 CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer)); 275 uint8_t *outPtr = (uint8_t *) outputBuffer->data(); 276 int32_t dataLength = outputBuffer->size(); 277 278 // Output codec specific data 279 if (mNumInputFrames < 0) { 280 if (!PVGetVolHeader(mHandle, outPtr, &dataLength, 0)) { 281 LOGE("Failed to get VOL header"); 282 return UNKNOWN_ERROR; 283 } 284 LOGV("Output VOL header: %d bytes", dataLength); 285 outputBuffer->meta_data()->setInt32(kKeyIsCodecConfig, 1); 286 outputBuffer->set_range(0, dataLength); 287 *out = outputBuffer; 288 ++mNumInputFrames; 289 return OK; 290 } 291 292 // Ready for accepting an input video frame 293 if (OK != mSource->read(&mInputBuffer, options)) { 294 LOGE("Failed to read from data source"); 295 outputBuffer->release(); 296 return UNKNOWN_ERROR; 297 } 298 299 if (mInputBuffer->size() - ((mVideoWidth * mVideoHeight * 3) >> 1) != 0) { 300 outputBuffer->release(); 301 mInputBuffer->release(); 302 mInputBuffer = NULL; 303 return UNKNOWN_ERROR; 304 } 305 306 int64_t timeUs; 307 CHECK(mInputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); 308 309 // When the timestamp of the current sample is the same as that 310 // of the previous sample, encoding of the current sample is 311 // bypassed, and the output length of the sample is set to 0 312 if (mNumInputFrames >= 1 && 313 (mNextModTimeUs > timeUs || mPrevTimestampUs == timeUs)) { 314 // Frame arrives too late 315 outputBuffer->set_range(0, 0); 316 *out = outputBuffer; 317 mInputBuffer->release(); 318 mInputBuffer = NULL; 319 return OK; 320 } 321 322 // Don't accept out-of-order samples 323 CHECK(mPrevTimestampUs < timeUs); 324 mPrevTimestampUs = timeUs; 325 326 // Color convert to OMX_COLOR_FormatYUV420Planar if necessary 327 outputBuffer->meta_data()->setInt64(kKeyTime, timeUs); 328 uint8_t *inPtr = (uint8_t *) mInputBuffer->data(); 329 if (mVideoColorFormat != OMX_COLOR_FormatYUV420Planar) { 330 CHECK(mInputFrameData); 331 CHECK(mVideoColorFormat == OMX_COLOR_FormatYUV420SemiPlanar); 332 ConvertYUV420SemiPlanarToYUV420Planar( 333 inPtr, mInputFrameData, mVideoWidth, mVideoHeight); 334 inPtr = mInputFrameData; 335 } 336 CHECK(inPtr != NULL); 337 338 // Ready for encoding a video frame 339 VideoEncFrameIO vin, vout; 340 vin.height = ((mVideoHeight + 15) >> 4) << 4; 341 vin.pitch = ((mVideoWidth + 15) >> 4) << 4; 342 vin.timestamp = (timeUs + 500) / 1000; // in ms 343 vin.yChan = inPtr; 344 vin.uChan = vin.yChan + vin.height * vin.pitch; 345 vin.vChan = vin.uChan + ((vin.height * vin.pitch) >> 2); 346 unsigned long modTimeMs = 0; 347 int32_t nLayer = 0; 348 MP4HintTrack hintTrack; 349 if (!PVEncodeVideoFrame(mHandle, &vin, &vout, 350 &modTimeMs, outPtr, &dataLength, &nLayer) || 351 !PVGetHintTrack(mHandle, &hintTrack)) { 352 LOGE("Failed to encode frame or get hink track at frame %lld", 353 mNumInputFrames); 354 outputBuffer->release(); 355 mInputBuffer->release(); 356 mInputBuffer = NULL; 357 return UNKNOWN_ERROR; 358 } 359 CHECK_EQ(NULL, PVGetOverrunBuffer(mHandle)); 360 if (hintTrack.CodeType == 0) { // I-frame serves as sync frame 361 outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1); 362 } 363 364 ++mNumInputFrames; 365 mNextModTimeUs = modTimeMs * 1000LL; 366 outputBuffer->set_range(0, dataLength); 367 *out = outputBuffer; 368 mInputBuffer->release(); 369 mInputBuffer = NULL; 370 return OK; 371 } 372 373 void M4vH263Encoder::signalBufferReturned(MediaBuffer *buffer) { 374 } 375 376 } // namespace android 377