1bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber/* 2bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * Copyright (C) 2011 The Android Open Source Project 3bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * 4bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * you may not use this file except in compliance with the License. 6bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * You may obtain a copy of the License at 7bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * 8bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * 10bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * Unless required by applicable law or agreed to in writing, software 11bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * See the License for the specific language governing permissions and 14bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber * limitations under the License. 15bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber */ 16bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 17bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber//#define LOG_NDEBUG 0 18bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#define LOG_TAG "SoftMPEG4" 19bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include <utils/Log.h> 20bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 21bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include "SoftMPEG4.h" 22bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 23bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include <media/stagefright/foundation/ADebug.h> 24a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar#include <media/stagefright/foundation/AUtils.h> 25bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include <media/stagefright/MediaDefs.h> 26bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include <media/stagefright/MediaErrors.h> 27457116d3a01618acf9a875020ca5860551ba03a6James Dong#include <media/IOMX.h> 28bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 29bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber#include "mp4dec_api.h" 30bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 31bbba88cb1bdc34705d1477208990a06904c022e7Andreas Hubernamespace android { 32bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 33457116d3a01618acf9a875020ca5860551ba03a6James Dongstatic const CodecProfileLevel kM4VProfileLevels[] = { 34457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0 }, 35457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level0b }, 36457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level1 }, 37457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level2 }, 38457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_MPEG4ProfileSimple, OMX_VIDEO_MPEG4Level3 }, 39457116d3a01618acf9a875020ca5860551ba03a6James Dong}; 40457116d3a01618acf9a875020ca5860551ba03a6James Dong 41457116d3a01618acf9a875020ca5860551ba03a6James Dongstatic const CodecProfileLevel kH263ProfileLevels[] = { 42457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level10 }, 43457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level20 }, 44457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level30 }, 45457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_H263ProfileBaseline, OMX_VIDEO_H263Level45 }, 46457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level10 }, 47457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level20 }, 48457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level30 }, 49457116d3a01618acf9a875020ca5860551ba03a6James Dong { OMX_VIDEO_H263ProfileISWV2, OMX_VIDEO_H263Level45 }, 50457116d3a01618acf9a875020ca5860551ba03a6James Dong}; 51457116d3a01618acf9a875020ca5860551ba03a6James Dong 52bbba88cb1bdc34705d1477208990a06904c022e7Andreas HuberSoftMPEG4::SoftMPEG4( 53bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber const char *name, 547f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar const char *componentRole, 557f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar OMX_VIDEO_CODINGTYPE codingType, 567f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar const CodecProfileLevel *profileLevels, 577f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar size_t numProfileLevels, 58bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber const OMX_CALLBACKTYPE *callbacks, 59bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber OMX_PTR appData, 60bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber OMX_COMPONENTTYPE **component) 617f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar : SoftVideoDecoderOMXComponent( 627f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar name, componentRole, codingType, profileLevels, numProfileLevels, 637f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar 352 /* width */, 288 /* height */, callbacks, appData, component), 647f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar mMode(codingType == OMX_VIDEO_CodingH263 ? MODE_H263 : MODE_MPEG4), 65bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mHandle(new tagvideoDecControls), 66bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mInputBufferCount(0), 67bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mSignalledError(false), 68bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mInitialized(false), 69bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mFramesConfigured(false), 70bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mNumSamplesOutput(0), 717f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar mPvTime(0) { 727f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar initPorts( 737f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar kNumInputBuffers, 74a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar 352 * 288 * 3 / 2 /* minInputBufferSize */, 757f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar kNumOutputBuffers, 767f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar (mMode == MODE_MPEG4) 777f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar ? MEDIA_MIMETYPE_VIDEO_MPEG4 : MEDIA_MIMETYPE_VIDEO_H263); 78bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber CHECK_EQ(initDecoder(), (status_t)OK); 79bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber} 80bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 81bbba88cb1bdc34705d1477208990a06904c022e7Andreas HuberSoftMPEG4::~SoftMPEG4() { 82bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber if (mInitialized) { 83bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber PVCleanUpVideoDecoder(mHandle); 84bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 85bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 86bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber delete mHandle; 87bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mHandle = NULL; 88bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber} 89bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 90bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huberstatus_t SoftMPEG4::initDecoder() { 91bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber memset(mHandle, 0, sizeof(tagvideoDecControls)); 92bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber return OK; 93bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber} 94bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 9584333e0475bc911adc16417f4ca327c975cf6c36Andreas Hubervoid SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) { 96bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber if (mSignalledError || mOutputPortSettingsChange != NONE) { 97bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber return; 98bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 99bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 100bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber List<BufferInfo *> &inQueue = getPortQueue(0); 101bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber List<BufferInfo *> &outQueue = getPortQueue(1); 102bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 103bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber while (!inQueue.empty() && outQueue.size() == kNumOutputBuffers) { 104bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber BufferInfo *inInfo = *inQueue.begin(); 105bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader; 106fd866b3aa0d97375de08f8888b95669026c83361Wei Jia if (inHeader == NULL) { 107fd866b3aa0d97375de08f8888b95669026c83361Wei Jia inQueue.erase(inQueue.begin()); 108fd866b3aa0d97375de08f8888b95669026c83361Wei Jia inInfo->mOwnedByUs = false; 109fd866b3aa0d97375de08f8888b95669026c83361Wei Jia continue; 110fd866b3aa0d97375de08f8888b95669026c83361Wei Jia } 111bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 112bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber PortInfo *port = editPortInfo(1); 113bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 114bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber OMX_BUFFERHEADERTYPE *outHeader = 115bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber port->mBuffers.editItemAt(mNumSamplesOutput & 1).mHeader; 116bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 117fd866b3aa0d97375de08f8888b95669026c83361Wei Jia if (inHeader->nFilledLen == 0) { 118bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber inQueue.erase(inQueue.begin()); 119bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber inInfo->mOwnedByUs = false; 120bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber notifyEmptyBufferDone(inHeader); 121bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 122bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber ++mInputBufferCount; 123bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 124fd866b3aa0d97375de08f8888b95669026c83361Wei Jia if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 125fd866b3aa0d97375de08f8888b95669026c83361Wei Jia outHeader->nFilledLen = 0; 126fd866b3aa0d97375de08f8888b95669026c83361Wei Jia outHeader->nFlags = OMX_BUFFERFLAG_EOS; 127bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 128fd866b3aa0d97375de08f8888b95669026c83361Wei Jia List<BufferInfo *>::iterator it = outQueue.begin(); 129fd866b3aa0d97375de08f8888b95669026c83361Wei Jia while ((*it)->mHeader != outHeader) { 130fd866b3aa0d97375de08f8888b95669026c83361Wei Jia ++it; 131fd866b3aa0d97375de08f8888b95669026c83361Wei Jia } 132bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 133fd866b3aa0d97375de08f8888b95669026c83361Wei Jia BufferInfo *outInfo = *it; 134fd866b3aa0d97375de08f8888b95669026c83361Wei Jia outInfo->mOwnedByUs = false; 135fd866b3aa0d97375de08f8888b95669026c83361Wei Jia outQueue.erase(it); 136fd866b3aa0d97375de08f8888b95669026c83361Wei Jia outInfo = NULL; 137bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 138fd866b3aa0d97375de08f8888b95669026c83361Wei Jia notifyFillBufferDone(outHeader); 139fd866b3aa0d97375de08f8888b95669026c83361Wei Jia outHeader = NULL; 140fd866b3aa0d97375de08f8888b95669026c83361Wei Jia } 141bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber return; 142bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 143bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 144bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber uint8_t *bitstream = inHeader->pBuffer + inHeader->nOffset; 145a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu uint32_t *start_code = (uint32_t *)bitstream; 146a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu bool volHeader = *start_code == 0xB0010000; 147a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu if (volHeader) { 148a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu PVCleanUpVideoDecoder(mHandle); 149a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu mInitialized = false; 150a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu } 151bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 152bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber if (!mInitialized) { 153bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber uint8_t *vol_data[1]; 154bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber int32_t vol_size = 0; 155bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 156bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber vol_data[0] = NULL; 157bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 158a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) || volHeader) { 159bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber vol_data[0] = bitstream; 160bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber vol_size = inHeader->nFilledLen; 161bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 162bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 163bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber MP4DecodingMode mode = 164bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber (mMode == MODE_MPEG4) ? MPEG4_MODE : H263_MODE; 165bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 166bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber Bool success = PVInitVideoDecoder( 1670f694a12f92a01f95807242320bd65e88c699708Ronghua Wu mHandle, vol_data, &vol_size, 1, 1680f694a12f92a01f95807242320bd65e88c699708Ronghua Wu outputBufferWidth(), outputBufferHeight(), mode); 169bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 170bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber if (!success) { 1715ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block ALOGW("PVInitVideoDecoder failed. Unsupported content?"); 172bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 173bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 174bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mSignalledError = true; 175bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber return; 176bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 177bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 178bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber MP4DecodingMode actualMode = PVGetDecBitstreamMode(mHandle); 179bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber if (mode != actualMode) { 180bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 181bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mSignalledError = true; 182bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber return; 183bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 184bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 185bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber PVSetPostProcType((VideoDecControls *) mHandle, 0); 186bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 187a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu bool hasFrameData = false; 188bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) { 189bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber inInfo->mOwnedByUs = false; 190bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber inQueue.erase(inQueue.begin()); 191bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber inInfo = NULL; 192bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber notifyEmptyBufferDone(inHeader); 193bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber inHeader = NULL; 194a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu } else if (volHeader) { 195a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu hasFrameData = true; 196bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 197bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 198bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mInitialized = true; 199bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 200a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu if (mode == MPEG4_MODE && handlePortSettingsChange()) { 201bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber return; 202bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 203bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 204a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu if (!hasFrameData) { 205a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu continue; 206a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu } 207bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 208bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 209bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber if (!mFramesConfigured) { 210bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber PortInfo *port = editPortInfo(1); 211bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber OMX_BUFFERHEADERTYPE *outHeader = port->mBuffers.editItemAt(1).mHeader; 212bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 213695123195034402ca76169b195069c28c30342d3Pawin Vongmasa OMX_U32 yFrameSize = sizeof(uint8) * mHandle->size; 214695123195034402ca76169b195069c28c30342d3Pawin Vongmasa if ((outHeader->nAllocLen < yFrameSize) || 215695123195034402ca76169b195069c28c30342d3Pawin Vongmasa (outHeader->nAllocLen - yFrameSize < yFrameSize / 2)) { 216baa9146401e28c5acf54dea21ddd197f0d3a8fcdPawin Vongmasa ALOGE("Too small output buffer for reference frame: %lu bytes", 217baa9146401e28c5acf54dea21ddd197f0d3a8fcdPawin Vongmasa (unsigned long)outHeader->nAllocLen); 218695123195034402ca76169b195069c28c30342d3Pawin Vongmasa android_errorWriteLog(0x534e4554, "30033990"); 219695123195034402ca76169b195069c28c30342d3Pawin Vongmasa notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 220695123195034402ca76169b195069c28c30342d3Pawin Vongmasa mSignalledError = true; 221695123195034402ca76169b195069c28c30342d3Pawin Vongmasa return; 222695123195034402ca76169b195069c28c30342d3Pawin Vongmasa } 223bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber PVSetReferenceYUV(mHandle, outHeader->pBuffer); 224bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mFramesConfigured = true; 225bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 226bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 227f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber uint32_t useExtTimestamp = (inHeader->nOffset == 0); 228f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber 229269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar // decoder deals in ms (int32_t), OMX in us (int64_t) 230269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar // so use fake timestamp instead 231269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar uint32_t timestamp = 0xFFFFFFFF; 232269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar if (useExtTimestamp) { 233269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar mPvToOmxTimeMap.add(mPvTime, inHeader->nTimeStamp); 234269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar timestamp = mPvTime; 235269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar mPvTime++; 236269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar } 237f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber 238bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber int32_t bufferSize = inHeader->nFilledLen; 23902accddf8d69da7b2b5e05631ad222cd842ff547Andreas Huber int32_t tmp = bufferSize; 240bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 241695123195034402ca76169b195069c28c30342d3Pawin Vongmasa OMX_U32 frameSize; 242695123195034402ca76169b195069c28c30342d3Pawin Vongmasa OMX_U64 yFrameSize = (OMX_U64)mWidth * (OMX_U64)mHeight; 243695123195034402ca76169b195069c28c30342d3Pawin Vongmasa if (yFrameSize > ((OMX_U64)UINT32_MAX / 3) * 2) { 244695123195034402ca76169b195069c28c30342d3Pawin Vongmasa ALOGE("Frame size too large"); 245695123195034402ca76169b195069c28c30342d3Pawin Vongmasa notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 246695123195034402ca76169b195069c28c30342d3Pawin Vongmasa mSignalledError = true; 247695123195034402ca76169b195069c28c30342d3Pawin Vongmasa return; 248695123195034402ca76169b195069c28c30342d3Pawin Vongmasa } 249695123195034402ca76169b195069c28c30342d3Pawin Vongmasa frameSize = (OMX_U32)(yFrameSize + (yFrameSize / 2)); 250695123195034402ca76169b195069c28c30342d3Pawin Vongmasa 2513a3c3f7fc658ef874f82e46857ad9df3616aac95Wonsik Kim if (outHeader->nAllocLen < frameSize) { 2523a3c3f7fc658ef874f82e46857ad9df3616aac95Wonsik Kim android_errorWriteLog(0x534e4554, "27833616"); 2533a3c3f7fc658ef874f82e46857ad9df3616aac95Wonsik Kim ALOGE("Insufficient output buffer size"); 2543a3c3f7fc658ef874f82e46857ad9df3616aac95Wonsik Kim notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 2553a3c3f7fc658ef874f82e46857ad9df3616aac95Wonsik Kim mSignalledError = true; 2563a3c3f7fc658ef874f82e46857ad9df3616aac95Wonsik Kim return; 2573a3c3f7fc658ef874f82e46857ad9df3616aac95Wonsik Kim } 25826557d832fde349721500b47d51467c046794ae9Wei Jia 25926557d832fde349721500b47d51467c046794ae9Wei Jia // Need to check if header contains new info, e.g., width/height, etc. 26026557d832fde349721500b47d51467c046794ae9Wei Jia VopHeaderInfo header_info; 26126557d832fde349721500b47d51467c046794ae9Wei Jia uint8_t *bitstreamTmp = bitstream; 26226557d832fde349721500b47d51467c046794ae9Wei Jia if (PVDecodeVopHeader( 26326557d832fde349721500b47d51467c046794ae9Wei Jia mHandle, &bitstreamTmp, ×tamp, &tmp, 26426557d832fde349721500b47d51467c046794ae9Wei Jia &header_info, &useExtTimestamp, 26526557d832fde349721500b47d51467c046794ae9Wei Jia outHeader->pBuffer) != PV_TRUE) { 26626557d832fde349721500b47d51467c046794ae9Wei Jia ALOGE("failed to decode vop header."); 26726557d832fde349721500b47d51467c046794ae9Wei Jia 26826557d832fde349721500b47d51467c046794ae9Wei Jia notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 26926557d832fde349721500b47d51467c046794ae9Wei Jia mSignalledError = true; 27026557d832fde349721500b47d51467c046794ae9Wei Jia return; 27126557d832fde349721500b47d51467c046794ae9Wei Jia } 27226557d832fde349721500b47d51467c046794ae9Wei Jia if (handlePortSettingsChange()) { 27326557d832fde349721500b47d51467c046794ae9Wei Jia return; 27426557d832fde349721500b47d51467c046794ae9Wei Jia } 27526557d832fde349721500b47d51467c046794ae9Wei Jia 2760029faf8f4efbca3844c4174b75d46c432f8f272Andreas Huber // The PV decoder is lying to us, sometimes it'll claim to only have 2770029faf8f4efbca3844c4174b75d46c432f8f272Andreas Huber // consumed a subset of the buffer when it clearly consumed all of it. 2780029faf8f4efbca3844c4174b75d46c432f8f272Andreas Huber // ignore whatever it says... 27926557d832fde349721500b47d51467c046794ae9Wei Jia if (PVDecodeVopBody(mHandle, &tmp) != PV_TRUE) { 28029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("failed to decode video frame."); 281bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 282bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 283bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mSignalledError = true; 284bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber return; 285bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 286bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 287a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu // H263 doesn't have VOL header, the frame size information is in short header, i.e. the 288a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu // decoder may detect size change after PVDecodeVideoFrame. 289a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu if (handlePortSettingsChange()) { 290bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber return; 291bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 292bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 293f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber // decoder deals in ms, OMX in us. 294269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar outHeader->nTimeStamp = mPvToOmxTimeMap.valueFor(timestamp); 295269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar mPvToOmxTimeMap.removeItem(timestamp); 296bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 29702accddf8d69da7b2b5e05631ad222cd842ff547Andreas Huber inHeader->nOffset += bufferSize; 29802accddf8d69da7b2b5e05631ad222cd842ff547Andreas Huber inHeader->nFilledLen = 0; 2994c44e9fed87ff6363393f2559b150291242da247Marco Nelissen if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) { 3004c44e9fed87ff6363393f2559b150291242da247Marco Nelissen outHeader->nFlags = OMX_BUFFERFLAG_EOS; 3014c44e9fed87ff6363393f2559b150291242da247Marco Nelissen } else { 3024c44e9fed87ff6363393f2559b150291242da247Marco Nelissen outHeader->nFlags = 0; 3034c44e9fed87ff6363393f2559b150291242da247Marco Nelissen } 304f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber 305f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber if (inHeader->nFilledLen == 0) { 306f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber inInfo->mOwnedByUs = false; 307f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber inQueue.erase(inQueue.begin()); 308f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber inInfo = NULL; 309f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber notifyEmptyBufferDone(inHeader); 310f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber inHeader = NULL; 311f2af5a2c607e71ff4cd39da28b077c0a68b206feAndreas Huber } 312bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 313bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber ++mInputBufferCount; 314bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 315bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber outHeader->nOffset = 0; 3163a3c3f7fc658ef874f82e46857ad9df3616aac95Wonsik Kim outHeader->nFilledLen = frameSize; 317bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 318bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber List<BufferInfo *>::iterator it = outQueue.begin(); 319bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber while ((*it)->mHeader != outHeader) { 320bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber ++it; 321bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 322bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 323bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber BufferInfo *outInfo = *it; 324bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber outInfo->mOwnedByUs = false; 325bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber outQueue.erase(it); 326bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber outInfo = NULL; 327bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 328bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber notifyFillBufferDone(outHeader); 329bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber outHeader = NULL; 330bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 331bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber ++mNumSamplesOutput; 332bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 333bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber} 334bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 335a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wubool SoftMPEG4::handlePortSettingsChange() { 3367f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar uint32_t disp_width, disp_height; 3377f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar PVGetVideoDimensions(mHandle, (int32 *)&disp_width, (int32 *)&disp_height); 338bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 3397f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar uint32_t buf_width, buf_height; 3407f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar PVGetBufferDimensions(mHandle, (int32 *)&buf_width, (int32 *)&buf_height); 341bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 342bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber CHECK_LE(disp_width, buf_width); 343bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber CHECK_LE(disp_height, buf_height); 344bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 3453856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("disp_width = %d, disp_height = %d, buf_width = %d, buf_height = %d", 346bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber disp_width, disp_height, buf_width, buf_height); 347bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 348d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu CropSettingsMode cropSettingsMode = kCropUnSet; 349d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu if (disp_width != buf_width || disp_height != buf_height) { 350d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu cropSettingsMode = kCropSet; 351d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu 352d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu if (mCropWidth != disp_width || mCropHeight != disp_height) { 353d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu mCropLeft = 0; 354d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu mCropTop = 0; 355d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu mCropWidth = disp_width; 356d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu mCropHeight = disp_height; 357d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu cropSettingsMode = kCropChanged; 358d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu } 359bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 360bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 361a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu bool portWillReset = false; 362a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu const bool fakeStride = true; 363a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu SoftVideoDecoderOMXComponent::handlePortSettingsChange( 364d5a2f55034022f2d0425fa0701894d0c4787b726Ronghua Wu &portWillReset, buf_width, buf_height, cropSettingsMode, fakeStride); 365a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu if (portWillReset) { 366bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber if (mMode == MODE_H263) { 367bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber PVCleanUpVideoDecoder(mHandle); 368bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 369bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber uint8_t *vol_data[1]; 370bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber int32_t vol_size = 0; 371bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 372bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber vol_data[0] = NULL; 373bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber if (!PVInitVideoDecoder( 3740f694a12f92a01f95807242320bd65e88c699708Ronghua Wu mHandle, vol_data, &vol_size, 1, outputBufferWidth(), outputBufferHeight(), 375bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber H263_MODE)) { 376bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL); 377bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mSignalledError = true; 378bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber return true; 379bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 380bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 381bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 382bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber mFramesConfigured = false; 383bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 384bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 385a694dd0ce2caaf921f7bc894df87a5d52594b4ebRonghua Wu return portWillReset; 386bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber} 387bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 388bbba88cb1bdc34705d1477208990a06904c022e7Andreas Hubervoid SoftMPEG4::onPortFlushCompleted(OMX_U32 portIndex) { 389bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber if (portIndex == 0 && mInitialized) { 390bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber CHECK_EQ((int)PVResetVideoDecoder(mHandle), (int)PV_TRUE); 391bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber } 392bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber} 393bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 394d94e716af0e49d775f0c0c4f36dd2c136ba5f2b2Andreas Hubervoid SoftMPEG4::onReset() { 3957f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar SoftVideoDecoderOMXComponent::onReset(); 396269a355679fce6a71523faeefc2ff575abbd1a8eLajos Molnar mPvToOmxTimeMap.clear(); 397d94e716af0e49d775f0c0c4f36dd2c136ba5f2b2Andreas Huber mSignalledError = false; 39853b0a2b1f9cb6b99b3f0d1a639921d1b24bc30b7Lajos Molnar mFramesConfigured = false; 39953b0a2b1f9cb6b99b3f0d1a639921d1b24bc30b7Lajos Molnar if (mInitialized) { 40053b0a2b1f9cb6b99b3f0d1a639921d1b24bc30b7Lajos Molnar PVCleanUpVideoDecoder(mHandle); 40153b0a2b1f9cb6b99b3f0d1a639921d1b24bc30b7Lajos Molnar mInitialized = false; 40253b0a2b1f9cb6b99b3f0d1a639921d1b24bc30b7Lajos Molnar } 403d94e716af0e49d775f0c0c4f36dd2c136ba5f2b2Andreas Huber} 404d94e716af0e49d775f0c0c4f36dd2c136ba5f2b2Andreas Huber 405a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnarvoid SoftMPEG4::updatePortDefinitions(bool updateCrop, bool updateInputSize) { 406a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar SoftVideoDecoderOMXComponent::updatePortDefinitions(updateCrop, updateInputSize); 407bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 4087f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar /* We have to align our width and height - this should affect stride! */ 4097f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef; 410a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar def->format.video.nStride = align(def->format.video.nStride, 16); 411a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar def->format.video.nSliceHeight = align(def->format.video.nSliceHeight, 16); 412a0940a569f2bc24b00dc10ce0fa7658b1dc3a3a5Lajos Molnar def->nBufferSize = (def->format.video.nStride * def->format.video.nSliceHeight * 3) / 2; 413bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber} 414bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 415bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber} // namespace android 416bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 417bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huberandroid::SoftOMXComponent *createSoftOMXComponent( 418bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber const char *name, const OMX_CALLBACKTYPE *callbacks, 419bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber OMX_PTR appData, OMX_COMPONENTTYPE **component) { 4207f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar using namespace android; 4217f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar if (!strcmp(name, "OMX.google.h263.decoder")) { 4227f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar return new android::SoftMPEG4( 4237f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar name, "video_decoder.h263", OMX_VIDEO_CodingH263, 4247f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar kH263ProfileLevels, ARRAY_SIZE(kH263ProfileLevels), 4257f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar callbacks, appData, component); 4267f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar } else if (!strcmp(name, "OMX.google.mpeg4.decoder")) { 4277f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar return new android::SoftMPEG4( 4287f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar name, "video_decoder.mpeg4", OMX_VIDEO_CodingMPEG4, 4297f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar kM4VProfileLevels, ARRAY_SIZE(kM4VProfileLevels), 4307f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar callbacks, appData, component); 4317f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar } else { 4327f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar CHECK(!"Unknown component"); 4337f616d3cc5366a4b8af20d3d0c768e3de1df0666Lajos Molnar } 434dba83c1cb1bef03bc5d1760c2639d06ff71c0fa7Mark Salyzyn return NULL; 435bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber} 436bbba88cb1bdc34705d1477208990a06904c022e7Andreas Huber 437