SoftMPEG4.cpp revision baa9146401e28c5acf54dea21ddd197f0d3a8fcd
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/MediaDefs.h> 25#include <media/stagefright/MediaErrors.h> 26#include <media/IOMX.h> 27 28#include "mp4dec_api.h" 29 30namespace android { 31 32static const CodecProfileLevel kM4VProfileLevels[] = { 33 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 }, 34 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b }, 35 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 }, 36 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 }, 37 { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 }, 38}; 39 40static const CodecProfileLevel kH263ProfileLevels[] = { 41 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10 }, 42 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level20 }, 43 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 }, 44 { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 }, 45 { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level10 }, 46 { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level20 }, 47 { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level30 }, 48 { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level45 }, 49}; 50 51SoftMPEG4::SoftMPEG4( 52 const char *name, 53 const char *componentRole, 54 OMX_VIDEO_CODINGTYPE codingType, 55 const CodecProfileLevel *profileLevels, 56 size_t numProfileLevels, 57 const OMX_CALLBACKTYPE *callbacks, 58 OMX_PTR appData, 59 OMX_COMPONENTTYPE **component) 60 : SoftVideoDecoderOMXComponent( 61 name, componentRole, codingType, profileLevels, numProfileLevels, 62 352 /* width */, 288 /* height */, callbacks, appData, component), 63 mMode(codingType == OMX_VIDEO_CodingH263 ? MODE_H263 : MODE_MPEG4), 64 mHandle(new tagvideoDecControls), 65 mInputBufferCount(0), 66 mSignalledError(false), 67 mInitialized(false), 68 mFramesConfigured(false), 69 mNumSamplesOutput(0), 70 mPvTime(0) { 71 initPorts( 72 kNumInputBuffers, 73 8192 /* inputBufferSize */, 74 kNumOutputBuffers, 75 (mMode == MODE_MPEG4) 76 ? MEDIA_MIMETYPE_VIDEO_MPEG4 : MEDIA_MIMETYPE_VIDEO_H263); 77 CHECK_EQ(initDecoder(), (status_t)OK); 78} 79 80SoftMPEG4::~SoftMPEG4() { 81 if (mInitialized) { 82 PVCleanUpVideoDecoder(mHandle); 83 } 84 85 delete mHandle; 86 mHandle = NULL; 87} 88 89status_t SoftMPEG4::initDecoder() { 90 memset(mHandle, 0, sizeof(tagvideoDecControls)); 91 return OK; 92} 93 94void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { 95 if (mSignalledError || mOutputPortSettingsChange != NONE) { 96 return; 97 } 98 99 List<BufferInfo *> &inQueue = getPortQueue(0); 100 List<BufferInfo *> &outQueue = getPortQueue(1); 101 102 while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) { 103 BufferInfo *inInfo = *inQueue.begin(); 104 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 105 106 PortInfo *port = editPortInfo(1); 107 108 OMX_BUFFERHEADERTYPE *outHeader = 109 port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader; 110 111 if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) { 112 inQueue.erase(inQueue.begin()); 113 inInfo->mOwnedByUs = false; 114 notifyEmptyBufferDone(inHeader); 115 116 ++mInputBufferCount; 117 118 outHeader->nFilledLen = 0; 119 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 120 121 List<BufferInfo *>::iterator it = outQueue.begin(); 122 while ((*it)->mHeader != outHeader) { 123 ++it; 124 } 125 126 BufferInfo *outInfo = *it; 127 outInfo->mOwnedByUs = false; 128 outQueue.erase(it); 129 outInfo = NULL; 130 131 notifyFillBufferDone(outHeader); 132 outHeader = NULL; 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 // The PV decoder is lying to us, sometimes it'll claim to only have 251 // consumed a subset of the buffer when it clearly consumed all of it. 252 // ignore whatever it says... 253 if (PVDecodeVideoFrame( 254 mHandle, &bitstream, ×tamp, &tmp, 255 &useExtTimestamp, 256 outHeader->pBuffer) != PV_TRUE) { 257 ALOGE("failed to decode video frame."); 258 259 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 260 mSignalledError = true; 261 return; 262 } 263 264 // H263 doesn't have VOL header, the frame size information is in short header, i.e. the 265 // decoder may detect size change after PVDecodeVideoFrame. 266 if (handlePortSettingsChange()) { 267 return; 268 } 269 270 // decoder deals in ms, OMX in us. 271 outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp); 272 mPvToOmxTimeMap.removeItem(timestamp); 273 274 inHeader->nOffset += bufferSize; 275 inHeader->nFilledLen = 0; 276 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 277 outHeader->nFlags = OMX_BUFFERFLAG_EOS; 278 } else { 279 outHeader->nFlags = 0; 280 } 281 282 if (inHeader->nFilledLen == 0) { 283 inInfo->mOwnedByUs = false; 284 inQueue.erase(inQueue.begin()); 285 inInfo = NULL; 286 notifyEmptyBufferDone(inHeader); 287 inHeader = NULL; 288 } 289 290 ++mInputBufferCount; 291 292 outHeader->nOffset = 0; 293 outHeader->nFilledLen = frameSize; 294 295 List<BufferInfo *>::iterator it = outQueue.begin(); 296 while ((*it)->mHeader != outHeader) { 297 ++it; 298 } 299 300 BufferInfo *outInfo = *it; 301 outInfo->mOwnedByUs = false; 302 outQueue.erase(it); 303 outInfo = NULL; 304 305 notifyFillBufferDone(outHeader); 306 outHeader = NULL; 307 308 ++mNumSamplesOutput; 309 } 310} 311 312bool SoftMPEG4::handlePortSettingsChange() { 313 uint32_t disp_width, disp_height; 314 PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height); 315 316 uint32_t buf_width, buf_height; 317 PVGetBufferDimensions(mHandle, (int32 *)&buf_width, (int32 *)&buf_height); 318 319 CHECK_LE(disp_width, buf_width); 320 CHECK_LE(disp_height, buf_height); 321 322 ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d", 323 disp_width, disp_height, buf_width, buf_height); 324 325 CropSettingsMode cropSettingsMode = kCropUnSet; 326 if (disp_width != buf_width || disp_height != buf_height) { 327 cropSettingsMode = kCropSet; 328 329 if (mCropWidth != disp_width || mCropHeight != disp_height) { 330 mCropLeft = 0; 331 mCropTop = 0; 332 mCropWidth = disp_width; 333 mCropHeight = disp_height; 334 cropSettingsMode = kCropChanged; 335 } 336 } 337 338 bool portWillReset = false; 339 const bool fakeStride = true; 340 SoftVideoDecoderOMXComponent::handlePortSettingsChange( 341 &portWillReset, buf_width, buf_height, cropSettingsMode, fakeStride); 342 if (portWillReset) { 343 if (mMode == MODE_H263) { 344 PVCleanUpVideoDecoder(mHandle); 345 346 uint8_t *vol_data[1]; 347 int32_t vol_size = 0; 348 349 vol_data[0] = NULL; 350 if (!PVInitVideoDecoder( 351 mHandle, vol_data, &vol_size, 1, outputBufferWidth(), outputBufferHeight(), 352 H263_MODE)) { 353 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 354 mSignalledError = true; 355 return true; 356 } 357 } 358 359 mFramesConfigured = false; 360 } 361 362 return portWillReset; 363} 364 365void SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) { 366 if (portIndex == 0 && mInitialized) { 367 CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE); 368 } 369} 370 371void SoftMPEG4::onReset() { 372 SoftVideoDecoderOMXComponent::onReset(); 373 mPvToOmxTimeMap.clear(); 374 mSignalledError = false; 375 mFramesConfigured = false; 376 if (mInitialized) { 377 PVCleanUpVideoDecoder(mHandle); 378 mInitialized = false; 379 } 380} 381 382void SoftMPEG4::updatePortDefinitions() { 383 SoftVideoDecoderOMXComponent::updatePortDefinitions(); 384 385 /* We have to align our width and height - this should affect stride! */ 386 OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef; 387 def->nBufferSize = 388 (((def->format.video.nFrameWidth + 15) & -16) 389 * ((def->format.video.nFrameHeight + 15) & -16) * 3) / 2; 390} 391 392} // namespace android 393 394android::SoftOMXComponent *createSoftOMXComponent( 395 const char *name, const OMX_CALLBACKTYPE *callbacks, 396 OMX_PTR appData, OMX_COMPONENTTYPE **component) { 397 using namespace android; 398 if (!strcmp(name, "OMX.google.h263.decoder")) { 399 return new android::SoftMPEG4( 400 name, "video_decoder.h263", OMX_VIDEO_CodingH263, 401 kH263ProfileLevels, ARRAY_SIZE(kH263ProfileLevels), 402 callbacks, appData, component); 403 } else if (!strcmp(name, "OMX.google.mpeg4.decoder")) { 404 return new android::SoftMPEG4( 405 name, "video_decoder.mpeg4", OMX_VIDEO_CodingMPEG4, 406 kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels), 407 callbacks, appData, component); 408 } else { 409 CHECK(!"Unknown component"); 410 } 411} 412 413