sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include "mdfvideodecoderbuffermanager.h" sl@0: sl@0: #define MDFVIDEODECODERBUFFERMANAGER_DEBUG 1 sl@0: sl@0: #if defined (SYMBIAN_MDFVIDEODECODERBUFFERMANAGER_DEBUG) sl@0: #define DEBUG_PRINT( x ) ( RDebug::Print( x ) ) sl@0: #define DEBUG_PRINT2( x,y ) ( RDebug::Print( x,y ) ) sl@0: #define DEBUG_PRINT3( x,y,z ) ( RDebug::Print( x,y,z ) ) sl@0: sl@0: #else sl@0: #define DEBUG_PRINT( x ) sl@0: #define DEBUG_PRINT2( x,y ) sl@0: #define DEBUG_PRINT3( x,y,z ) sl@0: #endif // defined (SYMBIAN_MDFVIDEODECODERBUFFERMANAGER_DEBUG) sl@0: sl@0: CVideoDataBuffer::CVideoDataBuffer() sl@0: { sl@0: } sl@0: sl@0: TUint CVideoDataBuffer::Length() sl@0: { sl@0: return iSize; sl@0: } sl@0: sl@0: CVideoDataBuffer* CVideoDataBuffer::NewL(TUint aSize) sl@0: { sl@0: CVideoDataBuffer* self = new (ELeave) CVideoDataBuffer; sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aSize); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: void CVideoDataBuffer::ConstructL(TUint aBufferSize) sl@0: { sl@0: iSize = aBufferSize; sl@0: CMMFDescriptorBuffer* buffer = CMMFDescriptorBuffer::NewL(aBufferSize); sl@0: TDes8& des = buffer->Data(); sl@0: TUint8* ptr = const_cast(des.Ptr()); sl@0: iVideoInputBuffer.iData.Set(ptr, des.Length(), des.MaxLength()); sl@0: iMmfBuffer = buffer; sl@0: } sl@0: sl@0: CVideoDataBuffer::operator CMMFBuffer*() sl@0: { sl@0: return iMmfBuffer; sl@0: } sl@0: sl@0: CVideoDataBuffer::operator TVideoInputBuffer&() sl@0: { sl@0: return iVideoInputBuffer; sl@0: } sl@0: sl@0: sl@0: sl@0: TBool CVideoDataBuffer::operator== (const CMMFBuffer* aBuffer) const sl@0: { sl@0: return (aBuffer == iMmfBuffer); sl@0: } sl@0: sl@0: TBool CVideoDataBuffer::operator== (const TVideoInputBuffer& aVideoInputBuffer) const sl@0: { sl@0: // compare the data pointers sl@0: return iVideoInputBuffer.iData == aVideoInputBuffer.iData; sl@0: } sl@0: sl@0: CVideoDataBuffer::~CVideoDataBuffer() sl@0: { sl@0: delete iMmfBuffer; sl@0: } sl@0: sl@0: sl@0: CVideoFrameBuffer::CVideoFrameBuffer(TSize aFrameSize, sl@0: TUncompressedVideoFormat aFormat, sl@0: TDisplayMode aDisplayMode) sl@0: : iRawPtr(0,0), sl@0: iFrameSize(aFrameSize), sl@0: iVideoFormat(aFormat), sl@0: iDisplayMode(aDisplayMode) sl@0: { sl@0: sl@0: } sl@0: sl@0: CVideoFrameBuffer* CVideoFrameBuffer::NewL(TSize aFrameSize, sl@0: TUncompressedVideoFormat aFormat, sl@0: TDisplayMode aDisplayMode) sl@0: { sl@0: CVideoFrameBuffer* self = new (ELeave) CVideoFrameBuffer(aFrameSize, aFormat, aDisplayMode); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: void CVideoFrameBuffer::SetLastBuffer(TBool aLastBuffer) sl@0: { sl@0: iLastBuffer = aLastBuffer; sl@0: } sl@0: sl@0: TBool CVideoFrameBuffer::LastBuffer() sl@0: { sl@0: return iLastBuffer; sl@0: } sl@0: sl@0: void CVideoFrameBuffer::ConstructL() sl@0: { sl@0: iFrameBufferSize = CFbsBitmap::ScanLineLength(iFrameSize.iWidth, iDisplayMode) * sl@0: iFrameSize.iHeight; sl@0: Mem::FillZ(&iVideoPicture, sizeof(TVideoPicture)); sl@0: if(iVideoFormat.iDataFormat == ERgbFbsBitmap) sl@0: { sl@0: iBitmap = new(ELeave)CFbsBitmap; sl@0: User::LeaveIfError(iBitmap->Create(iFrameSize, iDisplayMode)); sl@0: DEBUG_PRINT2(_L("BufferManager: Created bitmap at 0x%08x"), iBitmap); sl@0: sl@0: iVideoPicture.iData.iRgbBitmap = iBitmap; sl@0: iBitmap->LockHeap(); sl@0: TRAPD(err, iMmfBuffer = CMMFPtrBuffer::NewL(TPtr8(reinterpret_cast(iBitmap->DataAddress()), sl@0: iFrameBufferSize, sl@0: iFrameBufferSize)) ); sl@0: iBitmap->UnlockHeap(); sl@0: User::LeaveIfError(err); sl@0: } sl@0: else if((iVideoFormat.iDataFormat == ERgbRawData) || (iVideoFormat.iDataFormat == EYuvRawData)) sl@0: { sl@0: iRawBuffer = HBufC8::NewMaxL(iFrameBufferSize); sl@0: iRawPtr.Set(iRawBuffer->Des()); sl@0: iMmfBuffer = CMMFPtrBuffer::NewL(iRawPtr); sl@0: iVideoPicture.iData.iRawData = &iRawPtr; sl@0: } sl@0: iVideoPicture.iData.iDataFormat = iVideoFormat.iDataFormat; sl@0: iVideoPicture.iData.iDataSize = iFrameSize; sl@0: } sl@0: sl@0: CVideoFrameBuffer::operator CMMFBuffer*() sl@0: { sl@0: return iMmfBuffer; sl@0: } sl@0: sl@0: CVideoFrameBuffer::operator TVideoPicture&() sl@0: { sl@0: return iVideoPicture; sl@0: } sl@0: sl@0: CVideoFrameBuffer::operator CMMFBuffer&() sl@0: { sl@0: return *iMmfBuffer; sl@0: } sl@0: sl@0: CVideoFrameBuffer::operator TVideoPicture*() sl@0: { sl@0: return &iVideoPicture; sl@0: } sl@0: sl@0: void CVideoFrameBuffer::LockFrameBufferHeap() sl@0: { sl@0: iBitmap->LockHeap(); sl@0: iHeapLocked = ETrue; sl@0: } sl@0: sl@0: void CVideoFrameBuffer::UnlockFrameBufferHeap() sl@0: { sl@0: if (iHeapLocked) sl@0: { sl@0: iBitmap->UnlockHeap(); sl@0: iHeapLocked = EFalse; sl@0: } sl@0: } sl@0: sl@0: sl@0: TBool CVideoFrameBuffer::operator== (const CMMFBuffer* aBuffer) const sl@0: { sl@0: return (aBuffer == iMmfBuffer); sl@0: } sl@0: sl@0: TBool CVideoFrameBuffer::operator== (const TVideoPicture& aVideoInputBuffer) const sl@0: { sl@0: // compare the data pointers - cheat, it is the same pointer for the bitmap and sl@0: // raw data sl@0: return iVideoPicture.iData.iRawData == aVideoInputBuffer.iData.iRawData; sl@0: } sl@0: sl@0: CVideoFrameBuffer::~CVideoFrameBuffer() sl@0: { sl@0: UnlockFrameBufferHeap(); sl@0: delete iMmfBuffer; sl@0: delete iBitmap; sl@0: delete iRawBuffer; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Constructs a new instance of CMDFVideoDecoderBufferManager. sl@0: @return "CMDFVideoDecoderBufferManager*" sl@0: A pointer to the newly constructed CMDFVideoDecoderBufferManager sl@0: */ sl@0: CMdfVideoDecoderBufferManager* CMdfVideoDecoderBufferManager::NewL() sl@0: { sl@0: CMdfVideoDecoderBufferManager* s = new(ELeave) CMdfVideoDecoderBufferManager; sl@0: CleanupStack::PushL(s); sl@0: s->ConstructL(); sl@0: CleanupStack::Pop(s); sl@0: return (static_cast(s)); sl@0: } sl@0: sl@0: CMdfVideoDecoderBufferManager::CMdfVideoDecoderBufferManager() sl@0: { sl@0: } sl@0: void CMdfVideoDecoderBufferManager::ConstructL() sl@0: { sl@0: RFbsSession::Connect(); sl@0: } sl@0: sl@0: /** sl@0: Default destructor sl@0: */ sl@0: CMdfVideoDecoderBufferManager::~CMdfVideoDecoderBufferManager() sl@0: { sl@0: // get rid of input buffers sl@0: delete iInputBuffer; sl@0: // cleanup frame buffer arrays sl@0: iEmptyFrameBuffers.ResetAndDestroy(); sl@0: iFilledFrameBuffers.ResetAndDestroy(); sl@0: iFrameBuffersInUse.ResetAndDestroy(); sl@0: RFbsSession::Disconnect(); sl@0: sl@0: DEBUG_PRINT(_L("BufferManager: Closing down")); sl@0: } sl@0: sl@0: /** sl@0: Initializes the decoder buffer manager. sl@0: @param "const TUncompressedVideoFormat& aFormat" sl@0: The image format to decode into sl@0: */ sl@0: void CMdfVideoDecoderBufferManager::Init(const TUncompressedVideoFormat& aFormat) sl@0: { sl@0: DEBUG_PRINT(_L("BufferManager: Initializing")); sl@0: sl@0: iFormat = aFormat; sl@0: // The actual frame size will come from the VOL headers. sl@0: // Set an initial value for iFrameBufferSize so we can get sl@0: // the VOL headers themselves. sl@0: // Also ensure we allow one free output buffer. sl@0: iFrameBufferSize = 1024; // 1k sl@0: iMaxFrameBuffers = 1; sl@0: sl@0: iInputBufferInUse = EFalse; sl@0: } sl@0: sl@0: /** sl@0: Creates a new empty input buffer. sl@0: @param "TUint aBufferSize" sl@0: The requested buffer size. sl@0: @return "TVideoInputBuffer&" sl@0: An empty input buffer. sl@0: @leave May leave with KErrInUse if no input buffer is available, or with KErrNoMemory sl@0: if a buffer cannot be created or adjusted. sl@0: */ sl@0: CVideoDataBuffer& CMdfVideoDecoderBufferManager::CreateDataBufferL(TUint aBufferSize) sl@0: { sl@0: // We use one input buffer and one overflow buffer. sl@0: sl@0: // If the app requests another buffer before this one has been processed, then leave. sl@0: if(iInputBufferInUse) sl@0: { sl@0: User::Leave(KErrInUse); sl@0: } sl@0: sl@0: if(aBufferSize < 1) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: // Create or adjust the input buffer sl@0: sl@0: if(!iInputBuffer) sl@0: { sl@0: iInputBuffer = CVideoDataBuffer::NewL(aBufferSize); sl@0: } sl@0: else if(iInputBuffer->Length() != aBufferSize) sl@0: { sl@0: // NB don't use ReAllocL() as it will panic if the buffer is shrinking sl@0: // Use temp variable sl@0: CVideoDataBuffer* tempBuffer = CVideoDataBuffer::NewL(aBufferSize); sl@0: sl@0: // Coverity reports a leave_without_push error here because sl@0: // CVideoDataBuffer contains a frame buffer member which could contain sl@0: // a CFbsBitmap member which can panic during its destructor. The panic sl@0: // has a trapped leave and for some reason coverity does not recognise it. sl@0: // Mark as false positive sl@0: // coverity[leave_without_push : FALSE] sl@0: delete iInputBuffer; sl@0: iInputBuffer = NULL; sl@0: iInputBuffer = tempBuffer; sl@0: } sl@0: return *iInputBuffer; sl@0: } sl@0: sl@0: void CMdfVideoDecoderBufferManager::ReturnDataBufferL(TVideoInputBuffer& aInputBuffer) sl@0: { sl@0: if (!iInputBuffer) sl@0: { sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: // if this buffer isn't the input buffer, leave sl@0: if(! (*iInputBuffer == aInputBuffer) ) sl@0: { sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: // if the buffer is not in use, leave sl@0: if(!iInputBufferInUse) sl@0: { sl@0: User::Leave(KErrInUse); sl@0: } sl@0: sl@0: // finished with input buffer - mark it unused sl@0: iInputBufferInUse = EFalse; sl@0: } sl@0: sl@0: CVideoDataBuffer& CMdfVideoDecoderBufferManager::GetDataBufferL() sl@0: { sl@0: if (!iInputBuffer) sl@0: { sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: if (iInputBufferInUse) sl@0: { sl@0: User::Leave(KErrInUse); sl@0: } sl@0: iInputBufferInUse = ETrue; sl@0: return *iInputBuffer; sl@0: } sl@0: sl@0: /** sl@0: Gets the number of available input buffers. sl@0: @return "TInt" sl@0: The number of available input buffers. sl@0: */ sl@0: TInt CMdfVideoDecoderBufferManager::DataBuffersAvailable() const sl@0: { sl@0: // this plugin has one input buffer. if it is in use (i.e. the client hasn't been sl@0: // notified with MdvppNewBuffers()) then return 0. sl@0: return ((iInputBufferInUse) ? 0 : 1); sl@0: } sl@0: sl@0: /** sl@0: Sets the frame size. sl@0: @param "const TSize& aSize" sl@0: The frame size. sl@0: */ sl@0: void CMdfVideoDecoderBufferManager::SetFrameSize(const TSize& aSize) sl@0: { sl@0: iFrameSize = aSize; sl@0: } sl@0: sl@0: /** sl@0: Gets the frame size. sl@0: @return "const TSize&" sl@0: The frame size. sl@0: */ sl@0: const TSize& CMdfVideoDecoderBufferManager::FrameSize() const sl@0: { sl@0: return iFrameSize; sl@0: } sl@0: sl@0: /** sl@0: Sets the frame buffer size. sl@0: @param "TInt aSize" sl@0: The frame buffer size. sl@0: */ sl@0: void CMdfVideoDecoderBufferManager::SetFrameBufferSize(TInt aSize) sl@0: { sl@0: iFrameBufferSize = aSize; sl@0: } sl@0: sl@0: /** sl@0: Gets the frame buffer size. sl@0: @return "TInt" sl@0: The frame buffer size. sl@0: */ sl@0: TInt CMdfVideoDecoderBufferManager::FrameBufferSize() const sl@0: { sl@0: return iFrameBufferSize; sl@0: } sl@0: sl@0: /** sl@0: Gets the maximum number of frame buffers. sl@0: @return "TInt" sl@0: The maximum number of frame buffers. sl@0: */ sl@0: TInt CMdfVideoDecoderBufferManager::MaxFrameBuffers() const sl@0: { sl@0: return iMaxFrameBuffers; sl@0: } sl@0: sl@0: /** sl@0: Gets the number of available pictures (full output buffers). sl@0: @return "TInt" sl@0: The number of available pictures. sl@0: */ sl@0: TInt CMdfVideoDecoderBufferManager::FilledFrameBuffersAvailable() const sl@0: { sl@0: return ((iFilledFrameBuffers.Count() > 0) ? 1 : 0); sl@0: } sl@0: sl@0: /** sl@0: Gets the number of available frame buffers. sl@0: @return "TInt" sl@0: The number of available frame buffers. sl@0: */ sl@0: TInt CMdfVideoDecoderBufferManager::EmptyFrameBuffersAvailable() const sl@0: { sl@0: return ((iEmptyFrameBuffers.Count() < iMaxFrameBuffers) ? 1 : 0); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Gets the first available framebuffer sl@0: @return "TVideoPicture&" sl@0: A picture. sl@0: @leave May leave with KErrNotReady if no picture is available. sl@0: */ sl@0: CVideoFrameBuffer& CMdfVideoDecoderBufferManager::GetEmptyFrameBufferL(TBool aLockHeap) sl@0: { sl@0: DEBUG_PRINT2(_L("Get Empty Frame Buffer avail: %d"),iEmptyFrameBuffers.Count()); sl@0: sl@0: if(iEmptyFrameBuffers.Count() == 0) sl@0: { sl@0: User::Leave(KErrNotReady); sl@0: } sl@0: CVideoFrameBuffer* frameBuf = iEmptyFrameBuffers[0]; sl@0: iFrameBuffersInUse.AppendL(frameBuf); sl@0: iEmptyFrameBuffers.Remove(0); sl@0: if (aLockHeap) sl@0: { sl@0: frameBuf->LockFrameBufferHeap(); sl@0: } sl@0: return *frameBuf; sl@0: } sl@0: sl@0: sl@0: sl@0: /** sl@0: Gets the first available picture (full frame buffer). sl@0: @return "TVideoPicture&" sl@0: A picture. sl@0: @leave May leave with KErrNotReady if no picture is available. sl@0: */ sl@0: CVideoFrameBuffer& CMdfVideoDecoderBufferManager::GetFilledFrameBufferL(TBool aLockHeap) sl@0: { sl@0: DEBUG_PRINT2(_L("Get Filled Frame Buffer avail: %d"),iFilledFrameBuffers.Count()); sl@0: sl@0: if(iFilledFrameBuffers.Count() == 0) sl@0: { sl@0: User::Leave(KErrNotReady); sl@0: } sl@0: CVideoFrameBuffer* frameBuf = iFilledFrameBuffers[0]; sl@0: iFilledFrameBuffers.Remove(0); sl@0: iFrameBuffersInUse.AppendL(frameBuf); sl@0: sl@0: if (aLockHeap) sl@0: { sl@0: frameBuf->LockFrameBufferHeap(); sl@0: } sl@0: return *frameBuf; sl@0: } sl@0: sl@0: /** sl@0: Gets the last displayed picture. sl@0: Used by Direct Screen Access to redraw. sl@0: @return "TPictureData&" sl@0: The last displayed picture. sl@0: @leave May leave with KErrNotReady if no picture is available. sl@0: */ sl@0: const TPictureData& CMdfVideoDecoderBufferManager::LastPictureL() const sl@0: { sl@0: // it's a union, so we can check either iRgbBitmap or iRawData sl@0: if(!iLastDisplayedFrame.iRgbBitmap) sl@0: { sl@0: User::Leave(KErrNotReady); sl@0: } sl@0: return iLastDisplayedFrame; sl@0: } sl@0: sl@0: /** sl@0: Gets a new empty frame buffer. sl@0: @param aDisplayMode sl@0: The display mode of the bitmap to be created. sl@0: @return "TVideoPicture&" sl@0: A frame buffer. sl@0: @leave May leave with KErrNotReady if no frame buffer is available, or if there sl@0: is no memory to create a new one. sl@0: */ sl@0: CVideoFrameBuffer& CMdfVideoDecoderBufferManager::CreateFrameBufferL(TDisplayMode aDisplayMode) sl@0: { sl@0: CVideoFrameBuffer* frameBuffer = CVideoFrameBuffer::NewL(iFrameSize, iFormat, aDisplayMode); sl@0: CleanupStack::PushL(frameBuffer); sl@0: iEmptyFrameBuffers.AppendL(frameBuffer); sl@0: CleanupStack::Pop(frameBuffer); sl@0: sl@0: DEBUG_PRINT2(_L("BufferManager: Created frame buffer; %d buffers in use"), iEmptyFrameBuffers.Count()); sl@0: return *frameBuffer; sl@0: } sl@0: sl@0: /** sl@0: Returns a used picture to the buffer manager for disposal. sl@0: @param "TVideoPicture* aFrameBuffer" sl@0: A used picture. sl@0: @param "TBool aSaveLast" sl@0: Save this picture as the last displayed (for redraw). sl@0: @leave May leave with KErrNotFound if the picture does not exist. sl@0: */ sl@0: void CMdfVideoDecoderBufferManager::ReturnFrameBufferL(TVideoPicture& aFrameBuffer, CVideoFrameBuffer::TFrameBufferState aState) sl@0: { sl@0: DEBUG_PRINT(_L("Return Frame Buffer from TVideoPicture")); sl@0: sl@0: TInt bufIndex; sl@0: User::LeaveIfError(bufIndex = FindFrameBuffer(aFrameBuffer)); sl@0: // remove from the list of avaible buffers sl@0: CVideoFrameBuffer* frameBuf = iFrameBuffersInUse[bufIndex]; sl@0: frameBuf->UnlockFrameBufferHeap(); sl@0: if (aState == CVideoFrameBuffer::EEmptied) sl@0: { sl@0: DEBUG_PRINT(_L("Added to empty pool")); sl@0: iEmptyFrameBuffers.AppendL(frameBuf); sl@0: } sl@0: else sl@0: { sl@0: DEBUG_PRINT(_L("Added to filled pool")); sl@0: iFilledFrameBuffers.AppendL(frameBuf); sl@0: } sl@0: iFrameBuffersInUse.Remove(bufIndex); sl@0: sl@0: } sl@0: sl@0: void CMdfVideoDecoderBufferManager::ReturnFrameBufferL(CMMFBuffer* aBuffer, sl@0: CVideoFrameBuffer::TFrameBufferState aState, sl@0: TBool aLastBuffer) sl@0: { sl@0: DEBUG_PRINT(_L("Return Frame buffer from CMMFBuffer")); sl@0: TInt bufIndex; sl@0: User::LeaveIfError(bufIndex = FindFrameBuffer(aBuffer)); sl@0: // remove from the list of avaible buffers sl@0: CVideoFrameBuffer* frameBuf = iFrameBuffersInUse[bufIndex]; sl@0: frameBuf->SetLastBuffer(aLastBuffer); sl@0: frameBuf->UnlockFrameBufferHeap(); sl@0: if (aState == CVideoFrameBuffer::EEmptied) sl@0: { sl@0: DEBUG_PRINT(_L("Added to empty pool")); sl@0: iEmptyFrameBuffers.AppendL(frameBuf); sl@0: } sl@0: else sl@0: { sl@0: DEBUG_PRINT(_L("Added to filled pool")); sl@0: iFilledFrameBuffers.AppendL(frameBuf); sl@0: } sl@0: iFrameBuffersInUse.Remove(bufIndex); sl@0: sl@0: } sl@0: sl@0: // private methods sl@0: sl@0: TInt CMdfVideoDecoderBufferManager::FindFrameBuffer(const TVideoPicture& aFrameBuffer) const sl@0: { sl@0: TInt theCount = iFrameBuffersInUse.Count(); sl@0: TInt found = KErrNotFound; sl@0: for(TInt i = 0; i < theCount; i++) sl@0: { sl@0: if(*iFrameBuffersInUse[i] == aFrameBuffer) sl@0: { sl@0: found = i; sl@0: break; sl@0: } sl@0: } sl@0: return found; sl@0: } sl@0: sl@0: sl@0: TInt CMdfVideoDecoderBufferManager::FindFrameBuffer(const CMMFBuffer* aBuffer) const sl@0: { sl@0: TInt theCount = iFrameBuffersInUse.Count(); sl@0: TInt found = KErrNotFound; sl@0: for(TInt i = 0; i < theCount; i++) sl@0: { sl@0: if(*iFrameBuffersInUse[i] == aBuffer) sl@0: { sl@0: found = i; sl@0: break; sl@0: } sl@0: } sl@0: return found; sl@0: } sl@0: sl@0: // end