os/mm/mmplugins/mmfwplugins/src/Plugin/Controller/Video/AviPlayController/aviplaycontroller.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 
    17 #include "aviplaycontroller.h"
    18 
    19 #ifdef SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
    20 #include "srtreader.h"
    21 #include "mmfdevsubtitle.h"
    22 #endif //SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
    23 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
    24 #include <mmf/common/mmfvideoenums.h>
    25 #endif
    26 	
    27 const TInt KTestBufferSize = 0x10000; 
    28 _LIT8(KXvidDecoderMimeType,"video/mp4v-es");
    29 _LIT8(KAviVideoCodec,"XVID");
    30 
    31 #ifdef SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
    32 _LIT(KSrtExtension, "srt");
    33 _LIT(KSrtDecoder, "srtdecoder");
    34 #endif //SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
    35 
    36 
    37 //Table that maps given samplerate with the MMF samplerate
    38 const TSampleRateTable KRateLookup[]=
    39 								 {
    40 									{96000,EMMFSampleRate96000Hz},
    41         							{88200,EMMFSampleRate88200Hz},
    42                    					{48000,EMMFSampleRate48000Hz},
    43 			                   		{44100,EMMFSampleRate44100Hz},
    44 				                  	{32000,EMMFSampleRate32000Hz},
    45 				                  	{22050,EMMFSampleRate22050Hz},
    46 				                  	{16000,EMMFSampleRate16000Hz},
    47 				                  	{11025,EMMFSampleRate11025Hz},
    48 				                  	{8000, EMMFSampleRate8000Hz}
    49                    				 };
    50 
    51 
    52 //This method generates a panic internal to this dll.
    53 void CAviPlayController::Panic(TInt aPanicCode)
    54 	{
    55 	_LIT(KAviPlayControllerPanicCategory, "AviPlayController");
    56 	User::Panic(KAviPlayControllerPanicCategory, aPanicCode);
    57 	}
    58 
    59 	
    60 //This function creates an object of CAviPlayController.
    61 CAviPlayController* CAviPlayController::NewL()
    62 	{
    63     CAviPlayController* self = new(ELeave)CAviPlayController();
    64 	CleanupStack::PushL(self);
    65 	self->ConstructL();
    66 	CleanupStack::Pop(self);
    67 	return self;
    68 	}
    69 
    70 
    71 //Default Constructor of CAviPlayController
    72 CAviPlayController::CAviPlayController() :
    73 	iVideoSurfaceSupport(NULL)
    74 	{
    75 	
    76 	}
    77 
    78 
    79 //Destructor of CAviPlayController.
    80 CAviPlayController::~CAviPlayController()
    81 	{
    82 #ifdef SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
    83 	delete iSrtReader;
    84 	delete iDevSubtitle;
    85 #endif //SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
    86 
    87 	iDisplayRegion.Close();
    88 	iDerivedClipRegion.Close();
    89 	delete iAviReader;
    90 	delete iDevVideoPlay;
    91 	delete iMessage;
    92 	delete iEventHandler;
    93 	delete iScreenGc;
    94 	delete iScreenDev;
    95 	RFbsSession::Disconnect();
    96 	}
    97 
    98 //This constructs the custom command parsers of CAviPlayController.
    99 void CAviPlayController::ConstructL()
   100 	{
   101 	CMMFVideoPlayControllerCustomCommandParser* vidPlayConParser = CMMFVideoPlayControllerCustomCommandParser::NewL(*this);
   102 	CleanupStack::PushL(vidPlayConParser);
   103 	AddCustomCommandParserL(*vidPlayConParser);
   104 	CleanupStack::Pop(vidPlayConParser);
   105 	
   106 	CMMFVideoControllerCustomCommandParser* vidConParser = CMMFVideoControllerCustomCommandParser::NewL(*this);
   107 	CleanupStack::PushL(vidConParser);
   108 	AddCustomCommandParserL(*vidConParser);
   109 	CleanupStack::Pop(vidConParser);
   110 
   111 	CMMFAudioPlayDeviceCustomCommandParser* audPlayDevParser = CMMFAudioPlayDeviceCustomCommandParser::NewL(*this);
   112 	CleanupStack::PushL(audPlayDevParser);
   113 	AddCustomCommandParserL(*audPlayDevParser);
   114 	CleanupStack::Pop(audPlayDevParser);
   115 
   116 	CMMFResourceNotificationCustomCommandParser* notiParser = CMMFResourceNotificationCustomCommandParser::NewL(*this);
   117 	CleanupStack::PushL(notiParser);
   118 	AddCustomCommandParserL(*notiParser);
   119 	CleanupStack::Pop(notiParser);//audio resource Notification Parser
   120 	
   121 	CMMFVideoSetInitScreenCustomCommandParser* vidScrDevParser = CMMFVideoSetInitScreenCustomCommandParser::NewL(*this);
   122 	CleanupStack::PushL(vidScrDevParser);
   123 	AddCustomCommandParserL(*vidScrDevParser);
   124 	CleanupStack::Pop(vidScrDevParser);
   125 
   126 	CMMFVideoPlayControllerExtCustomCommandParser* vidPlayExtParser = CMMFVideoPlayControllerExtCustomCommandParser::NewL(*this);
   127 	CleanupStack::PushL(vidPlayExtParser);
   128 	AddCustomCommandParserL(*vidPlayExtParser);
   129 	CleanupStack::Pop(vidPlayExtParser);
   130 
   131 #ifdef SYMBIAN_BUILD_GCE	
   132 	CMMFVideoPlaySurfaceSupportCustomCommandParser* vidPlaySurfaceSupParser = CMMFVideoPlaySurfaceSupportCustomCommandParser::NewL(*this);
   133 	CleanupStack::PushL(vidPlaySurfaceSupParser);
   134 	AddCustomCommandParserL(*vidPlaySurfaceSupParser);
   135 	CleanupStack::Pop(vidPlaySurfaceSupParser);
   136 #endif // SYMBIAN_BUILD_GCE
   137 
   138 #ifdef SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
   139 	CMMFVideoPlaySubtitleSupportCustomCommandParser * vidPlaySubtitleSupParser = CMMFVideoPlaySubtitleSupportCustomCommandParser::NewL(*this);
   140 	CleanupStack::PushL(vidPlaySubtitleSupParser);
   141 	AddCustomCommandParserL(*vidPlaySubtitleSupParser);
   142 	CleanupStack::Pop(vidPlaySubtitleSupParser);
   143 #endif //SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
   144 
   145 	iEventHandler = new(ELeave) CSourceSinkEventHandler(*this);
   146 	iAudioEnabled = EFalse;
   147 	User::LeaveIfError(RFbsSession::Connect());
   148 	}
   149 
   150 
   151 //Adds a data source to the controller
   152 void CAviPlayController::AddDataSourceL(MDataSource& aDataSource)
   153 	{
   154 	if (iState != EStopped) 
   155 		{
   156 		User::Leave(KErrNotReady);
   157 		}
   158 	if (iClip)
   159 		{
   160 		User::Leave(KErrAlreadyExists);
   161 		}
   162 	if (aDataSource.DataSourceType()==KUidMmfFileSource)
   163 		{
   164 		iClip = static_cast<CMMFFile*>(&aDataSource);
   165 		iAviReader = CAviReader::NewL(*iClip,*this);
   166 		User::LeaveIfError(iClip->SourceThreadLogon(*iEventHandler));
   167 		iAviReader->AudioEnabled(iAudioEnabled);
   168 		}
   169 	else 
   170 		{
   171 		User::Leave(KErrNotSupported);
   172 		}
   173 	TMMFEvent controllerEvent;
   174 	controllerEvent.iEventType = KMMFEventCategoryVideoOpenComplete;
   175 	controllerEvent.iErrorCode = KErrNone;
   176 	DoSendEventToClient(controllerEvent);		
   177 	}
   178 
   179  
   180 //Adds a data sink to the controller
   181 void CAviPlayController::AddDataSinkL(MDataSink& aDataSink)
   182 	{
   183 	if (iState != EStopped) 
   184     	{
   185     	User::Leave(KErrNotReady);	
   186     	}
   187     if(iDevSound)
   188     	{
   189     	User::Leave(KErrAlreadyExists);
   190     	}
   191     if (aDataSink.DataSinkType()!=KUidMmfAudioOutput) 
   192     	{
   193     	User::Leave(KErrNotSupported);	
   194     	}
   195 	MMMFAudioOutput* audioOutput = static_cast<MMMFAudioOutput*>(&aDataSink);
   196     User::LeaveIfError(audioOutput->SinkThreadLogon(*iEventHandler));
   197     iDevSound = &(audioOutput->SoundDevice());
   198 	iDevSound->SetPrioritySettings(iPrioritySettings);
   199 	if (IsSecureDrmModeL())
   200 		{
   201 		User::LeaveIfError(iDevSound->SetClientThreadInfo(ClientThreadIdL()));
   202 		}
   203 
   204 	delete iScreenDev;
   205 	iScreenDev = NULL;
   206 	TRAPD(err, iScreenDev = CFbsScreenDevice::NewL(iScreenNumber,EColor16MA));
   207 	if (err == KErrNotSupported)
   208 		{
   209 		TRAP(err, iScreenDev = CFbsScreenDevice::NewL(iScreenNumber,EColor16M));
   210 		}
   211 	if (err == KErrNotSupported)
   212 		{
   213 		TRAP(err, iScreenDev = CFbsScreenDevice::NewL(iScreenNumber,EColor64K));
   214 		}
   215 	if (err == KErrNotSupported)
   216 		{
   217 		TRAP(err, iScreenDev = CFbsScreenDevice::NewL(iScreenNumber,EColor4K));
   218 		}
   219 	if (err == KErrNotSupported)
   220 		{
   221 		TRAP(err, iScreenDev = CFbsScreenDevice::NewL(iScreenNumber,EColor256));
   222 		}
   223 	if (err == KErrNotSupported)
   224 		{
   225 		TRAP(err, iScreenDev = CFbsScreenDevice::NewL(iScreenNumber,EColor16MAP));
   226 		}
   227 				
   228 	User::LeaveIfError(err);
   229 	delete iScreenGc;
   230 	iScreenGc = NULL;
   231 	User::LeaveIfError(iScreenDev->CreateContext(iScreenGc));
   232 	iScreenGc->SetPenColor(KRgbBlack);
   233 	iScreenGc->SetBrushColor(KRgbWhite);
   234 	iScreenGc->SetBrushStyle(CGraphicsContext::ESolidBrush);
   235 	delete iDevVideoPlay;
   236 	iDevVideoPlay = NULL;
   237 	iDevVideoPlay = CMMFDevVideoPlay::NewL(*this);
   238 	iVideoDecoderInitialized = EFalse;
   239 	}
   240 
   241 
   242 //Removes the data source from the controller
   243 void CAviPlayController::RemoveDataSourceL(MDataSource& aDataSource)
   244 	{
   245 	if (iState != EStopped) 
   246     	{
   247     	User::Leave(KErrNotReady);	
   248     	}
   249    	if (!iClip)
   250     	{
   251     	User::Leave(KErrNotReady);
   252     	}
   253     if (iClip != &aDataSource) 
   254 	 	{
   255     	User::Leave(KErrArgument);
   256     	}
   257     else
   258     	{
   259     	delete iAviReader;
   260     	iAviReader = NULL;
   261     	iClip = NULL;
   262    		}
   263 	}
   264 
   265 
   266 //Removes the data sink from the controller
   267 void CAviPlayController::RemoveDataSinkL(MDataSink& aDataSink)
   268 	{
   269 	if ((!iDevSound) || (iState!= EStopped))
   270 		{
   271     	User::Leave(KErrNotReady);
   272     	}
   273 	if (aDataSink.DataSinkType() !=	KUidMmfAudioOutput) 
   274 		{
   275 	   	User::Leave(KErrNotSupported);	
   276 	   	}
   277 	MMMFAudioOutput* audioOutput = static_cast<MMMFAudioOutput*>(&aDataSink);
   278 	CMMFDevSound& devSound = audioOutput->SoundDevice();
   279 	if (iDevSound != &devSound) 
   280 		{
   281 		User::Leave(KErrArgument);
   282 		}
   283 	else
   284 		{
   285 		iDevSound = NULL;
   286 		}
   287 	delete iDevVideoPlay;
   288    	iDevVideoPlay = NULL;
   289 	delete iScreenDev;
   290 	iScreenDev = NULL;
   291 	}
   292 
   293 
   294 //Resets the controller
   295 void CAviPlayController::ResetL()
   296 	{
   297 	StopL();
   298 	iDevSound = NULL;
   299 	delete iDevVideoPlay;
   300    	iDevVideoPlay = NULL;
   301     iClip=NULL;
   302     delete iAviReader;
   303     iAviReader = NULL;
   304     delete iMessage;
   305     iMessage = NULL;
   306 	}	
   307 
   308 
   309 //Primes the controller
   310 void CAviPlayController::PrimeL(TMMFMessage& aMessage)
   311 	{
   312 	if (iState != EStopped)  
   313 		{
   314 		User::Leave( KErrNotReady );	
   315 		}
   316 	if (!iClip)
   317 		{
   318 		User::Leave(KErrNotReady);
   319 		}
   320 	if(iAudioEnabled)
   321     	{
   322     	if(!iDevSound)
   323     		{
   324     		User::Leave(KErrNotReady);
   325     		}
   326     	}
   327     __ASSERT_ALWAYS((!iMessage),Panic(EBadCall));	
   328     iMessage = CMMFMessageHolder::NewL(aMessage);	
   329 	TRAPD(err,StartPrimeL());
   330 	if(err != KErrNone)
   331 		{
   332 		SendErrorToClient(err);
   333 		}
   334 	}
   335 	
   336 
   337 void CAviPlayController::PrimeL()
   338     {
   339     Panic(EBadCall);
   340     }
   341 	
   342 
   343 //Primes the controller
   344 void CAviPlayController::StartPrimeL()
   345 	{
   346 	CheckAviReaderPresentL();
   347 	CheckDevVideoPresentL();
   348     iAviReader->AudioEnabled(iAudioEnabled);
   349     iClip->SourcePrimeL();
   350     // Initialise Devsound
   351  	if (iAudioEnabled)
   352 		{
   353 		iDevSound->InitializeL(*this, EMMFStatePlaying);
   354 	  	}
   355 	if(!iVideoDecoderInitialized)
   356 		{
   357 		if (!iVideoSurfaceSupport)
   358 			{
   359 			if (LocateDecoderL(EFalse))
   360 				{
   361 				// Set the video destination as Screen.This will leave if the
   362 				// plug-in does not support DSA.
   363 				iDevVideoPlay->SetVideoDestScreenL(ETrue);
   364 				// Initialize devvideoPlay
   365 				iDevVideoPlay->Initialize();
   366 				}
   367 			else
   368 				{
   369 				// Inform client if we couldn't find a suitable decoder.
   370 				SendErrorToClient(KErrNotFound);
   371 				}
   372 			}
   373 		else
   374 			{
   375 			// Decoder already located, done in UseSurfaces
   376 			iDevVideoPlay->Initialize();
   377 			}
   378 		}
   379 	else
   380 		{
   381 		if(iAudioEnabled)
   382 			{
   383 			iDevVideoInitialized = ETrue;
   384 			}
   385 		else
   386 			{
   387 			if (iMessage)
   388 				{
   389 				iMessage->Complete(KErrNone);
   390 				delete iMessage;
   391 				iMessage = NULL;
   392 				}
   393 			}
   394 		
   395 		iState = EPrimed;
   396  		}
   397 	}
   398 
   399 TBool CAviPlayController::LocateDecoderL(TBool aUseSurfaces)
   400 	{
   401 	// Find the Decoder
   402  	RArray<TUid> foundDecodersArray;
   403 	CleanupClosePushL(foundDecodersArray);
   404 	iDevVideoPlay->FindDecodersL(KXvidDecoderMimeType,
   405 								 0, //  post-processing
   406 									//  support is not needed
   407 								 foundDecodersArray,
   408 								 EFalse);
   409 	TBool suitableDecoderFound = EFalse;
   410 	if(foundDecodersArray.Count() > 0)
   411 		{
   412 		TUncompressedVideoFormat reqOutFormat;
   413 		// Prefer RGB over YUV in case of graphics surfaces.
   414 		if (aUseSurfaces)
   415 			{
   416 			reqOutFormat.iDataFormat = ERgbRawData;	
   417 			reqOutFormat.iRgbFormat = ERgb32bit888;
   418 			}
   419 		else
   420 			{
   421 			reqOutFormat.iDataFormat = ERgbFbsBitmap;	
   422 			reqOutFormat.iRgbFormat = EFbsBitmapColor16M;
   423 			}
   424 		
   425 		// Here, we pick a decoder that can handle the output format
   426 		// required
   427 		suitableDecoderFound =
   428 			SelectFirstSuitableDecoderL(foundDecodersArray, reqOutFormat, aUseSurfaces);
   429 		}
   430 
   431 	CleanupStack::PopAndDestroy(&foundDecodersArray);
   432 	return suitableDecoderFound;
   433 	}
   434 	
   435 
   436 // Selection of a suitable decoder based on the output format required
   437 
   438 TBool CAviPlayController::SelectFirstSuitableDecoderL(
   439 	const RArray<TUid>& aDecodersArray,
   440 	const TUncompressedVideoFormat& aRequiredOutputFormat,
   441 #ifdef SYMBIAN_BUILD_GCE
   442 	TBool aUseSurfaces
   443 #else
   444 	TBool /* aUseSurfaces */
   445 #endif // SYMBIAN_BUILD_GCE
   446 	)
   447 	{
   448 	RArray<TUncompressedVideoFormat> outputFormatsArray;
   449 	CleanupClosePushL(outputFormatsArray);
   450 	TBool suitableDecoderFound = EFalse;
   451 	TInt numDecoders = aDecodersArray.Count();
   452 	for (TInt i = 0; !suitableDecoderFound && i < numDecoders; i++)
   453 		{
   454 		iDecoderDeviceId = iDevVideoPlay->SelectDecoderL(aDecodersArray[i]);
   455 		
   456 		#ifdef SYMBIAN_BUILD_GCE	
   457 			if (aUseSurfaces)
   458 				{
   459 				// try to access the interface for video surfaces in dev video
   460 				iVideoSurfaceSupport = static_cast<MMMFVideoSurfaceSupport*>(iDevVideoPlay->CustomInterface(iDecoderDeviceId, KUidMMFVideoSurfaceSupport));
   461 				
   462 				if (!iVideoSurfaceSupport)
   463 					{
   464 					continue;
   465 					}
   466 				}
   467 		#endif // SYMBIAN_BUILD_GCE
   468 		
   469 		iDevVideoPlay->GetOutputFormatListL(iDecoderDeviceId,
   470 											outputFormatsArray);
   471 		if (outputFormatsArray.Find(aRequiredOutputFormat) !=
   472 			KErrNotFound)
   473 			{
   474 			iDevVideoPlay->SetOutputFormatL(iDecoderDeviceId,
   475 											aRequiredOutputFormat);
   476 				
   477 #ifdef SYMBIAN_ENABLE_MMF_MULTISCREEN_SUPPORT
   478 			CVideoDecoderInfo* pCVideoDecoderInfo =
   479 				iDevVideoPlay->VideoDecoderInfoLC(aDecodersArray[i]);
   480 			RArray<TInt> supportedScreensArray;
   481 			CleanupClosePushL(supportedScreensArray);
   482 			pCVideoDecoderInfo->GetSupportedScreensL(supportedScreensArray);
   483 			// If supportedScreensArray.Count() is zero, it implies that
   484 			// decoder does not support any specific screens and it should be
   485 			// able to support any screen. Continue to initialize DevVideoPlay.
   486 			TInt err = KErrNone;
   487 			if(supportedScreensArray.Count() > 0)
   488 				{
   489 				// The decoder supports specific screens. Check if it supports
   490 				// the screen number set by the client.
   491 				err = supportedScreensArray.Find(iScreenNumber);
   492 				}
   493 			// If err is KErrNotFound, it implies that the decoder does not
   494 			// support the given screen and hence not suitable for the client.
   495 			// check if the next decoder in the list is suitable.
   496 			if(KErrNotFound != err)
   497 				{
   498 				// Suitable decoder is found.
   499 				iDevVideoInitialized = EFalse;
   500 				suitableDecoderFound = ETrue;
   501 				}
   502 			// supportedScreensArray, pCVideoDecoderInfo
   503 			CleanupStack::PopAndDestroy(2, pCVideoDecoderInfo);
   504 #else
   505 			iDevVideoInitialized = EFalse;
   506 			suitableDecoderFound = ETrue;
   507 #endif
   508 			}
   509 		outputFormatsArray.Reset();
   510 		}
   511 	CleanupStack::PopAndDestroy(&outputFormatsArray);
   512 
   513 	return suitableDecoderFound;
   514 	}
   515 
   516 
   517 //Starts playing and transfers the data from data source to data sink.
   518 void CAviPlayController::PlayL()
   519 	{
   520 	if (iState != EPrimed )
   521     	{
   522     	User::Leave(KErrNotReady);
   523     	}
   524 	iClip->SourcePlayL();
   525 	
   526 	if (iVideoSurfaceSupport == NULL)
   527 		{
   528 		iDevVideoPlay->StartDirectScreenAccessL(iScreenRect,*iScreenDev,iDerivedClipRegion);
   529 		}
   530 	
   531     iDevVideoPlay->Start();	
   532     if(iAudioEnabled)
   533   		{
   534     	iDevSound->PlayInitL();	
   535     	iState = EAudioReadyToPlay;
   536     	}
   537     else
   538     	{
   539     	iState = EPlaying;
   540     	}	
   541     	
   542 #ifdef SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
   543     if (iDevSubtitle)
   544     	{
   545     	// subtitle enabled
   546     	iDevSubtitle->SetVideoPositionL(0);
   547     	iDevSubtitle->Start();
   548     	iDevSubtitleStarted = ETrue;
   549     	}
   550 #endif //SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
   551    	}
   552 
   553 
   554 //Pause playing and the data transfer from data source to data sink.
   555 void CAviPlayController::PauseL()
   556     {
   557     User::Leave(KErrNotSupported);
   558 	}
   559 
   560 
   561 //Stops playing and the data transfer from data source to data sink.
   562 void CAviPlayController::StopL()
   563 	{
   564 	if (iState == EStopped)
   565     	{
   566     	return;
   567     	}
   568 
   569 	StopAudioL();
   570 	StopVideoL();
   571 	StopAviReaderL();
   572 #ifdef SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
   573     StopSubtitles();
   574 #endif //SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
   575 
   576     iState = EStopped;
   577 	}
   578 
   579 
   580 //Returns the current playing position from devvideoplay.
   581 TTimeIntervalMicroSeconds CAviPlayController::PositionL() const
   582 	{
   583  	if (iState == EStopped)
   584     	{
   585     	return 0;
   586     	}
   587 	CheckDevVideoPresentL();	
   588     return iDevVideoPlay->PlaybackPosition();
   589 	}
   590 
   591 
   592 //Set the position to play from.
   593 void CAviPlayController::SetPositionL(const TTimeIntervalMicroSeconds& /*aPosition*/)
   594 	{
   595 	//This will leave with KErrNotsupported as there is no support for seeking 
   596 	//position in an .avi file.
   597 	User::Leave(KErrNotSupported);
   598 	}
   599 
   600 
   601 //Returns the duration of the clip.
   602 TTimeIntervalMicroSeconds CAviPlayController::DurationL() const
   603 	{
   604 	CheckAviReaderPresentL();
   605 	return iAviReader->Duration();
   606 	}
   607 
   608 
   609 //Handles a custom command.
   610 void CAviPlayController::CustomCommand(TMMFMessage& aMessage)
   611 	{
   612 	aMessage.Complete(KErrNotSupported);
   613 	}
   614 
   615 
   616 //Sets the priority settings for devsound.
   617 void CAviPlayController::SetPrioritySettings(const TMMFPrioritySettings& aPrioritySettings)
   618 	{
   619  	iPrioritySettings = aPrioritySettings;
   620     if (iDevSound)
   621     	{
   622     	iDevSound->SetPrioritySettings(aPrioritySettings);
   623     	}
   624 	}
   625 
   626 
   627 //Gets the number of meta entries in the clip.
   628 void CAviPlayController::GetNumberOfMetaDataEntriesL(TInt& /*aNumberOfEntries*/)
   629 	{
   630 	//Support to get meta data is not present.so this will leave with KErrNotSupported.
   631 	User::Leave(KErrNotSupported);
   632 	}
   633 
   634 
   635 
   636 //Gets a meta entry at a specified index.
   637 CMMFMetaDataEntry* CAviPlayController::GetMetaDataEntryL(TInt /*aIndex*/)
   638 	{
   639 	//Support to get meta data is not present.so this will leave with KErrNotSupported. 
   640 	User::Leave(KErrNotSupported);
   641 	return NULL;
   642 	}
   643 
   644 //----------------------------------------------- //
   645 // MMMFVideoPlayControllerCustomCommandImplementor //
   646 //-----------------------------------------------//
   647 
   648 
   649 //Sets the screen clip region
   650 void CAviPlayController::MvpcUpdateDisplayRegionL(const TRegion& aRegion)
   651 	{
   652 	// Only update display region if not using graphics surfaces
   653 	if (!iVideoSurfaceSupport)
   654 		{
   655 		iDisplayRegion.Copy(aRegion);
   656 		UpdateClipRegion();
   657 		}
   658 	}
   659 
   660 
   661 //Gets the previously requested frame
   662 void CAviPlayController::MvpcGetFrameL(MMMFVideoFrameMessage& aMessage)
   663 	{
   664 	CFbsBitmap& bitmap = aMessage.GetBitmap();
   665 	TRAPD(err, CopyFrameL(bitmap));
   666 	aMessage.FrameReady(err);	
   667 	}
   668 
   669 
   670 //Copies the previously requested frame
   671 void CAviPlayController::CopyFrameL(CFbsBitmap& aBitmap)
   672 	{
   673 	CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
   674 	CleanupStack::PushL(bitmap);
   675 	User::LeaveIfError(aBitmap.Resize(bitmap->SizeInPixels()));
   676 	CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(&aBitmap);
   677 	CleanupStack::PushL(bitmapDevice);
   678 	CFbsBitGc* gc = NULL;
   679 	User::LeaveIfError(bitmapDevice->CreateContext(gc));
   680 	gc->DrawBitmap(TPoint(0,0), bitmap);
   681 	gc->Clear();
   682 	delete gc;
   683 	CleanupStack::PopAndDestroy(2,bitmap);//for bitmapdevice and bitmap.
   684 	}
   685 
   686 
   687 //Gets if audio is enabled during playing.
   688 void CAviPlayController::MvpcGetAudioEnabledL(TBool& aEnabled)
   689 	{
   690 	CheckAviReaderPresentL();
   691 	iAviReader->AudioEnabled(iAudioEnabled);
   692 	aEnabled = iAudioEnabled;
   693 	}
   694 
   695 
   696 //Sets the display window on the screen.
   697 void CAviPlayController::MvpcSetDisplayWindowL(const TRect& aWindowRect, const TRect& aClipRect)
   698 	{
   699 	if (iVideoSurfaceSupport != NULL)
   700 		{
   701 		User::Leave(KErrNotSupported);
   702 		}
   703 		
   704 	iScreenRect= aWindowRect;
   705 	iClipRect = aClipRect;
   706 	ASSERT(iScreenGc);
   707 	UpdateClipRegion();
   708 	}
   709 
   710 
   711 //Aborts or resumes direct screen access depends on the DSA event received
   712 void CAviPlayController::MvpcDirectScreenAccessEventL(const TMMFDSAEvent aDSAEvent)
   713 	{
   714 	if (iVideoSurfaceSupport != NULL)
   715 		{
   716 		User::Leave(KErrNotSupported);
   717 		}
   718 		
   719 	CheckDevVideoPresentL();
   720 	if (aDSAEvent == EAbortDSA)
   721 		{
   722 		if(iState == EPlaying)
   723 			{
   724 			iDevVideoPlay->AbortDirectScreenAccess();
   725 			}
   726 		}
   727 	else if (aDSAEvent == EResumeDSA)
   728 		{
   729 		if((iState == EPrimed)||(iState == EPlaying))
   730 			{
   731 			iDevVideoPlay->StartDirectScreenAccessL(iScreenRect,*iScreenDev,iDerivedClipRegion);
   732 			}
   733 		}
   734 	}
   735 
   736 //Plays videoclip within the playwindow set
   737 void CAviPlayController::MvpcPlayL(const TTimeIntervalMicroSeconds& /*aBegin*/,const TTimeIntervalMicroSeconds& /*aEnd*/)
   738 	{
   739 	//This will leave with KErrNotSupported as there is no provision to
   740 	// seek the position in an .avi file.
   741 	User::Leave(KErrNotSupported);
   742 	}
   743 
   744 
   745 //Redraws the current frame
   746 void CAviPlayController::MvpcRefreshFrameL()
   747 	{
   748 	CheckDevVideoPresentL();
   749 	iDevVideoPlay->Redraw();
   750 	}
   751 
   752 
   753 //Gets the progress of loading video clip
   754 void CAviPlayController::MvpcGetLoadingProgressL(TInt& /*aPercentage*/)
   755 	{
   756 	//This will leave with KErrNotSuuported as there is no support 
   757 	User::Leave(KErrNotSupported);
   758 	}
   759 
   760 
   761 //Prepares the controller for recording.
   762 void CAviPlayController::MvpcPrepare()
   763 	{
   764 	TMMFEvent controllerEvent;
   765 	controllerEvent.iEventType = KMMFEventCategoryVideoPrepareComplete;
   766 	controllerEvent.iErrorCode = KErrNone;
   767 	DoSendEventToClient(controllerEvent);		
   768 	}
   769 
   770 
   771 //Rotates the video file on the screen with the rotation angle given.
   772 void CAviPlayController::MvpcSetRotationL(TVideoRotation aRotation)
   773 	{
   774 	//this will leave with KErrNotSupported as the Xvid Hwdevice does not support post processing.
   775 	iRotation = aRotation;
   776 	User::Leave(KErrNotSupported);
   777 	}
   778 
   779 
   780 //Gets the rotation applied to the video file.
   781 void CAviPlayController::MvpcGetRotationL(TVideoRotation& aRotation)
   782 	{
   783 	//this will leave with KErrNotSupported as the Xvid Hwdevice does not support post processing.
   784 	aRotation = iRotation;
   785 	User::Leave(KErrNotSupported);
   786 	}
   787 
   788 
   789 //Scales the the video file on the screen with the scaling parameters given.
   790 void CAviPlayController::MvpcSetScaleFactorL(TReal32 aWidthPercentage, TReal32 aHeightPercentage, TBool aAntiAliasFiltering)
   791 	{
   792 	//this will leave with KErrNotSupported as the Xvid Hwdevice does not support post processing.
   793 	iWidthPercentage = aWidthPercentage;
   794 	iHeightPercentage = aHeightPercentage;
   795 	iAntiAliasFiltering = aAntiAliasFiltering;
   796 	User::Leave(KErrNotSupported);	
   797 	}
   798 
   799 
   800 //Gets the scale factor applied for the video file.
   801 void CAviPlayController::MvpcGetScaleFactorL(TReal32& aWidthPercentage, TReal32& aHeightPercentage, TBool& aAntiAliasFiltering)
   802 	{
   803 	//this will leave with KErrNotSupported as the Xvid Hwdevice does not support post processing.
   804 	aWidthPercentage = iWidthPercentage;
   805 	aHeightPercentage = iHeightPercentage;
   806 	aAntiAliasFiltering = iAntiAliasFiltering;
   807 	User::Leave(KErrNotSupported);
   808 	}
   809 
   810 
   811 //Sets the crop options for the image.
   812 void CAviPlayController::MvpcSetCropRegionL(const TRect& aCropRegion)
   813 	{
   814 	//this will leave with KErrNotSupported as the Xvid Hwdevice does not support post processing.
   815 	iCropRect = aCropRegion;
   816 	User::Leave(KErrNotSupported);
   817 	}
   818 
   819 
   820 //Gets the crop options of the image.
   821 void CAviPlayController::MvpcGetCropRegionL(TRect& aCropRegion)
   822 	{
   823 	//this will leave with KErrNotSupported as the Xvid Hwdevice does not support post processing.
   824 	aCropRegion = iCropRect;
   825 	User::Leave(KErrNotSupported);
   826 	}
   827 
   828 
   829 //Sets the video frame rate for recording.
   830 void CAviPlayController::MvcSetFrameRateL(TReal32 /*aFramesPerSecond*/)
   831 	{
   832 	//There are no apis available at devvideo level to do this.
   833 	//so, this will leave with KErrNotSupported.
   834 	User::Leave(KErrNotSupported);
   835 	}
   836 
   837 
   838 //Gets the video frame rate applied for playing 
   839 void CAviPlayController::MvcGetFrameRateL(TReal32& aFramesPerSecond)
   840 	{
   841 	CheckAviReaderPresentL();
   842 	iAviReader->FrameRate(aFramesPerSecond);
   843 	}
   844 
   845 
   846 //Gets the audio codec used for playing.
   847 void CAviPlayController::MvcGetAudioCodecL(TFourCC& aCodec)
   848 	{
   849 	if (iAudioEnabled)
   850 		{
   851 		aCodec = KMMFFourCCCodePCM16;
   852 		CheckAviReaderPresentL();
   853 	 	iAviReader->AudioCodec(aCodec);
   854 		}
   855 	else
   856 		{
   857 		User::Leave(KErrNotSupported);
   858 		}
   859 	}
   860 
   861 
   862 //Gets the video codec used for playing.
   863 void CAviPlayController::MvcGetVideoMimeTypeL(TDes8& aMimeType)
   864 	{
   865 	CheckAviReaderPresentL();
   866 	aMimeType = KAviVideoCodec;
   867 	iAviReader->VideoMimeType(aMimeType);
   868 	}
   869 
   870 
   871 //Gets the video bit rate used for playing.
   872 void CAviPlayController::MvcGetVideoBitRateL(TInt& /*aBitRate*/)
   873 	{
   874 	//There are no devvideo api's to do this.
   875 	//so, leave with KErrNotSuported.
   876 	User::Leave(KErrNotSupported);
   877 	}
   878 
   879 
   880 //Gets the audio bit rate used for playing.
   881 void CAviPlayController::MvcGetAudioBitRateL(TInt& aBitRate)
   882 	{
   883 	CheckAviReaderPresentL();
   884 	if(iAudioEnabled)
   885 		{
   886 		aBitRate = (iAviReader->BitsPerSample() * iAviReader->SampleRate()* iAviReader->Channels());
   887 		}
   888 	else
   889 		{
   890 		User::Leave(KErrNotSupported);	
   891 		}	
   892 	}
   893 
   894 
   895 //Returns the video framesize of the file.
   896 void CAviPlayController::MvcGetVideoFrameSizeL(TSize& aSize)
   897 	{
   898 	CheckAviReaderPresentL();
   899 	iAviReader->VideoFrameSize(aSize);
   900 	}
   901 
   902 
   903 
   904 //Sets the volume during playing.
   905 void CAviPlayController::MapdSetVolumeL(TInt aVolume)
   906 	{
   907 	if (iAudioEnabled)
   908 		{
   909 		CheckDevSoundPresentL();
   910 		TInt maxVolume = iDevSound->MaxVolume();
   911 		iDevSound->SetVolume(aVolume);
   912 		}
   913 	else
   914 		{
   915 		User::Leave(KErrNotSupported);
   916 		}	
   917 	}
   918 
   919 
   920 //Gets the maximum audio volume for playing.
   921 void CAviPlayController::MapdGetMaxVolumeL(TInt& aMaxVolume)
   922 	{
   923 	if(iAudioEnabled)
   924 		{
   925 		CheckDevSoundPresentL();
   926 		aMaxVolume = iDevSound->MaxVolume();
   927 		}
   928 	else
   929 		{
   930 		User::Leave(KErrNotSupported);
   931 		}	
   932 	}
   933 
   934 
   935 //Gets the volume for playing
   936 void CAviPlayController::MapdGetVolumeL(TInt& aVolume)
   937 	{
   938 	if (iAudioEnabled)
   939 		{
   940 		CheckDevSoundPresentL();
   941 		aVolume = iDevSound->Volume();
   942 		}
   943 	else
   944 		{
   945 		User::Leave(KErrNotSupported);
   946 		}
   947 	}
   948 
   949 
   950 //Gets the volume ramp for playing
   951 void CAviPlayController::MapdSetVolumeRampL(const TTimeIntervalMicroSeconds& aRampDuration)
   952 	{
   953 	if (iAudioEnabled)
   954 		{
   955 		CheckDevSoundPresentL();
   956 		iDevSound->SetVolumeRamp(aRampDuration);
   957 		}
   958 	else
   959 		{
   960 		User::Leave(KErrNotSupported);
   961 		}	
   962 	}
   963 
   964 
   965 //Set the audio balance for playing.
   966 void CAviPlayController::MapdSetBalanceL(TInt aBalance)
   967 	{
   968 	if (iAudioEnabled)
   969 		{
   970 		CheckDevSoundPresentL();
   971 		if (aBalance < KMMFBalanceMaxLeft)
   972 			{
   973     		aBalance = KMMFBalanceMaxLeft;	
   974     		}
   975 		else if (aBalance > KMMFBalanceMaxRight)
   976 			{
   977 			aBalance = KMMFBalanceMaxRight;
   978 			}
   979 		TInt left = (100 * (aBalance-KMMFBalanceMaxRight)) / (KMMFBalanceMaxLeft-KMMFBalanceMaxRight);
   980 		TInt right = 100 - left;
   981 		iDevSound->SetPlayBalanceL(left, right);
   982 		}
   983 	else
   984 		{
   985 		User::Leave(KErrNotSupported);
   986 		}	
   987 	}
   988 
   989 
   990 //Get the audio balance applied for playing
   991 void CAviPlayController::MapdGetBalanceL(TInt& aBalance)
   992 	{
   993 	if (iAudioEnabled)
   994 		{
   995 		CheckDevSoundPresentL();
   996 		TInt left = 50; // arbitrary values 
   997 		TInt right = 50;
   998 		iDevSound->GetPlayBalanceL(left, right); 
   999 		if ((left > 0) && (right > 0))
  1000 			{
  1001 			aBalance = (left * (KMMFBalanceMaxLeft-KMMFBalanceMaxRight))/100 + KMMFBalanceMaxRight;
  1002 			}
  1003 		else if ((left == 0) && (right == 0))
  1004 			{
  1005 			aBalance = 0;
  1006 			}
  1007 		else if ((left == 0) && (right > 0))
  1008 			{
  1009 			aBalance = 100;
  1010 			}
  1011 		else if ((left > 0) && (right == 0))
  1012 			{
  1013 			aBalance = -100;
  1014 			}
  1015 		}
  1016 	else
  1017 		{
  1018 		User::Leave(KErrNotSupported);
  1019 		}	
  1020 	}
  1021 	
  1022 
  1023 //Checks if valid devsound object is present.
  1024 void CAviPlayController::CheckDevSoundPresentL()
  1025 	{
  1026 	if (!iDevSound)
  1027 		{
  1028 		User::Leave(KErrNotReady);
  1029 		}
  1030 	}
  1031 
  1032 
  1033 //Checks if valid devvideoplay object present
  1034 void CAviPlayController::CheckDevVideoPresentL() const
  1035 	{
  1036 	if (iDevVideoPlay && iVideoFatalError)
  1037 		{
  1038 		// A fatal error occured. This will recreate the DevVideo instance and
  1039 		// also will clear iVideoFatalError flag. We use the cast operator here
  1040 		// as we need to modify member data.
  1041 		const_cast<CAviPlayController*>(this)->RecreateDevVideoAfterFatalErrorL();
  1042 		}
  1043 	if (!iDevVideoPlay)
  1044 		{
  1045 		User::Leave(KErrNotReady);
  1046 		}
  1047 	}
  1048 
  1049 
  1050 //Checks if valid avireader object present.
  1051 void CAviPlayController::CheckAviReaderPresentL() const
  1052 	{
  1053 	if (!iAviReader)
  1054     	{
  1055     	User::Leave(KErrNotReady);
  1056     	}
  1057 	}
  1058 
  1059 
  1060 //New empty buffers are available for decoding.Fill the video buffer
  1061 //with video data and send it for decoding.
  1062 void CAviPlayController:: MdvpoNewBuffers()
  1063 	{
  1064 	TVideoInputBuffer* newBuffer = NULL;
  1065 	ASSERT(iAviReader);
  1066 	ASSERT(iDevVideoPlay);
  1067 	if (!iAviReader->IsVideoInputEnd())
  1068 		{			
  1069 	   	// get a buffer of a minimum size from DevVideoPlay.
  1070     	TRAPD(error, newBuffer = iDevVideoPlay->GetBufferL(KTestBufferSize));
  1071 		if (!newBuffer)
  1072 			{
  1073 			//Lack of free buffers are not considered as an error.Hence return.
  1074 			return;
  1075 			}
  1076 		   	
  1077     	TRAP(error, iAviReader->FillVideoBufferL(newBuffer));
  1078     	if (error != KErrNone)
  1079 			{
  1080 			SendErrorToClient(error);
  1081 			return;
  1082 			}
  1083 		if(iAviReader->IsVideoInputEnd())
  1084 			{
  1085 			TRAPD(error,iDevVideoPlay->WriteCodedDataL(newBuffer));
  1086 			if (error!= KErrNone)
  1087 				{
  1088 				SendErrorToClient(error);
  1089 				return;			
  1090 				}
  1091 			iDevVideoPlay->InputEnd();
  1092 			}
  1093 		}
  1094 	}
  1095 
  1096 
  1097 //Fatal error occured while decoding video.Send the error to client.
  1098 void CAviPlayController::MdvpoFatalError(TInt aError)
  1099 	{
  1100 	// No need to stop Video as this call back already implies a video problem,
  1101 	// therefore it is supposed to be stopped (trying to stop it twice will
  1102 	// cause a panic in devvideo).
  1103 #ifdef SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
  1104 	StopSubtitles();
  1105 #endif //SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
  1106     TRAP_IGNORE(StopAudioL(); StopAviReaderL());
  1107 	// At this point we have to recreate the DevVideo instance. Since it is not
  1108 	// safe to delete the instance inside this error call back, we use a flag
  1109 	// so the next time we need to use DevVideo it will be recreated.
  1110 	iVideoFatalError = ETrue;
  1111 	iDevVideoInitialized = EFalse;
  1112 	iVideoDecoderInitialized = EFalse;
  1113 	iState = EStopped;
  1114     SendErrorToClient(aError);
  1115     }
  1116 
  1117 
  1118 //Notifies the client that there are one or more new pictures are available.
  1119 void CAviPlayController::MdvpoNewPictures()
  1120 	{
  1121     // dispose of the picture
  1122 	TVideoPicture* thePicture= NULL;
  1123 	ASSERT(iDevVideoPlay);
  1124 	TRAPD(err, thePicture = iDevVideoPlay->NextPictureL());
  1125 	if (err == KErrNone && thePicture != NULL)
  1126 		{
  1127 		iDevVideoPlay->ReturnPicture(thePicture);
  1128 		}
  1129 	}
  1130 
  1131 
  1132 //Initialization complete for devvideoplay.If audio is not enabled
  1133 //set state to EPrimed.
  1134 void CAviPlayController::MdvpoInitComplete(TInt aError)
  1135 	{
  1136    	if (aError != KErrNone)
  1137 		{
  1138 		SendErrorToClient(aError);
  1139 		return;
  1140 		}
  1141     iDevVideoInitialized = ETrue;
  1142 	// if audio is enabled we need to wait for both the audio and video initializations
  1143 	//before completing client's prime message.
  1144 	CheckForInitComplete();	
  1145 	}
  1146  
  1147 
  1148 //End of the video data in the file.
  1149 void CAviPlayController::MdvpoStreamEnd()
  1150 	{
  1151 	TRAP_IGNORE(StopL());
  1152 	SendErrorToClient(KErrNone);
  1153 	}
  1154 
  1155 
  1156 //Intended for future use.Will panic if called.
  1157 void CAviPlayController:: MdvpoReturnPicture(TVideoPicture* /*aPicture*/)
  1158 	{
  1159     Panic(EBadCall);
  1160     }
  1161  
  1162 
  1163 //Intended for future use.Will panic if called.
  1164 void CAviPlayController::MdvpoSupplementalInformation(const TDesC8 &/*aData*/, const TTimeIntervalMicroSeconds &/*aTimestamp*/, const TPictureId &/*aPictureId*/)
  1165 	{
  1166    	Panic(EBadCall);
  1167     }
  1168 
  1169 
  1170 //Intended for future use.Will panic if called.
  1171 void CAviPlayController:: MdvpoPictureLoss()
  1172 	{  
  1173  	Panic(EBadCall);
  1174  	}
  1175 
  1176 
  1177 //Intended for future use.Will panic if called.
  1178 void CAviPlayController::MdvpoPictureLoss(const TArray< TPictureId > &/*aPictures*/)
  1179 	{
  1180    	Panic(EBadCall);
  1181     }
  1182     
  1183 
  1184 //Intended for future use.Will panic if called.
  1185 void CAviPlayController:: MdvpoSliceLoss(TUint /*aFirstMacroblock*/, TUint /*aNumMacroblocks*/, const TPictureId &/*aPicture*/)
  1186     {
  1187    	Panic(EBadCall);
  1188     }
  1189     
  1190 
  1191 //Intended for future use.Will panic if called.
  1192 void CAviPlayController::MdvpoReferencePictureSelection(const TDesC8 &/*aSelectionData*/)
  1193     {
  1194     Panic(EBadCall);
  1195     }
  1196     
  1197 
  1198 //Intended for future use.Will panic if called.
  1199 void CAviPlayController::MdvpoTimedSnapshotComplete(TInt /*aError*/, TPictureData */*aPictureData*/, const TTimeIntervalMicroSeconds &/*aPresentationTimestamp*/, const TPictureId &/*aPictureId*/)
  1200     {
  1201     Panic(EBadCall);
  1202     }
  1203 
  1204 //Sets the initial screen number for the video display
  1205 void CAviPlayController::MvsdSetInitScreenNumber(TInt aScreenNumber)
  1206 	{
  1207 	iScreenNumber = aScreenNumber;
  1208 	}
  1209 
  1210 #ifdef SYMBIAN_BUILD_GCE
  1211 void CAviPlayController::MvpssUseSurfacesL()
  1212 	{
  1213 	// UseSurfaces must happen before initialize
  1214 	if (!iDevVideoPlay || iVideoDecoderInitialized)
  1215 		{
  1216 		User::Leave(KErrNotReady);
  1217 		}
  1218 
  1219 	// Calling UseSurfaces multiple times is allowed
  1220 	
  1221 	if (iVideoSurfaceSupport == NULL)
  1222 		{
  1223 		if (LocateDecoderL(ETrue) && iVideoSurfaceSupport != NULL)
  1224 			{
  1225 			iVideoSurfaceSupport->MmvssSetObserver(*this);
  1226 			iVideoSurfaceSupport->MmvssUseSurfaces();
  1227 			}			
  1228 		}
  1229 	
  1230 	// iVideoSurfaceSupport will be updated in LocateDecoderL
  1231 	if (iVideoSurfaceSupport == NULL)
  1232 		{
  1233 		User::Leave(KErrNotSupported);
  1234 		}		
  1235 	}
  1236 	
  1237 void CAviPlayController::MvpssGetSurfaceParametersL(TSurfaceId& aSurfaceId,	TRect& aCropRect,
  1238 														TVideoAspectRatio& aPixelAspectRatio)
  1239 	{
  1240 	if (iVideoSurfaceSupport == NULL)
  1241 		{
  1242 		User::Leave(KErrNotSupported);
  1243 		}
  1244 
  1245 	iVideoSurfaceSupport->MmvssGetSurfaceParametersL(aSurfaceId, aCropRect, aPixelAspectRatio);
  1246 	}
  1247 	
  1248 void CAviPlayController::MvpssSurfaceRemovedL(const TSurfaceId& aSurfaceId)
  1249 	{
  1250 	if (iVideoSurfaceSupport == NULL)
  1251 		{
  1252 		User::Leave(KErrNotSupported);
  1253 		}
  1254 	
  1255 	iVideoSurfaceSupport->MmvssSurfaceRemovedL(aSurfaceId);
  1256 	}
  1257 
  1258 void CAviPlayController::MmvsoSurfaceCreated()
  1259 	{
  1260 	DoSendEventToClient(TMMFEvent(KMMFEventCategoryVideoSurfaceCreated, KErrNone));
  1261 	}
  1262 	
  1263 void CAviPlayController::MmvsoSurfaceParametersChanged()
  1264 	{
  1265 	DoSendEventToClient(TMMFEvent(KMMFEventCategoryVideoSurfaceParametersChanged, KErrNone));
  1266 	}
  1267 
  1268 void CAviPlayController::MmvsoRemoveSurface()
  1269 	{
  1270 	DoSendEventToClient(TMMFEvent(KMMFEventCategoryVideoRemoveSurface, KErrNone));
  1271 	}
  1272 #endif // SYMBIAN_BUILD_GCE
  1273 
  1274 //Devsound initialization is completed.Configure devsound capabilities. 
  1275 void CAviPlayController::InitializeComplete(TInt aError)
  1276 	{
  1277 	TInt error = aError;
  1278    	if (error == KErrNone)
  1279 		{
  1280 		ASSERT(iDevSound);
  1281 		TMMFCapabilities devSoundCaps = iDevSound->Capabilities();
  1282 		TMMFCapabilities caps;
  1283 		ASSERT(iAviReader);
  1284 		TInt rate = iAviReader->SampleRate();
  1285 		TBool found = EFalse;
  1286 		for( TInt index =0; index < KNumSampleRates; index++)
  1287 			{
  1288 			if(rate == KRateLookup[index].iRate)
  1289 				{
  1290 				caps.iRate = KRateLookup[index].iRateEnum;
  1291 				found = ETrue;
  1292 				}
  1293 			}
  1294     	if(!found)
  1295     		{
  1296     		error = KErrNotFound;
  1297     		}
  1298     	if(error == KErrNone)
  1299     		{
  1300     		caps.iChannels = iAviReader->Channels();
  1301 	    	if (caps.iChannels == 1) 
  1302 				{
  1303 				caps.iChannels = EMMFMono;
  1304 				}
  1305 			else if (caps.iChannels == 2)
  1306 				{
  1307 				caps.iChannels = EMMFStereo;
  1308 				}
  1309 			else 
  1310 				{
  1311 				error = KErrNotFound;
  1312 				}	
  1313     		}
  1314     	if(error == KErrNone)
  1315     		{
  1316     		caps.iEncoding = EMMFSoundEncoding16BitPCM;
  1317     		TRAP(error,iDevSound->SetConfigL(caps));
  1318         	if(error == KErrNone)
  1319 				{
  1320 				iDevSoundInitialized = ETrue;
  1321 				CheckForInitComplete();	
  1322 				}
  1323 			}
  1324 		}
  1325 	else
  1326 		{
  1327 		SendErrorToClient(error);
  1328 		}
  1329 		
  1330    	 }
  1331 
  1332 //Intended for future use.Will panic if called.
  1333 void CAviPlayController::ToneFinished(TInt /*aError*/)
  1334    	{
  1335  	Panic(EBadCall);
  1336  	}
  1337 
  1338 
  1339 //This is called when an empty audio buffer is available.Fill the buffer with audio data.
  1340 void CAviPlayController::BufferToBeFilled(CMMFBuffer* aBuffer)
  1341 	{
  1342 	if (iState == EAudioReadyToPlay)
  1343 		{
  1344 		iState = EPlaying;	
  1345 		}
  1346 	ASSERT(iAviReader);
  1347 	TRAPD(err, iAviReader->FillAudioBufferL(aBuffer));
  1348 	//if error,send the error to client
  1349 	if(err)
  1350 		{
  1351 		SendErrorToClient(err);
  1352 		}
  1353 	}
  1354 
  1355 //This is called when an audio play completion is successfully played or otherwise
  1356 void CAviPlayController::PlayError(TInt aError)
  1357  	{
  1358 	ASSERT(iAviReader);
  1359 	
  1360 	// Ignore overflow when the end of audio is reached.
  1361 	if(aError == KErrUnderflow && iAviReader->IsAudioInputEnd())
  1362 		{
  1363 		// audio has reached the end of the file
  1364 		aError = KErrNone;
  1365 		}
  1366 	
  1367 	// Controller will be stopped and play complete message sent when the video stream
  1368 	// has ended, unless there is an error.
  1369 	if (aError != KErrNone)
  1370 		{
  1371 		TRAP_IGNORE(StopL());
  1372 		SendErrorToClient(aError);
  1373 		}
  1374 	}
  1375 
  1376 //Will panic if called.Should not be called during playing
  1377 void CAviPlayController::BufferToBeEmptied(CMMFBuffer* /*aBuffer*/)
  1378 	 {
  1379 	 Panic(EBadCall);
  1380 	 }
  1381 
  1382 
  1383 //Will panic if called.Should not be called during playing
  1384 void CAviPlayController::RecordError(TInt /*aError*/)
  1385 	 {
  1386      Panic(EBadCall);
  1387 	 }
  1388 
  1389 
  1390 //Will panic if called.Should not be called during playing
  1391 void CAviPlayController::ConvertError(TInt /*aError*/)
  1392 	 {
  1393 	 Panic(EBadCall);
  1394 	 }
  1395 	 
  1396 
  1397 //Will panic if called.Should not be called during playing
  1398 void CAviPlayController::DeviceMessage(TUid /*aMessageType*/, const TDesC8& /*aMsg*/)
  1399 	 {
  1400 	 Panic(EBadCall);
  1401 	 }
  1402 
  1403 
  1404 //Sends an event to client.
  1405 void CAviPlayController::SendEventToClient(const TMMFEvent& aEvent)
  1406 	{
  1407     DoSendEventToClient(aEvent);
  1408 	}
  1409  
  1410 
  1411 //This function is called when an empty audio buffer filled with audio data.
  1412 //This can now be sent to devsound for decoding.
  1413 void CAviPlayController::AudioBufferFilled()
  1414 	{
  1415 	ASSERT(iDevSound);
  1416 	iDevSound->PlayData();
  1417 	}
  1418 
  1419 
  1420 //This function is called when an empty video buffer is filled with video data.
  1421 //This can now be sent for decoding.If there is no data then inform devvideo
  1422 //about end of video stream.
  1423 void CAviPlayController::VideoBufferFilled(TVideoInputBuffer* aBuffer)
  1424 	{
  1425 	ASSERT(iDevVideoPlay);
  1426 	ASSERT(iAviReader);
  1427 	TRAPD(error,iDevVideoPlay->WriteCodedDataL(aBuffer));
  1428 	if(error != KErrNone)
  1429 		{
  1430 		SendErrorToClient(error);
  1431 		return;
  1432 		}
  1433 	if(iAviReader->IsVideoInputEnd())
  1434 		{
  1435 		iDevVideoPlay->InputEnd();
  1436 		}
  1437 	}
  1438 
  1439 
  1440 
  1441 //This function is used when both audio and video are enabled for playing.
  1442 //The State is set to EPrimed when initialization is completed on both DevSound and DevVideo 
  1443 void CAviPlayController::CheckForInitComplete()
  1444  	{
  1445  	if(iAudioEnabled)
  1446 		{
  1447  		if ((iDevVideoInitialized) &&(iDevSoundInitialized))
  1448  			{
  1449  			iState = EPrimed;
  1450  			if (iMessage)
  1451 				{
  1452 				iMessage->Complete(KErrNone);
  1453 				delete iMessage;
  1454 				iMessage = NULL;
  1455 				}
  1456  			}
  1457  		}
  1458  	else
  1459  		{
  1460  		iState = EPrimed;
  1461  		 		
  1462  		if (iMessage)
  1463  			{
  1464  			iMessage->Complete(KErrNone);
  1465 			delete iMessage;
  1466 			iMessage = NULL;
  1467  			}
  1468  		}
  1469  	iVideoDecoderInitialized = ETrue;
  1470  	}
  1471 
  1472 //Sends the error message to the client.
  1473 void CAviPlayController::SendErrorToClient(TInt aError)  
  1474 	{
  1475 	if (iMessage)
  1476 		{
  1477 		iMessage->Complete(aError);
  1478 		delete iMessage;
  1479 		iMessage = NULL;
  1480 		}
  1481 	else
  1482 		{
  1483 		TMMFEvent controllerEvent;
  1484 		controllerEvent.iEventType = KMMFEventCategoryPlaybackComplete;
  1485 		controllerEvent.iErrorCode = aError;
  1486 		DoSendEventToClient(controllerEvent);	
  1487 		}
  1488 	}
  1489 
  1490 CAviPlayController::CMMFMessageHolder* CAviPlayController::CMMFMessageHolder::NewL(TMMFMessage& aMessage)
  1491 	{
  1492 	return new(ELeave) CMMFMessageHolder(aMessage);
  1493 	}
  1494 		
  1495 void CAviPlayController::CMMFMessageHolder::Complete(TInt aError) 
  1496 	{
  1497 	iMessage.Complete(aError);
  1498 	}
  1499 	
  1500 CAviPlayController::CMMFMessageHolder::CMMFMessageHolder(TMMFMessage& aMessage): CBase(), iMessage(aMessage)
  1501 	{
  1502 	}
  1503 
  1504 
  1505 CAviPlayController::CSourceSinkEventHandler::CSourceSinkEventHandler(CAviPlayController& aParent):iParent(aParent)
  1506 	{
  1507 	}
  1508 
  1509 CAviPlayController::CSourceSinkEventHandler::~CSourceSinkEventHandler()
  1510 	{
  1511 	}
  1512 
  1513 TInt CAviPlayController::CSourceSinkEventHandler::SendEventToClient(const TMMFEvent& aEvent)
  1514 	{
  1515 	iParent.SendEventToClient(aEvent);
  1516 	return KErrNone;
  1517 	}
  1518 
  1519 void CAviPlayController::MarnRegisterAsClientL(TUid aEventType, const TDesC8& aNotificationRegistrationData)
  1520 	{
  1521 	//If file is open, check if audio is enabled
  1522 	if(iAviReader)
  1523 		{
  1524 		iAviReader->AudioEnabled(iAudioEnabled);
  1525 		if(!iAudioEnabled)
  1526 			{
  1527 			User::Leave(KErrArgument);	
  1528 			}
  1529 		}
  1530 	//[ precondition that we have a sink]
  1531 	CheckDevSoundPresentL();
  1532 	
  1533 	//[register the notification ]
  1534 	TInt err = iDevSound->RegisterAsClient(aEventType, aNotificationRegistrationData);
  1535 	User::LeaveIfError(err);
  1536 	}
  1537 
  1538 void CAviPlayController::MarnCancelRegisterAsClientL(TUid aEventType)
  1539 	{
  1540 	//[ precondition that we have a sink]
  1541 	CheckDevSoundPresentL();
  1542 	
  1543 	//[cancel the notification ]
  1544 	TInt err = 	iDevSound->CancelRegisterAsClient(aEventType);
  1545 	User::LeaveIfError(err);
  1546 	}
  1547 
  1548 void CAviPlayController::MarnGetResourceNotificationDataL(TUid aEventType, TDes8& aNotificationData)
  1549 	{
  1550 	//[ precondition that we have a sink]
  1551 	CheckDevSoundPresentL();
  1552 	
  1553 	//[get the notification data]
  1554 	TMMFTimeIntervalMicroSecondsPckg pckg;
  1555 	TInt err = iDevSound->GetResourceNotificationData(aEventType, pckg);
  1556 	User::LeaveIfError(err);
  1557 	
  1558 	// aNotificationData is a package buffer returned as TMMFTimeIntervalMicroSecondsPckg.
  1559 	// The contents should be converted to an integer and interpreted as samples played,
  1560 	// but not as a microsecond value. 
  1561 	// As the client expects a position (in microseconds from the beginning
  1562 	// of the clip) we need to convert the data depending on the sample rate.
  1563 	// Potential issue if using the number of samples played with VBR sampling.
  1564 	TUint rate = 0;
  1565 	TMMFCapabilities caps = iDevSound->Config();
  1566 	for( TInt i = 0; i < KNumSampleRates; i++)
  1567 		{
  1568 		if(caps.iRate == KRateLookup[i].iRateEnum)
  1569 			{
  1570 			rate = KRateLookup[i].iRate;
  1571 			break;	
  1572 			}
  1573 		}
  1574 	if(rate != 0)
  1575 		{
  1576 		// Convert the given number of samples using the sample rate
  1577 		const TInt KMicroSecsInOneSec = 1000000;
  1578 		TTimeIntervalMicroSeconds value = pckg();
  1579 		value = TTimeIntervalMicroSeconds(value.Int64() * ((TReal)KMicroSecsInOneSec / rate));
  1580 		pckg() = value;
  1581 		}
  1582 	else
  1583 		{
  1584 		User::Leave(KErrArgument);
  1585 		}
  1586 	aNotificationData = pckg;
  1587 	}
  1588 
  1589 void CAviPlayController::MarnWillResumePlayL()
  1590 	{
  1591 	//[ precondition that we have a sink]
  1592 	CheckDevSoundPresentL();
  1593 	
  1594 	//[wait for the client to resume ]
  1595 	TInt err = iDevSound->WillResumePlay();	
  1596 	User::LeaveIfError(err);
  1597 	}
  1598 
  1599 // Stops video.
  1600 void CAviPlayController::StopVideoL()
  1601 	{
  1602 	// If already stopped, do nothing
  1603 	if (iState == EStopped)
  1604     	{
  1605     	return;
  1606     	}
  1607 
  1608 	CheckDevVideoPresentL();
  1609 	// AbortDirectScreenAccess and Stop can only be used if DevVideoPlay has
  1610 	// been already initialized. If CheckDevVideoPresentL has just recreated
  1611 	// the DevVideoPlay instance, no need to make these calls on DevVideoPlay.
  1612 	if (iDevVideoInitialized)
  1613 		{
  1614 		if (iVideoSurfaceSupport == NULL)
  1615 			{
  1616 			iDevVideoPlay->AbortDirectScreenAccess();
  1617 			}
  1618 
  1619 		iDevVideoPlay->Stop();
  1620 		}
  1621 	}
  1622 
  1623 
  1624 // Stops audio (if enabled).
  1625 void CAviPlayController::StopAudioL()
  1626 	{
  1627 	// If already stopped, do nothing
  1628 	if (iState == EStopped || !iAudioEnabled)
  1629     	{
  1630     	return;
  1631     	}
  1632 
  1633 	CheckDevSoundPresentL();
  1634 	iDevSound->Stop();
  1635 	iDevSoundInitialized = EFalse;
  1636 	}
  1637 
  1638 // Stops the data transfer from data source to data sink.
  1639 void CAviPlayController::StopAviReaderL()
  1640 	{
  1641 	// If already stopped, do nothing
  1642 	if (iState == EStopped)
  1643     	{
  1644     	return;
  1645     	}
  1646 
  1647 	// Stop avi reader
  1648     CheckAviReaderPresentL();
  1649     iAviReader->ResetL();
  1650 	}
  1651 
  1652 #ifdef SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
  1653 // Stops DevSubtitle
  1654 void CAviPlayController::StopSubtitles()
  1655 	{
  1656     if (iDevSubtitle && iDevSubtitleStarted)
  1657     	{
  1658     	// stop subtitles if it was enabled
  1659     	iDevSubtitle->Stop();
  1660     	iDevSubtitleStarted = EFalse;
  1661     	}
  1662 	}
  1663 #endif //SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
  1664 
  1665 // This non-const method is used to encapsulate non-const actions that need to
  1666 // take place within a const method so there's no need to change the constness
  1667 // definition of the caller method.
  1668 void CAviPlayController::RecreateDevVideoAfterFatalErrorL()
  1669 	{
  1670 	iVideoFatalError = EFalse;
  1671 	delete iDevVideoPlay;
  1672 	iDevVideoPlay = NULL;
  1673 	iDevVideoPlay = CMMFDevVideoPlay::NewL(*this);
  1674 	iDevVideoInitialized = EFalse;
  1675 	}
  1676 
  1677 /*
  1678 MMMFVideoPlayControllerExtCustomCommandImplementor
  1679 */
  1680 
  1681 // Sets play velocity. that will be effective on next play
  1682 void CAviPlayController::MvpecSetPlayVelocityL(TInt )
  1683 	{
  1684 	User::Leave(KErrNotSupported);
  1685 	}
  1686 
  1687 // returns play velocity
  1688 TInt CAviPlayController::MvpecPlayVelocityL()
  1689 	{
  1690 	return 100; // return default play velocity.
  1691 	}
  1692 
  1693 //steps to the frame, relative to current frame
  1694 void CAviPlayController::MvpecStepFrameL(TInt )
  1695 	{
  1696 	User::Leave(KErrNotSupported);
  1697 	}
  1698 
  1699 // return paly capabilities.
  1700 void CAviPlayController::MvpecGetPlayRateCapabilitiesL(TVideoPlayRateCapabilities& aCapabilities)
  1701 	{
  1702 	// none of the capabilities are supported.
  1703 	aCapabilities.iPlayBackward = EFalse;
  1704 	aCapabilities.iPlayForward = EFalse;
  1705 	aCapabilities.iStepBackward = EFalse;
  1706 	aCapabilities.iStepForward = EFalse;
  1707 	}
  1708 
  1709 // enables or disables video.
  1710 void CAviPlayController::MvpecSetVideoEnabledL(TBool )
  1711 	{
  1712 	User::Leave(KErrNotSupported);
  1713 	}
  1714 
  1715 // reutrns video enabled status.
  1716 TBool CAviPlayController::MvpecVideoEnabledL()
  1717 	{
  1718 	// by default video is enabled.
  1719 	return ETrue;
  1720 	}
  1721 
  1722 //enables or disables video.
  1723 void CAviPlayController::MvpecSetAudioEnabledL(TBool )
  1724 	{
  1725 	User::Leave(KErrNotSupported);
  1726 	}
  1727 
  1728 // Scales video display as per the input parameters.
  1729 void CAviPlayController::MvpecSetAutoScaleL(TAutoScaleType , TInt , TInt )
  1730 	{
  1731 	User::Leave(KErrNotSupported);
  1732 	}
  1733 
  1734 // Called when either iDisplayRegion or iClipRect are changed. The derived
  1735 // clip region is the intersection of these. This method can be called
  1736 // during playback, so the new region is passed immediately to DevVideo.
  1737 void CAviPlayController::UpdateClipRegion()
  1738 	{
  1739 	iDerivedClipRegion.Copy(iDisplayRegion);
  1740 	iDerivedClipRegion.ClipRect(iClipRect);
  1741 	
  1742 	if(iDevVideoInitialized)
  1743 		{
  1744 		// This isn't necessary in all cases, for instance there may be a
  1745 		// direct screen access start/stop, which would also set the clipping
  1746 		// region. This is added for completeness.
  1747 		iDevVideoPlay->SetScreenClipRegion(iDerivedClipRegion);
  1748 		}
  1749 	
  1750 	if(iScreenGc)
  1751 		{
  1752 		iScreenGc->SetClippingRegion(iDerivedClipRegion);
  1753 		}
  1754 	}
  1755 
  1756 #ifdef SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT
  1757 // MMMFVideoPlaySubtitleSupportCustomCommandImplementor
  1758 void CAviPlayController::MvpsusGetCrpParametersL(TInt aWindowId, TWsGraphicId& aId, TRect& aCrpRect)
  1759 	{
  1760 	if (!iDevSubtitle)
  1761 		{
  1762 		User::Leave(KErrNotReady);
  1763 		}
  1764 	iDevSubtitle->GetCrpParametersL(aWindowId, aId, aCrpRect);
  1765 	}
  1766 
  1767 void CAviPlayController::MvpsusAddSubtitleConfigL(const TMMFSubtitleWindowConfig& aConfig)
  1768 	{
  1769 	if (!iDevSubtitle)
  1770 		{
  1771 		User::Leave(KErrNotReady);
  1772 		}
  1773 	iDevSubtitle->AddSubtitleConfigL(aConfig);
  1774 	
  1775 	// Add successful, increment configuration count.
  1776 	iSubtitleConfigCount++;
  1777 	
  1778 	if (iState == EPlaying && !iDevSubtitleStarted)
  1779 		{
  1780 		// video is playing but dev subtitle hasn't started, i.e. subtitle enabled during play
  1781 		iDevSubtitle->SetVideoPositionL(iDevVideoPlay->PlaybackPosition());
  1782     	iDevSubtitle->Start();
  1783     	iDevSubtitleStarted = ETrue;
  1784 		}
  1785 	
  1786 	// add subtitle config was successful
  1787 	DoSendEventToClient(TMMFEvent(KMMFEventCategoryVideoSubtitleCrpReady, aConfig.iWindowId));
  1788 	}
  1789 
  1790 void CAviPlayController::MvpsusRemoveSubtitleConfigL(TInt aWindowId)
  1791 	{
  1792 	if (!iDevSubtitle)
  1793 		{
  1794 		User::Leave(KErrNotReady);
  1795 		}
  1796 	iDevSubtitle->RemoveSubtitleConfigL(aWindowId);
  1797 	
  1798 	// Remove successful, decrement configuration count.
  1799 	iSubtitleConfigCount--;
  1800 	
  1801 	if (iSubtitleConfigCount == 0)
  1802 		{
  1803 		StopSubtitles();
  1804 		}
  1805 	}
  1806 
  1807 void CAviPlayController::MvpsusUpdateSubtitleConfigL(const TMMFSubtitleWindowConfig& aConfig)
  1808 	{
  1809 	if (!iDevSubtitle)
  1810 		{
  1811 		User::Leave(KErrNotReady);
  1812 		}
  1813 	iDevSubtitle->UpdateSubtitleConfigL(aConfig);
  1814 
  1815 	// update subtitle config was successful
  1816 	DoSendEventToClient(TMMFEvent(KMMFEventCategoryVideoSubtitleCrpReady, aConfig.iWindowId));
  1817 	}
  1818 
  1819 void CAviPlayController::MvpsusGetSubtitlesAvailableL(TBool& aAvailable)
  1820 	{
  1821 	aAvailable = EFalse;
  1822 	// first check if file source is added
  1823 	if (iClip)
  1824 		{
  1825 		if (iSrtReader)
  1826 			{
  1827 			aAvailable = ETrue;
  1828 			}
  1829 		else
  1830 			{
  1831 			// Create and destroy a temporary SRT Reader object.
  1832 			CSrtReader* tempReader = NULL;
  1833 			TRAPD(err, tempReader = CreateSubtitleSourceL());
  1834 			delete tempReader;
  1835 			
  1836 			// Subtitles are available if and only if CreateSubtitleSourceL had no errors.
  1837 			aAvailable = (err == KErrNone);
  1838 			
  1839 			// If CreateSubtitleSourceL left with KErrNotFound then we do not leave; just report 
  1840 			// subtitles as not available.
  1841 			if (err != KErrNotFound && err != KErrNone)
  1842 				{
  1843 				User::Leave(err);
  1844 				}
  1845 			}
  1846 		}
  1847 	}
  1848 
  1849 // create srt reader, return subtitle file name if a file clip has been added, leave if out of memory
  1850 CSrtReader* CAviPlayController::CreateSubtitleSourceL()
  1851 	{
  1852 	const TDesC& filedrive = iClip->FileDrive();
  1853 	const TDesC& filepath = iClip->FilePath();
  1854 	const TDesC& filename = iClip->FileName();
  1855 	
  1856 	TFileName srtFileName;
  1857 	
  1858 	// Check that the srt file's filename length is not longer than the maximum filename length.  This
  1859 	// can arise only when the extension "srt" is longer than the clip's file extension and the rest of 
  1860 	// the name is very long.
  1861 	// The 1 is added to account for the period "." before the extension.
  1862 	if (filedrive.Length() + filepath.Length() + filename.Length() + KSrtExtension().Length() + 1 > srtFileName.MaxLength())
  1863 		{
  1864 		// File cannot exist on the filesystem
  1865 		User::Leave(KErrNotFound);
  1866 		}
  1867 	
  1868 	srtFileName.Format(_L("%S%S%S.%S"), &filedrive, &filepath, &filename, &KSrtExtension);
  1869 	
  1870 	CSrtReader* reader = CSrtReader::NewL(srtFileName);
  1871 	
  1872 	return reader;
  1873 	}
  1874 
  1875 void CAviPlayController::MvpsusDisableSubtitlesL()
  1876 	{
  1877 	// disable subtitles if subtitles was enabled
  1878 	if (iDevSubtitle)
  1879 		{
  1880 		StopSubtitles();
  1881 		delete iDevSubtitle;
  1882 		iDevSubtitle = NULL;
  1883 		
  1884 		delete iSrtReader;
  1885 		iSrtReader = NULL;
  1886 		}
  1887 	}
  1888 
  1889 void CAviPlayController::MvpsusEnableSubtitlesL()
  1890 	{
  1891 	if (!iClip)
  1892 		{
  1893 		User::Leave(KErrNotReady);
  1894 		}
  1895 	if (iDevSubtitle)
  1896 		{
  1897 		User::Leave(KErrInUse);
  1898 		}
  1899 	CSrtReader* reader = CreateSubtitleSourceL();
  1900 	CleanupStack::PushL(reader);
  1901 	CMMFDevSubtitle* devSubtitle = CMMFDevSubtitle::NewLC(*reader);
  1902 	devSubtitle->SelectDecoderL(KSrtDecoder);
  1903 	
  1904 	// subtitle was enabled sucessfully
  1905 	// assign reader and devSubtitle to class and pop them from cleanup stack
  1906 	CleanupStack::Pop(2, reader);
  1907 	iDevSubtitle = devSubtitle;
  1908 	iSrtReader = reader;
  1909 	}
  1910 
  1911 void CAviPlayController::MvpsusGetSubtitleLanguageL(TLanguage& aLanguage)
  1912 	{
  1913 	if (!iDevSubtitle)
  1914 		{
  1915 		User::Leave(KErrNotReady);
  1916 		}
  1917 	aLanguage = iDevSubtitle->SubtitleLanguageL();
  1918 	}
  1919 
  1920 void CAviPlayController::MvpsusGetSupportedSubtitleLanguagesL(RArray<TLanguage>& aLanguages)
  1921 	{
  1922 	if (!iDevSubtitle)
  1923 		{
  1924 		User::Leave(KErrNotReady);
  1925 		}
  1926 	iDevSubtitle->GetSupportedSubtitleLanguagesL(aLanguages);
  1927 	}
  1928 
  1929 void CAviPlayController::MvpsusSetSubtitleLanguageL(TLanguage aLanguage)
  1930 	{
  1931 	if (!iDevSubtitle)
  1932 		{
  1933 		User::Leave(KErrNotReady);
  1934 		}
  1935 	iDevSubtitle->SetSubtitleLanguageL(aLanguage);
  1936 	}
  1937 
  1938 #endif //SYMBIAN_MULTIMEDIA_SUBTITLE_SUPPORT