os/mm/mmswadaptation/videorenderer/src/videorenderer.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/mm/mmswadaptation/videorenderer/src/videorenderer.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,587 @@
     1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +//
    1.18 +
    1.19 +#include "videorenderer.h"
    1.20 +#include "rendererrelay.h"
    1.21 +#include "buffermanager.h"
    1.22 +#include "rendererutil.h"
    1.23 +#include "renderertimer.h"
    1.24 +#include "resourcefilereader.h"
    1.25 +#include "videoframebuffer.h"
    1.26 +
    1.27 +
    1.28 +_LIT(KVideoRendererThreadName, "VideoRendererThread");
    1.29 +_LIT(KResourceFileName, "Z:\\resource\\videorenderer\\videorenderer.rsc");
    1.30 +
    1.31 +const TThreadPriority KSubThreadPriority = EPriorityRealTime;
    1.32 +const TInt KSubThreadStackSize = KDefaultStackSize;	// 0x2000 = 8k
    1.33 +
    1.34 +
    1.35 +
    1.36 +/**
    1.37 +Factory method. Creates a new video renderer instance.
    1.38 +
    1.39 +@param aObserver Video renderer observer
    1.40 +@param aTimed ETrue if CVideoRenderer should handle timing of buffer updates. 
    1.41 +              If ETrue CVideoRenderer launches its own high-priority thread to handle buffer update timing. If EFalse CVideoRenderer requires a CActiveScheduler to be present in calling thread.
    1.42 +@return  A pointer to the newly created CVideoRenderer object.
    1.43 +*/
    1.44 +EXPORT_C CVideoRenderer* CVideoRenderer::NewL(MVideoRendererObserver& aObserver, TBool aTimed)
    1.45 +	{
    1.46 +	CVideoRenderer* self = new (ELeave) CVideoRenderer(aObserver, aTimed);
    1.47 +	CleanupStack::PushL(self);
    1.48 +	self->ConstructL();
    1.49 +	CleanupStack::Pop(self);
    1.50 +	return self;
    1.51 +	}
    1.52 +
    1.53 +/**
    1.54 +Private constructor
    1.55 +@internalComponent
    1.56 +*/
    1.57 +CVideoRenderer::CVideoRenderer(MVideoRendererObserver& aObserver, TBool aTimed)
    1.58 +:iObserver(aObserver), iTimed(aTimed)
    1.59 +	{
    1.60 +	}
    1.61 +
    1.62 +/**
    1.63 +Second phase constructor
    1.64 +@internalComponent
    1.65 +*/
    1.66 +void CVideoRenderer::ConstructL()
    1.67 +	{
    1.68 +	User::LeaveIfError(iSurfaceManager.Open());
    1.69 +
    1.70 +	User::LeaveIfError(iWsSession.Connect());
    1.71 +	
    1.72 +	CResourceFileReader* reader = CResourceFileReader::NewLC(KResourceFileName);
    1.73 +	reader->ReadSupportedFormatL(iSupportedFormat);
    1.74 +
    1.75 +	if (iTimed)
    1.76 +		{
    1.77 +		// Create a high priority thread for timed mode
    1.78 +
    1.79 +		// get timer info for timed mode
    1.80 +		TInt64 defaultDelay;
    1.81 +		TInt64 maxDelay;
    1.82 +		reader->ReadTimerInfoL(defaultDelay, maxDelay);
    1.83 +
    1.84 +		//Get a reference to this thread's heap
    1.85 +		RHeap& thisHeap = User::Heap();
    1.86 +
    1.87 +		//Parameters to send to the sub thread
    1.88 +		TThreadRelayParam param;
    1.89 +		param.iObserver = &iObserver;
    1.90 +		param.iThreadRelay = &iRendererRelay; // return pointer to allow direct calls
    1.91 +
    1.92 +		//Get the id of this thread
    1.93 +		RThread thisThread;
    1.94 +		TThreadId thisThreadId = thisThread.Id();
    1.95 +		param.iMainThreadId = thisThreadId;
    1.96 +
    1.97 +		//Get a request to signal for setup completion
    1.98 +		TRequestStatus setupComplete = KRequestPending;
    1.99 +		param.iSetupComplete = &setupComplete;
   1.100 +		
   1.101 +		//current time and the "this" pointer for a unique key
   1.102 +		_LIT(KFormatString,"%S.%020Lu.%08X");
   1.103 +	   	TName threadName;
   1.104 +		TTime now;
   1.105 +		now.UniversalTime();
   1.106 +		threadName.Format(KFormatString, &KVideoRendererThreadName, now.Int64(), reinterpret_cast<TUint>(this));
   1.107 +
   1.108 +		//Create a new thread using the same heap as this thread
   1.109 +		TInt result = iRendererThread.Create(threadName,
   1.110 +										ThreadCreateFunction,
   1.111 +										KSubThreadStackSize,
   1.112 +										&thisHeap,
   1.113 +										&param);
   1.114 +		User::LeaveIfError(result);
   1.115 +
   1.116 +		//Run the thread under high priority
   1.117 +		iRendererThread.SetPriority(KSubThreadPriority); 
   1.118 +
   1.119 +		//Wait for thread startup to complete
   1.120 +		TRequestStatus threadStatus = KRequestPending;
   1.121 +		iRendererThread.Logon(threadStatus);
   1.122 +
   1.123 +		//Start the thread
   1.124 +		iRendererThread.Resume();
   1.125 +		User::WaitForRequest(threadStatus, setupComplete);
   1.126 +		if(threadStatus != KRequestPending)
   1.127 +			{
   1.128 +			//Thread creation failed
   1.129 +			TInt reason = iRendererThread.ExitReason();
   1.130 +			DEBUGPRINT3(_L("Renderer thread died with type=%d, reason=%d"), iRendererThread.ExitType(), reason);
   1.131 +			User::Leave(reason);
   1.132 +			}
   1.133 +
   1.134 +		// Thread creation was successfull
   1.135 +		TInt error = iRendererThread.LogonCancel(threadStatus);
   1.136 +		User::LeaveIfError(error); // There is no outstanding request
   1.137 +		User::WaitForRequest(threadStatus); // Consume the signal
   1.138 +
   1.139 +		__ASSERT_DEBUG(iRendererRelay != NULL, User::Panic(_L("CVR::ConstructL"), KErrCorrupt));
   1.140 +		iRendererRelay->SetRendererThread(&iRendererThread);
   1.141 +		iRendererRelay->SetTimerInfo(defaultDelay, maxDelay);
   1.142 +		
   1.143 +		iThreadCreated = ETrue;
   1.144 +		User::LeaveIfError(setupComplete.Int());
   1.145 +
   1.146 +		//Create a listener that will monitor the thread
   1.147 +		iRendererThreadUndertaker = CThreadUndertaker::NewL(iRendererThread);
   1.148 +		}
   1.149 +	else
   1.150 +		{
   1.151 +		iRendererRelay = CRendererRelay::NewL(iObserver);
   1.152 +		}
   1.153 +
   1.154 +	CleanupStack::PopAndDestroy(reader);
   1.155 +	}
   1.156 +
   1.157 +/**
   1.158 +Main thread entry point for the video renderer sub-thread.
   1.159 +Create a cleanup stack for the thread and process the codec
   1.160 +inside a trap for cleanup behaviour.
   1.161 +@internalComponent
   1.162 +
   1.163 +@param aPtr Parameters to be used for creating the thread.
   1.164 +@return The error code for thread termination.
   1.165 +*/
   1.166 +TInt CVideoRenderer::ThreadCreateFunction(TAny* aPtr)
   1.167 +	{
   1.168 +	TInt error = KErrNone;
   1.169 +
   1.170 +	// Create a cleanup stack for the thread
   1.171 +	CTrapCleanup* cleanupStack = CTrapCleanup::New();
   1.172 +	if (cleanupStack)
   1.173 +		{
   1.174 +		if(error == KErrNone)
   1.175 +			{
   1.176 +			TRAP(error, ThreadTrapFunctionL(aPtr));
   1.177 +			}
   1.178 +		}
   1.179 +	else
   1.180 +		{
   1.181 +		error = KErrNoMemory;
   1.182 +		}
   1.183 +
   1.184 +	delete cleanupStack;
   1.185 +	return error;
   1.186 +	}
   1.187 +
   1.188 +/**
   1.189 +Function for thread execution. Create an active scheduler for the thread
   1.190 +and start the function call listener. If the thread is successfully created signal
   1.191 +the main thread that the thread creation was successfull.
   1.192 +@internalComponent
   1.193 +
   1.194 +@param aPtr A pointer to a TThreadRelayParam object containing the startup parameters
   1.195 +			for the thread.
   1.196 +*/
   1.197 +void CVideoRenderer::ThreadTrapFunctionL(TAny* aPtr)
   1.198 +	{
   1.199 +	//Create an active scheduler for the thread
   1.200 +	CActiveScheduler* scheduler = new (ELeave) CActiveScheduler;
   1.201 +	CleanupStack::PushL(scheduler);
   1.202 +	CActiveScheduler::Install(scheduler);
   1.203 +
   1.204 +	//Call a Factory function to create a CSubThreadRelay derived object
   1.205 +	TThreadRelayParam* relayParam;
   1.206 +	relayParam = static_cast<TThreadRelayParam*>(aPtr);
   1.207 +
   1.208 +	CRendererThreadRelay* threadRelay = CRendererThreadRelay::NewL(*relayParam->iObserver, relayParam->iMainThreadId);
   1.209 +	CleanupStack::PushL(threadRelay);
   1.210 +	
   1.211 +	//Send a pointer to the sub thread relay back to the main thread
   1.212 +	*relayParam->iThreadRelay = threadRelay;
   1.213 +
   1.214 +	threadRelay->Start();
   1.215 +	threadRelay->SignalSetupComplete(relayParam->iSetupComplete);
   1.216 +
   1.217 +	CActiveScheduler::Start();	
   1.218 +
   1.219 +	CleanupStack::PopAndDestroy(2,scheduler); //threadRelay, scheduler
   1.220 +	}
   1.221 +
   1.222 +/**
   1.223 +Destructor
   1.224 +*/
   1.225 +EXPORT_C CVideoRenderer::~CVideoRenderer()
   1.226 +	{
   1.227 +	iWsSession.Close();
   1.228 +	iSupportedFormat.Close();
   1.229 +	
   1.230 +	// first, stop all active objects that may use any buffers
   1.231 +	if(iThreadCreated)
   1.232 +		{
   1.233 +		delete iRendererThreadUndertaker;
   1.234 +
   1.235 +		// this also delete CRendererThreadRelay
   1.236 +    	TRequestStatus terminateRequest = KRequestPending;
   1.237 +	    iRendererRelay->Terminate(terminateRequest);
   1.238 +    	User::WaitForRequest(terminateRequest);
   1.239 +        iThreadCreated = EFalse;
   1.240 +
   1.241 +        iRendererThread.Close();
   1.242 +		}
   1.243 +	else if (iTimed == EFalse)
   1.244 +		{
   1.245 +		delete iRendererRelay;
   1.246 +		}
   1.247 +	
   1.248 +	// next, close surface if still open
   1.249 +	if (iBufferManager)
   1.250 +		{
   1.251 +		delete iBufferManager;
   1.252 +		iSurfaceManager.CloseSurface(iSurfaceId);
   1.253 +		}
   1.254 +	
   1.255 +	// close the rest
   1.256 +	iSurfaceManager.Close();
   1.257 +	}
   1.258 +
   1.259 +/**
   1.260 +Retrieves the list of supported surface formats from the renderer.
   1.261 +
   1.262 +@param aArray Supported video formats. The renderer will populate the array with supported formats.
   1.263 +@leave KErrNoMemory Out of memory
   1.264 +*/
   1.265 +EXPORT_C void CVideoRenderer::GetSupportedFormatsL(RArray<TUncompressedVideoFormat>& aArray)
   1.266 +	{
   1.267 +	aArray.Reset(); // first clear the old data
   1.268 +	
   1.269 +	TInt count = iSupportedFormat.Count();
   1.270 +	for (TInt i = 0; i < count; ++i)
   1.271 +		{
   1.272 +		aArray.AppendL(iSupportedFormat[i]);
   1.273 +		}
   1.274 +	}
   1.275 +
   1.276 +/**
   1.277 +Creates a new surface for video rendering and registers it with the windows server for all displays.
   1.278 +
   1.279 +@param aSize Surface size in pixels
   1.280 +@param aNumBuffers The minimum number of buffers required. The renderer can create a surface with more buffers.
   1.281 +@param aFormat Surface data format
   1.282 +@param aSurface Output: Surface ID for the new surface
   1.283 +
   1.284 +@leave KErrNoMemory Out of memory
   1.285 +@leave KErrNotSupported The requested parameters are not supported
   1.286 +@leave KErrInUse Too many video surfaces are already in use
   1.287 +*/
   1.288 +EXPORT_C void CVideoRenderer::CreateSurfaceL(const TSize& aSize, TInt aNumBuffers, const TUncompressedVideoFormat& aFormat, TSurfaceId& aSurface)
   1.289 +	{
   1.290 +	if (iBufferManager != NULL)
   1.291 +		{
   1.292 +		User::Leave(KErrInUse);
   1.293 +		}
   1.294 +	else if (aNumBuffers <= 0)
   1.295 +		{
   1.296 +		User::Leave(KErrNotSupported);
   1.297 +		}
   1.298 +	
   1.299 +	RSurfaceManager::TSurfaceCreationAttributesBuf attribBuf;
   1.300 +	RSurfaceManager::TSurfaceCreationAttributes& attrib = attribBuf();
   1.301 +	attrib.iSize = aSize;
   1.302 +	attrib.iBuffers = aNumBuffers;
   1.303 +	attrib.iPixelFormat = VideoRendererUtil::ConvertUncompressedVideoFormatToUidPixelFormatL(aFormat);
   1.304 +	attrib.iStride = aSize.iWidth * VideoRendererUtil::BytesPerPixelL(attrib.iPixelFormat);
   1.305 +	attrib.iOffsetToFirstBuffer = 0;
   1.306 +	attrib.iAlignment = 4;
   1.307 +	attrib.iContiguous = ETrue;
   1.308 +	attrib.iMappable = ETrue;
   1.309 +
   1.310 +	User::LeaveIfError(iSurfaceManager.CreateSurface(attribBuf, iSurfaceId));
   1.311 +	
   1.312 +	// Push surfaceId to cleanup stack in case buffer manager constructor leave.
   1.313 +	// SurfaceId needs to be pushed because the renderer state is inconsistent 
   1.314 +	// if buffer manager creation leave
   1.315 +	CleanupReleasePushL(*this);
   1.316 +	
   1.317 +	RChunk chunk;
   1.318 +	User::LeaveIfError(iSurfaceManager.MapSurface(iSurfaceId, chunk));
   1.319 +	CleanupClosePushL(chunk);
   1.320 +	
   1.321 +	RSurfaceManager::TInfoBuf infoBuf;
   1.322 +	User::LeaveIfError(iSurfaceManager.SurfaceInfo(iSurfaceId, infoBuf));
   1.323 +
   1.324 +	// Register must take place after 'this' pushed onto cleanupstack just in case 
   1.325 +	// function leaves after registration
   1.326 +	RegisterSurfaceL();
   1.327 +	
   1.328 +	// prepare the renderer relay
   1.329 +	RSurfaceManager::TSurfaceInfoV01 info = infoBuf();
   1.330 +	if (iTimed)
   1.331 +		{
   1.332 +		TRequestStatus updateRequest = KRequestPending;
   1.333 +		TRequestStatus logonRequest = KRequestPending;
   1.334 +
   1.335 +		// While a function call is in progress this thread is suspended
   1.336 +		// and the undertaker will not catch panics, listen for these here
   1.337 +		iRendererThread.Logon(logonRequest);
   1.338 +
   1.339 +		// Send request to renderer thread
   1.340 +		iRendererRelay->PrepareL(iSurfaceId, info.iBuffers, &updateRequest);
   1.341 +		User::WaitForRequest(logonRequest, updateRequest);
   1.342 +
   1.343 +		if(logonRequest != KRequestPending)
   1.344 +			{
   1.345 +			// renderer thread got panic from surface update session, so panic client
   1.346 +			TInt reason = iRendererThread.ExitReason();
   1.347 +			TExitCategoryName category = iRendererThread.ExitCategory();
   1.348 +			User::Panic(category,reason);
   1.349 +			}
   1.350 +
   1.351 +		// Thread is still alive and well
   1.352 +		iRendererThread.LogonCancel(logonRequest);
   1.353 +		User::WaitForRequest(logonRequest); // Consume the signal
   1.354 +		
   1.355 +		// leave if memory allocation failed in renderer thread
   1.356 +		User::LeaveIfError(updateRequest.Int());
   1.357 +
   1.358 +		__ASSERT_DEBUG(updateRequest != KRequestPending, User::Panic(_L("CVR::UpdateBuffer"), KErrCorrupt));
   1.359 +		}
   1.360 +	else
   1.361 +		{
   1.362 +		iRendererRelay->PrepareL(iSurfaceId, info.iBuffers, NULL);
   1.363 +		}
   1.364 +	
   1.365 +	// find the buffer offsets
   1.366 +	RArray<TInt> offsets;
   1.367 +	CleanupClosePushL(offsets);
   1.368 +	
   1.369 +	TInt offsetInChunk = 0;
   1.370 +	for (TInt i = 0; i < info.iBuffers; ++i)
   1.371 +		{
   1.372 +		User::LeaveIfError(iSurfaceManager.GetBufferOffset(iSurfaceId, i, offsetInChunk));
   1.373 +		offsets.AppendL(offsetInChunk);
   1.374 +		}
   1.375 +	
   1.376 +	// finally, create buffer manager
   1.377 +	iBufferManager = CRendererBufferManager::NewL(info, offsets, chunk, iTimed);
   1.378 +
   1.379 +	CleanupStack::PopAndDestroy(&offsets);
   1.380 +	CleanupStack::Pop(&chunk);
   1.381 +	CleanupStack::Pop(this); // surfaceId
   1.382 +	
   1.383 +	aSurface = iSurfaceId;
   1.384 +	iRendererRelay->SetBufferManager(iBufferManager);
   1.385 +	
   1.386 +	for (TInt i = 0; i < info.iBuffers; ++i)
   1.387 +		{
   1.388 +		// notify observer once for each buffer created
   1.389 +		iObserver.MvroVideoBufferAvailable();
   1.390 +		}
   1.391 +	}
   1.392 +
   1.393 +/** 
   1.394 + Helper function to unregister and release surfaceId when CreateSurfaceL leave
   1.395 + @internalComponent
   1.396 + */
   1.397 +void CVideoRenderer::Release()
   1.398 +	{
   1.399 +	UnregisterSurface();
   1.400 +	iSurfaceManager.CloseSurface(iSurfaceId);
   1.401 +	}
   1.402 +
   1.403 +/** 
   1.404 + Helper function to register surfaces for all displays
   1.405 + @internalComponent
   1.406 + */
   1.407 +void CVideoRenderer::RegisterSurfaceL()
   1.408 +	{
   1.409 +	TInt screens = iWsSession.NumberOfScreens();
   1.410 +	TInt error;
   1.411 +	
   1.412 +	for(TInt i=0; i<screens; i++)
   1.413 +		{
   1.414 +		error = iWsSession.RegisterSurface(i, iSurfaceId);
   1.415 +		User::LeaveIfError(error);
   1.416 +		}
   1.417 +	}
   1.418 +
   1.419 +/** 
   1.420 + Helper function to unregister surafces for all displays
   1.421 + @internalComponent
   1.422 + */
   1.423 +void CVideoRenderer::UnregisterSurface()
   1.424 +	{
   1.425 +	TInt screens = iWsSession.NumberOfScreens();
   1.426 +	
   1.427 +	for(TInt i=0; i<screens; i++)
   1.428 +		{
   1.429 +		iWsSession.UnregisterSurface(i, iSurfaceId);
   1.430 +		}
   1.431 +	}
   1.432 +	
   1.433 +/**
   1.434 +Destroys a surface previously created with CreateSurfaceL() and unregisters it with the windows
   1.435 +server for all displays. The client must stop using the surface before calling this method. All
   1.436 +buffers retrieved with NextBuffer() will become invalid and can no longer be used.
   1.437 +
   1.438 +@param aSurface The surface to delete
   1.439 +*/
   1.440 +EXPORT_C void CVideoRenderer::DestroySurface(const TSurfaceId& aSurface)
   1.441 +	{
   1.442 +	if (aSurface != iSurfaceId || iBufferManager == NULL)
   1.443 +		{
   1.444 +		// surface id is not expected or surface has not been created
   1.445 +		return;
   1.446 +		}
   1.447 +	
   1.448 +	// cancel the active objects that use the surface
   1.449 +	if (iTimed)
   1.450 +		{
   1.451 +		TRequestStatus request = KRequestPending;
   1.452 +		TRequestStatus logonRequest = KRequestPending;
   1.453 +
   1.454 +		// While a function call is in progress this thread is suspended
   1.455 +		// and the undertaker will not catch panics, listen for these here
   1.456 +		iRendererThread.Logon(logonRequest);
   1.457 +
   1.458 +		// Send request to renderer thread
   1.459 +		iRendererRelay->DestroySurface(&request);
   1.460 +		User::WaitForRequest(logonRequest, request);
   1.461 +
   1.462 +		if(logonRequest != KRequestPending)
   1.463 +			{
   1.464 +			// renderer thread got panic from surface update session, so panic client
   1.465 +			TInt reason = iRendererThread.ExitReason();
   1.466 +			TExitCategoryName category = iRendererThread.ExitCategory();
   1.467 +			User::Panic(category,reason);
   1.468 +			}
   1.469 +
   1.470 +		// Thread is still alive and well
   1.471 +		iRendererThread.LogonCancel(logonRequest);
   1.472 +		User::WaitForRequest(logonRequest); // Consume the signal
   1.473 +
   1.474 +		__ASSERT_DEBUG(request != KRequestPending, User::Panic(_L("CVR::DestroySurface"), KErrCorrupt));
   1.475 +		}
   1.476 +	else
   1.477 +		{
   1.478 +		iRendererRelay->DestroySurface(NULL);
   1.479 +		}
   1.480 +
   1.481 +	UnregisterSurface();
   1.482 +	
   1.483 +	delete iBufferManager;
   1.484 +	iBufferManager = NULL;
   1.485 +	iRendererRelay->SetBufferManager(NULL);
   1.486 +	
   1.487 +	TInt err = iSurfaceManager.CloseSurface(iSurfaceId);
   1.488 +	DEBUGPRINT2(_L("RSurfaceManager::CloseSurface returned with %d"), err);
   1.489 +	}
   1.490 +
   1.491 +/**
   1.492 +Retrieves the next free buffer from the renderer. The client can write data to 
   1.493 +the buffer and update it to the screen using UpdateBuffer(). The buffer will 
   1.494 +remain accessible to the client until it returns it to the renderer with 
   1.495 +UpdateBuffer() or ReleaseBuffer(), the surface is destroyed (DestroySurface()), 
   1.496 +or the renderer object is deleted.
   1.497 +
   1.498 +If no free buffers are available the client should wait for a 
   1.499 +MvroVideoBufferAvailable() callback instead of polling for free buffers continuously.
   1.500 +
   1.501 +@return A pointer to the free buffer, or NULL if no free buffers are available.
   1.502 +*/
   1.503 +EXPORT_C TVideoFrameBuffer* CVideoRenderer::NextBuffer()
   1.504 +	{
   1.505 +	if (iBufferManager)
   1.506 +		{
   1.507 +		return iBufferManager->NextBuffer();
   1.508 +		}
   1.509 +	
   1.510 +	// surface had not been created, return null
   1.511 +	return NULL;
   1.512 +	}
   1.513 +
   1.514 +/**
   1.515 +Updates a surface buffer on the display. The buffer must have previously been 
   1.516 +retrieved with NextBuffer() and must contain a valid video picture. The 
   1.517 +renderer uses statistics from previous video frame rendering times to render 
   1.518 +the picture as close to the requested presentation time as possible.
   1.519 +
   1.520 +@param aBuffer The buffer to update
   1.521 +@param aPresentationTime The system clock time when the buffer should be 
   1.522 +			visible on the display. If the time is zero the renderer will 
   1.523 +			update the buffer as soon as possible without further synchronization.
   1.524 +*/
   1.525 +EXPORT_C void CVideoRenderer::UpdateBuffer(TVideoFrameBuffer* aBuffer, const TTime& aPresentationTime)
   1.526 +	{
   1.527 +	__ASSERT_DEBUG(aBuffer != NULL, User::Panic(_L("CVR::UpdateBuffer"), KErrArgument));
   1.528 +	DEBUGPRINT3(_L("CVideoRenderer::UpdateBuffer entered with bufId=%d, aPresentationTime=%Ld"), 
   1.529 +				aBuffer->BufferId() , aPresentationTime.Int64());
   1.530 +
   1.531 +	// ignore request if a surface has not been created or has been destroyed
   1.532 +	if (!iBufferManager)
   1.533 +		{
   1.534 +		return;
   1.535 +		}
   1.536 +
   1.537 +	if (iTimed)
   1.538 +		{
   1.539 +		TRequestStatus updateRequest = KRequestPending;
   1.540 +		TRequestStatus logonRequest = KRequestPending;
   1.541 +
   1.542 +		// While a function call is in progress this thread is suspended
   1.543 +		// and the undertaker will not catch panics, listen for these here
   1.544 +		iRendererThread.Logon(logonRequest);
   1.545 +
   1.546 +		// Send request to renderer thread
   1.547 +		iRendererRelay->UpdateBuffer(aBuffer, aPresentationTime, &updateRequest);
   1.548 +		User::WaitForRequest(logonRequest, updateRequest);
   1.549 +
   1.550 +		if(logonRequest != KRequestPending)
   1.551 +			{
   1.552 +			// renderer thread got panic from surface update session, so panic client
   1.553 +			TInt reason = iRendererThread.ExitReason();
   1.554 +			TExitCategoryName category = iRendererThread.ExitCategory();
   1.555 +			User::Panic(category,reason);
   1.556 +			}
   1.557 +
   1.558 +		// Thread is still alive and well
   1.559 +		iRendererThread.LogonCancel(logonRequest);
   1.560 +		User::WaitForRequest(logonRequest); // Consume the signal
   1.561 +
   1.562 +		__ASSERT_DEBUG(updateRequest != KRequestPending, User::Panic(_L("CVR::UpdateBuffer"), KErrCorrupt));
   1.563 +		}
   1.564 +	else
   1.565 +		{
   1.566 +		iRendererRelay->UpdateBuffer(aBuffer, aPresentationTime, NULL);
   1.567 +		}
   1.568 +	}
   1.569 +
   1.570 +/**
   1.571 +Releases a buffer without updating it to the display.
   1.572 +The buffer must have previously been retrieved with NextBuffer() and 
   1.573 +UpdateBuffer() is not called yet, otherwise the release request is ignored.
   1.574 +
   1.575 +@param aBuffer The buffer to release
   1.576 +*/
   1.577 +EXPORT_C void CVideoRenderer::ReleaseBuffer(TVideoFrameBuffer* aBuffer)
   1.578 +	{
   1.579 +	// ignore if if a surface has not been created or has beed destroyed
   1.580 +	if (!iBufferManager || !aBuffer)
   1.581 +		{
   1.582 +		return;
   1.583 +		}
   1.584 +
   1.585 +	if (iBufferManager->ReleaseBuffer(aBuffer))
   1.586 +		{
   1.587 +		// a buffer is releaseed, notify observer
   1.588 +		iObserver.MvroVideoBufferAvailable();
   1.589 +		}
   1.590 +	}