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