1 /* 2 * Copyright (C) 2011 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 "SoftMPEG4" 19 #include <utils/Log.h> 20 21 #include "SoftMPEG4.h" 22 23 #include <media/stagefright/foundation/ADebug.h> 24 #include <media/stagefright/foundation/AUtils.h> 25 #include <media/stagefright/MediaDefs.h> 26 #include <media/stagefright/MediaErrors.h> 27 #include <media/IOMX.h> 28 29 #include "mp4dec_api.h" 30 31 namespace android { 32 33 static const CodecProfileLevel kM4VProfileLevels[] = { 34 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 }, 35 }; 36 37 static const CodecProfileLevel kH263ProfileLevels[] = { 38 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 }, 39 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 }, 40 { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level30 }, 41 { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level45 }, 42 }; 43 44 SoftMPEG4::SoftMPEG4( 45 const char *name, 46 const char *componentRole, 47 OMX_VIDEO_CODINGTYPE codingType, 48 const CodecProfileLevel *profileLevels, 49 size_t numProfileLevels, 50 const OMX_CALLBACKTYPE *callbacks, 51 OMX_PTR appData, 52 OMX_COMPONENTTYPE **component) 53 : SoftVideoDecoderOMXComponent( 54 name, componentRole, codingType, profileLevels, numProfileLevels, 55 352 /* width */, 288 /* height */, callbacks, appData, component), 56 mMode(codingType == OMX_VIDEO_CodingH263 ? MODE_H263 : MODE_MPEG4), 57 mHandle(new tagvideoDecControls), 58 mInputBufferCount(0), 59 mSignalledError(false), 60 mInitialized(false), 61 mFramesConfigured(false), 62 mNumSamplesOutput(0), 63 mPvTime(0) { 64 initPorts( 65 kNumInputBuffers, 66 352 * 288 * 3 / 2 /* minInputBufferSize */, 67 kNumOutputBuffers, 68 (mMode == MODE_MPEG4) 69 ? MEDIA_MIMETYPE_VIDEO_MPEG4 : MEDIA_MIMETYPE_VIDEO_H263); 70 CHECK_EQ(initDecoder(), (status_t)OK); 71 } 72 73 SoftMPEG4::~SoftMPEG4() { 74 if (mInitialized) { 75 PVCleanUpVideoDecoder(mHandle); 76 } 77 78 delete mHandle; 79 mHandle = NULL; 80 } 81 82 status_t SoftMPEG4::initDecoder() { 83 memset(mHandle, 0, sizeof(tagvideoDecControls)); 84 return OK; 85 } 86 87 void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { 88 if (mSignalledError || mOutputPortSettingsChange != NONE) { 89 return; 90 } 91 92 List<BufferInfo *> &inQueue = getPortQueue(0); 93 List<BufferInfo *> &outQueue = getPortQueue(1); 94 95 while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) { 96 BufferInfo *inInfo = *inQueue.begin(); 97 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 98 if (inHeader == NULL) { 99 inQueue.erase(inQueue.begin()); 100 inInfo->mOwnedByUs = false; 101 continue; 102 } 103 104 PortInfo *port = editPortInfo(1); 105 106 OMX_BUFFERHEADERTYPE *outHeader = 107 port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader; 108 109 if (inHeader->nFilledLen == 0) { 110 inQueue.erase(inQueue.begin()); 111 inInfo->mOwnedByUs = false; 112 notifyEmptyBufferDone(inHeader); 113 114 ++mInputBufferCount; 115 116 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 117 outHeader->nFilledLen = 0; 118 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 119 120 List<BufferInfo *>::iterator it = outQueue.begin(); 121 while ((*it)->mHeader != outHeader) { 122 ++it; 123 } 124 125 BufferInfo *outInfo = *it; 126 outInfo->mOwnedByUs = false; 127 outQueue.erase(it); 128 outInfo = NULL; 129 130 notifyFillBufferDone(outHeader); 131 outHeader = NULL; 132 } 133 return; 134 } 135 136 uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset; 137 uint32_t *start_code = (uint32_t *)bitstream; 138 bool volHeader = *start_code == 0xB0010000; 139 if (volHeader) { 140 PVCleanUpVideoDecoder(mHandle); 141 mInitialized = false; 142 } 143 144 if (!mInitialized) { 145 uint8_t *vol_data[1]; 146 int32_t vol_size = 0; 147 148 vol_data[0] = NULL; 149 150 if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) { 151 vol_data[0] = bitstream; 152 vol_size = inHeader->nFilledLen; 153 } 154 155 MP4DecodingMode mode = 156 (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE; 157 158 Bool success = PVInitVideoDecoder( 159 mHandle, vol_data, &vol_size, 1, 160 outputBufferWidth(), outputBufferHeight(), mode); 161 162 if (!success) { 163 ALOGW("PVInitVideoDecoder failed. Unsupported content?"); 164 165 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 166 mSignalledError = true; 167 return; 168 } 169 170 MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle); 171 if (mode != actualMode) { 172 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 173 mSignalledError = true; 174 return; 175 } 176 177 PVSetPostProcType((VideoDecControls *) mHandle, 0); 178 179 bool hasFrameData = false; 180 if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { 181 inInfo->mOwnedByUs = false; 182 inQueue.erase(inQueue.begin()); 183 inInfo = NULL; 184 notifyEmptyBufferDone(inHeader); 185 inHeader = NULL; 186 } else if (volHeader) { 187 hasFrameData = true; 188 } 189 190 mInitialized = true; 191 192 if (mode == MPEG4_MODE && handlePortSettingsChange()) { 193 return; 194 } 195 196 if (!hasFrameData) { 197 continue; 198 } 199 } 200 201 if (!mFramesConfigured) { 202 PortInfo *port = editPortInfo(1); 203 OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader; 204 205 OMX_U32 yFrameSize = sizeof(uint8) * mHandle->size; 206 if ((outHeader->nAllocLen < yFrameSize) || 207 (outHeader->nAllocLen - yFrameSize < yFrameSize / 2)) { 208 ALOGE("Too small output buffer for reference frame: %lu bytes", 209 (unsigned long)outHeader->nAllocLen); 210 android_errorWriteLog(0x534e4554, "30033990"); 211 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 212 mSignalledError = true; 213 return; 214 } 215 PVSetReferenceYUV(mHandle, outHeader->pBuffer); 216 mFramesConfigured = true; 217 } 218 219 uint32_t useExtTimestamp = (inHeader->nOffset == 0); 220 221 // decoder deals in ms (int32_t), OMX in us (int64_t) 222 // so use fake timestamp instead 223 uint32_t timestamp = 0xFFFFFFFF; 224 if (useExtTimestamp) { 225 mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp); 226 timestamp = mPvTime; 227 mPvTime++; 228 } 229 230 int32_t bufferSize = inHeader->nFilledLen; 231 int32_t tmp = bufferSize; 232 233 OMX_U32 frameSize; 234 OMX_U64 yFrameSize = (OMX_U64)mWidth * (OMX_U64)mHeight; 235 if (yFrameSize > ((OMX_U64)UINT32_MAX / 3) * 2) { 236 ALOGE("Frame size too large"); 237 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 238 mSignalledError = true; 239 return; 240 } 241 frameSize = (OMX_U32)(yFrameSize + (yFrameSize / 2)); 242 243 if (outHeader->nAllocLen < frameSize) { 244 android_errorWriteLog(0x534e4554, "27833616"); 245 ALOGE("Insufficient output buffer size"); 246 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 247 mSignalledError = true; 248 return; 249 } 250 251 // Need to check if header contains new info, e.g., width/height, etc. 252 VopHeaderInfo header_info; 253 uint8_t *bitstreamTmp = bitstream; 254 if (PVDecodeVopHeader( 255 mHandle, &bitstreamTmp, ×tamp, &tmp, 256 &header_info, &useExtTimestamp, 257 outHeader->pBuffer) != PV_TRUE) { 258 ALOGE("failed to decode vop header."); 259 260 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 261 mSignalledError = true; 262 return; 263 } 264 if (handlePortSettingsChange()) { 265 return; 266 } 267 268 // The PV decoder is lying to us, sometimes it'll claim to only have 269 // consumed a subset of the buffer when it clearly consumed all of it. 270 // ignore whatever it says... 271 if (PVDecodeVopBody(mHandle, &tmp) != PV_TRUE) { 272 ALOGE("failed to decode video frame."); 273 274 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 275 mSignalledError = true; 276 return; 277 } 278 279 // H263 doesn't have VOL header, the frame size information is in short header, i.e. the 280 // decoder may detect size change after PVDecodeVideoFrame. 281 if (handlePortSettingsChange()) { 282 return; 283 } 284 285 // decoder deals in ms, OMX in us. 286 outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp); 287 mPvToOmxTimeMap.removeItem(timestamp); 288 289 inHeader->nOffset += bufferSize; 290 inHeader->nFilledLen = 0; 291 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 292 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 293 } else { 294 outHeader->nFlags = 0; 295 } 296 297 if (inHeader->nFilledLen == 0) { 298 inInfo->mOwnedByUs = false; 299 inQueue.erase(inQueue.begin()); 300 inInfo = NULL; 301 notifyEmptyBufferDone(inHeader); 302 inHeader = NULL; 303 } 304 305 ++mInputBufferCount; 306 307 outHeader->nOffset = 0; 308 outHeader->nFilledLen = frameSize; 309 310 List<BufferInfo *>::iterator it = outQueue.begin(); 311 while ((*it)->mHeader != outHeader) { 312 ++it; 313 } 314 315 BufferInfo *outInfo = *it; 316 outInfo->mOwnedByUs = false; 317 outQueue.erase(it); 318 outInfo = NULL; 319 320 notifyFillBufferDone(outHeader); 321 outHeader = NULL; 322 323 ++mNumSamplesOutput; 324 } 325 } 326 327 bool SoftMPEG4::handlePortSettingsChange() { 328 uint32_t disp_width, disp_height; 329 PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height); 330 331 uint32_t buf_width, buf_height; 332 PVGetBufferDimensions(mHandle, (int32 *)&buf_width, (int32 *)&buf_height); 333 334 CHECK_LE(disp_width, buf_width); 335 CHECK_LE(disp_height, buf_height); 336 337 ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d", 338 disp_width, disp_height, buf_width, buf_height); 339 340 CropSettingsMode cropSettingsMode = kCropUnSet; 341 if (disp_width != buf_width || disp_height != buf_height) { 342 cropSettingsMode = kCropSet; 343 344 if (mCropWidth != disp_width || mCropHeight != disp_height) { 345 mCropLeft = 0; 346 mCropTop = 0; 347 mCropWidth = disp_width; 348 mCropHeight = disp_height; 349 cropSettingsMode = kCropChanged; 350 } 351 } 352 353 bool portWillReset = false; 354 const bool fakeStride = true; 355 SoftVideoDecoderOMXComponent::handlePortSettingsChange( 356 &portWillReset, buf_width, buf_height, cropSettingsMode, fakeStride); 357 if (portWillReset) { 358 if (mMode == MODE_H263) { 359 PVCleanUpVideoDecoder(mHandle); 360 361 uint8_t *vol_data[1]; 362 int32_t vol_size = 0; 363 364 vol_data[0] = NULL; 365 if (!PVInitVideoDecoder( 366 mHandle, vol_data, &vol_size, 1, outputBufferWidth(), outputBufferHeight(), 367 H263_MODE)) { 368 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 369 mSignalledError = true; 370 return true; 371 } 372 } 373 374 mFramesConfigured = false; 375 } 376 377 return portWillReset; 378 } 379 380 void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) { 381 if (portIndex == 0 && mInitialized) { 382 CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE); 383 } 384 } 385 386 void SoftMPEG4::onReset() { 387 SoftVideoDecoderOMXComponent::onReset(); 388 mPvToOmxTimeMap.clear(); 389 mSignalledError = false; 390 mFramesConfigured = false; 391 if (mInitialized) { 392 PVCleanUpVideoDecoder(mHandle); 393 mInitialized = false; 394 } 395 } 396 397 void SoftMPEG4::updatePortDefinitions(bool updateCrop, bool updateInputSize) { 398 SoftVideoDecoderOMXComponent::updatePortDefinitions(updateCrop, updateInputSize); 399 400 /* We have to align our width and height - this should affect stride! */ 401 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef; 402 def->format.video.nStride = align(def->format.video.nStride, 16); 403 def->format.video.nSliceHeight = align(def->format.video.nSliceHeight, 16); 404 def->nBufferSize = (def->format.video.nStride * def->format.video.nSliceHeight * 3) / 2; 405 } 406 407 } // namespace android 408 409 android::SoftOMXComponent *createSoftOMXComponent( 410 const char *name, const OMX_CALLBACKTYPE *callbacks, 411 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 412 using namespace android; 413 if (!strcmp(name, "OMX.google.h263.decoder")) { 414 return new android::SoftMPEG4( 415 name, "video_decoder.h263", OMX_VIDEO_CodingH263, 416 kH263ProfileLevels, ARRAY_SIZE(kH263ProfileLevels), 417 callbacks, appData, component); 418 } else if (!strcmp(name, "OMX.google.mpeg4.decoder")) { 419 return new android::SoftMPEG4( 420 name, "video_decoder.mpeg4", OMX_VIDEO_CodingMPEG4, 421 kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels), 422 callbacks, appData, component); 423 } else { 424 CHECK(!"Unknown component"); 425 } 426 return NULL; 427 } 428 429