sl@0: // Copyright (c) 2007-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: /** sl@0: @file sl@0: @internalComponent sl@0: */ sl@0: sl@0: #include sl@0: #include "buffermanager.h" sl@0: #include "videoframebuffer.h" sl@0: #include "rendererutil.h" sl@0: sl@0: /** Constructor for performing 1st stage construction */ sl@0: CRendererBufferManager::CRendererBufferManager(const RChunk& aChunk, TBool aTimed) sl@0: : iChunk(aChunk), sl@0: iTimed(aTimed), sl@0: iAvailBuffers(TVideoFrameBuffer::iOffset), sl@0: iWaitingBuffers(TVideoFrameBuffer::iOffset), sl@0: iWaitingBuffersIter(iWaitingBuffers) sl@0: {} sl@0: sl@0: /** Destructor. */ sl@0: CRendererBufferManager::~CRendererBufferManager() sl@0: { sl@0: if (iTimed) sl@0: { sl@0: iMutex.Close(); sl@0: } sl@0: iAvailBuffers.Reset(); sl@0: iWaitingBuffers.Reset(); sl@0: iBuffers.ResetAndDestroy(); sl@0: iChunk.Close(); sl@0: } sl@0: sl@0: /** Two-phased constructor. */ sl@0: CRendererBufferManager* CRendererBufferManager::NewL(const RSurfaceManager::TSurfaceInfoV01& aSurfaceInfo, const RArray& aBufferOffsets, const RChunk& aChunk, TBool aTimed) sl@0: { sl@0: CRendererBufferManager* self = new (ELeave) CRendererBufferManager(aChunk, aTimed); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aSurfaceInfo, aBufferOffsets); sl@0: CleanupStack::Pop(); // self; sl@0: return self; sl@0: } sl@0: sl@0: /** Constructor for performing 2nd stage construction */ sl@0: void CRendererBufferManager::ConstructL(const RSurfaceManager::TSurfaceInfoV01& aSurfaceInfo, const RArray& aBufferOffsets) sl@0: { sl@0: if (iTimed) sl@0: { sl@0: User::LeaveIfError(iMutex.CreateLocal()); sl@0: } sl@0: sl@0: TUncompressedVideoFormat format = VideoRendererUtil::ConvertUidPixelFormatToUncompressedVideoFormatL(aSurfaceInfo.iPixelFormat); sl@0: sl@0: TVideoFrameBuffer* buffer = NULL; sl@0: for (TInt i = 0; i < aSurfaceInfo.iBuffers; ++i) sl@0: { sl@0: buffer = new (ELeave) TVideoFrameBuffer(format, aSurfaceInfo.iStride, i, iChunk, aBufferOffsets[i]); sl@0: buffer->SetBufferStatus(TVideoFrameBuffer::EAvailable); sl@0: CleanupStack::PushL(buffer); sl@0: iBuffers.AppendL(buffer); sl@0: CleanupStack::Pop(buffer); sl@0: sl@0: iAvailBuffers.AddLast(*buffer); sl@0: } sl@0: } sl@0: sl@0: /** Lock buffer table on timed mode */ sl@0: void CRendererBufferManager::Lock() sl@0: { sl@0: if (iTimed) sl@0: { sl@0: iMutex.Wait(); sl@0: } sl@0: } sl@0: sl@0: /** Unlock buffer table on timed mode */ sl@0: void CRendererBufferManager::Unlock() sl@0: { sl@0: if (iTimed) sl@0: { sl@0: iMutex.Signal(); sl@0: } sl@0: } sl@0: sl@0: /** Get the next available buffer */ sl@0: TVideoFrameBuffer* CRendererBufferManager::NextBuffer() sl@0: { sl@0: Lock(); sl@0: sl@0: TVideoFrameBuffer* buffer = NULL; sl@0: if (!iAvailBuffers.IsEmpty()) sl@0: { sl@0: buffer = iAvailBuffers.First(); sl@0: sl@0: __ASSERT_DEBUG(buffer->BufferStatus() == TVideoFrameBuffer::EAvailable, sl@0: User::Panic(_L("CRBM::NextBuffer"), KErrCorrupt)); sl@0: buffer->SetBufferStatus(TVideoFrameBuffer::EUsedByClient); sl@0: buffer->DblQueLink().Deque(); sl@0: } sl@0: sl@0: Unlock(); sl@0: return buffer; sl@0: } sl@0: sl@0: /** Check if a buffer was previously sent to client */ sl@0: TBool CRendererBufferManager::BufferUsedByClient(TVideoFrameBuffer* aBuffer) sl@0: { sl@0: TVideoFrameBuffer* buffer = iBuffers[aBuffer->BufferId()]; sl@0: if (buffer->BufferStatus() == TVideoFrameBuffer::EUsedByClient && aBuffer == buffer) sl@0: { sl@0: return ETrue; sl@0: } sl@0: return EFalse; sl@0: } sl@0: sl@0: /** Release the buffer for reuse */ sl@0: TBool CRendererBufferManager::ReleaseBuffer(TVideoFrameBuffer* aBuffer) sl@0: { sl@0: TBool released = EFalse; sl@0: Lock(); sl@0: sl@0: if (BufferUsedByClient(aBuffer)) sl@0: { sl@0: // release the buffer if it was previously sent to client sl@0: aBuffer->SetBufferStatus(TVideoFrameBuffer::EAvailable); sl@0: iAvailBuffers.AddLast(*aBuffer); sl@0: released = ETrue; sl@0: } sl@0: sl@0: Unlock(); sl@0: return released; sl@0: } sl@0: sl@0: /** Received notification that buffer become available */ sl@0: void CRendererBufferManager::BufferAvailable(TInt aBufferId) sl@0: { sl@0: Lock(); sl@0: sl@0: TVideoFrameBuffer* buffer = iBuffers[aBufferId]; sl@0: sl@0: __ASSERT_DEBUG(buffer->BufferStatus() == TVideoFrameBuffer::EWaiting || buffer->BufferStatus() == TVideoFrameBuffer::ESubmitted, sl@0: User::Panic(_L("CRBM::BufferAvailable"), KErrCorrupt)); sl@0: sl@0: buffer->SetBufferStatus(TVideoFrameBuffer::EAvailable); sl@0: buffer->DblQueLink().Deque(); sl@0: iAvailBuffers.AddLast(*buffer); sl@0: sl@0: Unlock(); sl@0: } sl@0: sl@0: /** Get the next waiting buffer to submit sl@0: @param aRemoveFromList If true, mark the buffer as submitted and deque from waiting list sl@0: @param aIsLast ETrue on result if the returned buffer is the last buffer in waiting list sl@0: */ sl@0: TVideoFrameBuffer* CRendererBufferManager::WaitingBuffer(TBool aRemoveFromList, TBool& aIsLast) sl@0: { sl@0: Lock(); sl@0: sl@0: TVideoFrameBuffer* buf = NULL; sl@0: if (iWaitingBuffers.IsEmpty() == EFalse) sl@0: { sl@0: buf = iWaitingBuffers.First(); sl@0: sl@0: __ASSERT_DEBUG(buf->BufferStatus() == TVideoFrameBuffer::EWaiting, sl@0: User::Panic(_L("CRBM::WaitingBuffer"), KErrCorrupt)); sl@0: aIsLast = iWaitingBuffers.IsLast(buf); sl@0: sl@0: if (aRemoveFromList) sl@0: { sl@0: buf->SetBufferStatus(TVideoFrameBuffer::ESubmitted); sl@0: buf->DblQueLink().Deque(); sl@0: } sl@0: } sl@0: sl@0: Unlock(); sl@0: return buf; sl@0: } sl@0: sl@0: /** Mark the buffer as submitted and deque from waiting list */ sl@0: void CRendererBufferManager::BufferSubmitted(TVideoFrameBuffer* aBuffer) sl@0: { sl@0: Lock(); sl@0: sl@0: __ASSERT_DEBUG(aBuffer->BufferStatus() == TVideoFrameBuffer::EWaiting, sl@0: User::Panic(_L("CRBM::BufferSubmitted"), KErrArgument)); sl@0: sl@0: aBuffer->SetBufferStatus(TVideoFrameBuffer::ESubmitted); sl@0: aBuffer->DblQueLink().Deque(); sl@0: sl@0: Unlock(); sl@0: } sl@0: sl@0: /** Return ETrue if the waiting list is empty */ sl@0: TBool CRendererBufferManager::WaitingListIsEmpty() sl@0: { sl@0: Lock(); sl@0: sl@0: TBool ret = iWaitingBuffers.IsEmpty(); sl@0: sl@0: Unlock(); sl@0: return ret; sl@0: } sl@0: sl@0: /** sl@0: Mark a buffer as waiting for update and add to waiting list, return ETrue sl@0: if rescheduled is needed (i.e. head of waiting list has changed and the list wasn't empty) */ sl@0: TBool CRendererBufferManager::UpdateBuffer(TVideoFrameBuffer* aBuffer, const TTime& aTime) sl@0: { sl@0: Lock(); sl@0: sl@0: TBool headChanged = EFalse; sl@0: if (BufferUsedByClient(aBuffer)) sl@0: { sl@0: aBuffer->SetBufferStatus(TVideoFrameBuffer::EWaiting); sl@0: aBuffer->SetPresentationTime(aTime); sl@0: sl@0: // add buffer to waiting buffer list according to presentation time sl@0: if (iWaitingBuffers.IsEmpty()) sl@0: { sl@0: iWaitingBuffers.AddLast(*aBuffer); sl@0: } sl@0: else sl@0: { sl@0: TVideoFrameBuffer* buf = iWaitingBuffers.Last(); sl@0: if (aTime >= buf->PresentationTime()) sl@0: { sl@0: iWaitingBuffers.AddLast(*aBuffer); sl@0: } sl@0: else sl@0: { sl@0: // client tried to insert a older frame, search for the right position to insert sl@0: iWaitingBuffersIter.SetToFirst(); sl@0: while ((buf = iWaitingBuffersIter++) != NULL) sl@0: { sl@0: if (aTime < buf->PresentationTime()) sl@0: { sl@0: // Found the slot sl@0: if (iWaitingBuffers.IsFirst(buf)) sl@0: { sl@0: iWaitingBuffers.AddFirst(*aBuffer); sl@0: headChanged = ETrue; sl@0: } sl@0: else sl@0: { sl@0: aBuffer->DblQueLink().AddBefore(&(buf->DblQueLink())); sl@0: } sl@0: } sl@0: } sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: DEBUGPRINT1(_L("CRendererBufferManager::UpdateBuffer receive buffer not usable by client")); sl@0: __ASSERT_DEBUG(EFalse, User::Panic(_L("CRBM::UpdateBuf"), KErrBadHandle)); sl@0: } sl@0: sl@0: Unlock(); sl@0: sl@0: return headChanged; sl@0: }