os/mm/mmplugins/mmfwplugins/src/Plugin/Controller/Video/AviPlayController/avireader.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 #include "avireader.h"
    17 
    18 const TInt KReadBufferSize = 0x8000; // 4k
    19 const TInt KChunkHeaderSize = 8;
    20 
    21 const TInt KInvalidMediaIdx = -1;
    22 
    23 #define RiffChunkName(A,B,C,D) ((D<<24)+(C<<16)+(B<<8)+A)
    24 
    25 const TInt KRiffChunkNameRiff = RiffChunkName('R','I','F','F');
    26 const TInt KRiffChunkNameList = RiffChunkName('L','I','S','T');
    27 const TInt KRiffChunkNameAvih = RiffChunkName('a','v','i','h');
    28 const TInt KRiffChunkTypeAvi  = RiffChunkName('A','V','I',' ');
    29 const TInt KRiffChunkTypeHdrl = RiffChunkName('h','d','r','l');
    30 const TInt KRiffChunkTypeStrl = RiffChunkName('s','t','r','l');
    31 const TInt KRiffChunkNameStrh = RiffChunkName('s','t','r','h');
    32 const TInt KRiffChunkNameStrf = RiffChunkName('s','t','r','f');
    33 const TInt KRiffChunkNameStrn = RiffChunkName('s','t','r','n');
    34 const TInt KRiffChunkTypeVids = RiffChunkName('v','i','d','s');
    35 const TInt KRiffChunkTypeAuds = RiffChunkName('a','u','d','s');
    36 const TInt KRiffChunkNameJunk = RiffChunkName('J','U','N','K');
    37 const TInt KRiffChunkTypeMovi = RiffChunkName('m','o','v','i');
    38 const TInt KRiffChunkName00db = RiffChunkName('0','0','d','b');
    39 const TInt KRiffChunkName00dc = RiffChunkName('0','0','d','c');
    40 const TInt KRiffChunkName00wb = RiffChunkName('0','0','w','b');
    41 const TInt KRiffChunkName01wb = RiffChunkName('0','1','w','b');
    42 const TInt KRiffChunkName01db = RiffChunkName('0','1','d','b');
    43 const TInt KRiffChunkName01dc = RiffChunkName('0','1','d','c');
    44 const TInt KRiffChunkNameXvid = RiffChunkName('X','V','I','D');
    45 const TInt KRiffChunkNameIdx1 = RiffChunkName('i','d','x','1');
    46 const TInt KRiffChunkNameStrd = RiffChunkName('s','t','r','d'); 
    47 const TInt KRiffChunkNameIndex = RiffChunkName('i','n','d','x');
    48 const TInt KRiffChunkNameVprp = RiffChunkName('v','p','r','p');
    49 const TInt KAVIF_ISINTERLEAVED = 0x00000001;
    50 
    51 
    52 
    53 
    54 //CAviReader Functions
    55 
    56 /**
    57 Fast read for non-aligned 16 bit data.
    58 @param aPtr
    59 @return
    60 */
    61 LOCAL_C TUint16 Read16(const TUint8* aPtr)
    62 	{
    63     return *(TUint16*)aPtr;
    64     }
    65 
    66 /**
    67 Fast read for non-aligned 32 bit data.
    68 @param aPtr
    69 @return
    70 */
    71 LOCAL_C TUint32 Read32(const TUint8* aPtr)
    72     {
    73     TUint32 x = *aPtr++;
    74     x |= *aPtr++ << 8;
    75     x |= *aPtr++ << 16;
    76     x |= *aPtr++ << 24;
    77     return x;
    78     }
    79 
    80 /**
    81 Creates CAviReader object.
    82 @param aClip
    83 @param aObserver
    84 @return CAviReader*
    85 */ 
    86 CAviReader* CAviReader::NewL(CMMFClip& aClip, MAviReaderObserver& aObserver)
    87     {
    88     CAviReader* self = new(ELeave) CAviReader(aClip, aObserver);
    89     CleanupStack::PushL(self);
    90     self->ConstructL();
    91     CleanupStack::Pop(self);
    92     return self;
    93     }
    94   
    95 /**
    96 Constructor of CAviReader
    97 */
    98 CAviReader::CAviReader(CMMFClip& aClip, MAviReaderObserver& aObserver)
    99          :MDataSink(KNullUid),iObserver(aObserver),iClip(aClip),iAudioIdx(KInvalidMediaIdx),
   100          iVideoIdx(KInvalidMediaIdx)
   101     {
   102     }
   103 
   104 /**
   105 Destructor of CAviReader
   106 */  
   107 CAviReader::~CAviReader()
   108     {
   109 	delete iVideoBuffer;
   110 	delete iAudioBuffer;
   111 	delete iSourceBuffer;
   112     }
   113 
   114 /**
   115 Second phase constructor.
   116 */ 
   117 void CAviReader::ConstructL()
   118     {
   119     if (iClip.Size() > 0)
   120     	{
   121     	iClip.SourcePrimeL();
   122     	iSourceBuffer = CMMFDescriptorBuffer::NewL(KReadBufferSize);
   123     	ReadFormatL();
   124     	}
   125      else
   126     	{
   127     	iClip.SourceStopL();
   128     	User::Leave(KErrCorrupt);
   129     	}
   130     }   
   131 
   132 /**
   133 Reads the header information in the clip.
   134 @leave KErrCorrupt if the header information is incorrect.
   135 */ 
   136 TInt CAviReader::ReadFormatL()
   137 	{
   138 	User::LeaveIfError(FindRiffChunksL());
   139 	return 0;
   140 	}
   141 	
   142 /**
   143 Reads the header information in the clip.
   144 @return KErrNone on Success or KErrCorrupt on incorrect header.
   145 */ 
   146 TInt CAviReader::FindRiffChunksL()
   147 	{
   148 	TBool videoEnabled = EFalse;
   149 	iClip.ReadBufferL(iSourceBuffer,0);
   150 	TUint8* rawform = &(iSourceBuffer->Data()[0]);
   151 	TUint8* pBufBegin =  rawform;
   152 	if (Read32(rawform) !=  KRiffChunkNameRiff)
   153 		{
   154 		return KErrCorrupt; //not a RIFF file	
   155 		}
   156 	rawform+=4;
   157 	rawform+=4;// skip file size
   158 	if (Read32(rawform) != KRiffChunkTypeAvi)
   159 		{
   160 	 	return KErrCorrupt;//not an .avi file
   161 		}
   162 	rawform+=4;
   163 	if (Read32(rawform) != KRiffChunkNameList)
   164 		{
   165 		return KErrCorrupt; 	//it is not a list
   166 		}
   167 	rawform+=4;
   168 	TUint32 dwToRead = Read32(rawform);
   169 	rawform+=4;//crossed the list size
   170 	if (Read32(rawform) !=KRiffChunkTypeHdrl)
   171 		{
   172 		return KErrCorrupt;
   173 		}
   174 	rawform+=4;
   175 	if (Read32(rawform) != KRiffChunkNameAvih)
   176 		{
   177 		return KErrCorrupt;	
   178 		}
   179 	rawform+=4;
   180 	rawform+=4; //skip chunk size
   181 	iMainHeader.iMicroSecPerFrame = Read32(rawform);rawform+=4;
   182 	iMainHeader.iMaxBytesPerSec = Read32(rawform);rawform+=4;
   183 	iMainHeader.iPaddingGranularity= Read32(rawform);rawform+=4;
   184 	//Audio gives underflow if the file is interleaved.So audio and video
   185 	//is read separately.
   186 	iMainHeader.iFlags= Read32(rawform); rawform+=4;
   187 	iMainHeader.iTotalFrames= Read32(rawform);rawform+=4;
   188 	iMainHeader.iInitialFrames= Read32(rawform);rawform+=4;
   189 	iMainHeader.iStreams	= Read32(rawform);rawform+=4;
   190 	if(iMainHeader.iStreams > 2)
   191 		{
   192 		return KErrCorrupt;
   193 		}
   194 	iMainHeader.iSuggestedBufferSize= Read32(rawform);rawform+=4;
   195 	iMainHeader.iWidth= Read32(rawform);rawform+=4;
   196 	iMainHeader.iHeight= Read32(rawform);rawform+=4;
   197 	iMainHeader.iReserved[0]= Read32(rawform);rawform+=4;
   198     iMainHeader.iReserved[1]= Read32(rawform);rawform+=4;
   199     iMainHeader.iReserved[2]= Read32(rawform);rawform+=4;
   200     iMainHeader.iReserved[3]= Read32(rawform);rawform+=4;
   201 
   202 	for (TUint8 i=0; i < iMainHeader.iStreams; i++)
   203 		{
   204 		if(Read32(rawform) != KRiffChunkNameList)
   205 			{
   206 			return KErrCorrupt;	
   207 			}
   208 		rawform+=4;
   209 		rawform+=4; //skip list size;
   210 		if(Read32(rawform) != KRiffChunkTypeStrl)
   211 			{
   212 			return KErrCorrupt;
   213 			}
   214 		rawform+=4;
   215 		if(Read32(rawform) != KRiffChunkNameStrh)
   216 			{
   217 			return KErrCorrupt;
   218 			}
   219 		rawform+=4;//read stream header chunk
   220 		rawform+=4; //skip stream header chunk size;
   221 		iStreamHeader[i].iFccType = Read32(rawform);rawform+=4;
   222 		iStreamHeader[i].iFccHandler = Read32(rawform);rawform+=4;
   223 		iStreamHeader[i].iFlags= Read32(rawform);rawform+=4; 
   224 		iStreamHeader[i].iReserved = Read32(rawform);rawform+=4;
   225 		iStreamHeader[i].iInitialFrames =Read32(rawform);rawform+=4;
   226 		iStreamHeader[i].iScale =Read32(rawform);rawform+=4;
   227 		iStreamHeader[i].iRate= Read32(rawform);rawform+=4;
   228 		iStreamHeader[i].iStart = Read32(rawform);rawform+=4;
   229 		iStreamHeader[i].iLength = Read32(rawform);rawform+=4;
   230 		iStreamHeader[i].iSuggestedBufferSize = Read32(rawform);rawform+=4;
   231 		iStreamHeader[i].iQuality = Read32(rawform);rawform+=4;
   232 		iStreamHeader[i].iSampleSize = Read32(rawform);rawform+=4;
   233 		iStreamHeader[i].iRcFrame.iLeft =Read16(rawform);rawform+=2;
   234 		iStreamHeader[i].iRcFrame.iTop =Read16(rawform);rawform+=2;
   235 		iStreamHeader[i].iRcFrame.iRight =Read16(rawform);rawform+=2;
   236 		iStreamHeader[i].iRcFrame.iBottom =Read16(rawform);rawform+=2;
   237 		if (Read32(rawform) != KRiffChunkNameStrf)		
   238 			{
   239 			return KErrCorrupt;		
   240 			}
   241 		rawform+=4;//read stream format chunk
   242 		TInt chunklen = Read32(rawform);
   243 		rawform+=4; //skip stream format chunk size;	
   244 	
   245 		if (iStreamHeader[i].iFccType == KRiffChunkTypeAuds) //if audio stream
   246 			{
   247 			if(iAudioEnabled)
   248 				{
   249 				return KErrCorrupt;	
   250 				}
   251 			iAudioEnabled = ETrue;
   252 			if (Read16(rawform) == 0x0001) // Do not have support except PCM
   253 				{
   254 	    		iPCMWaveFormat.iWaveFormat.iFormatTag = Read16(rawform);rawform+=2;
   255                 iPCMWaveFormat.iWaveFormat.iNChannels = Read16(rawform);rawform+=2;
   256                 iPCMWaveFormat.iWaveFormat.iNSamplesPerSec = Read32(rawform);rawform+=4; 
   257                  iPCMWaveFormat.iWaveFormat.iNAvgBytesPerSec= Read32(rawform); rawform+=4;
   258                 iPCMWaveFormat.iWaveFormat.iNBlockAlign = Read16(rawform);rawform+=2;
   259                 iPCMWaveFormat.iBitsPerSample = Read16(rawform);rawform+=2;                
   260 
   261 	    		iAudioIdx = i;				
   262 				}
   263 			else
   264 				{
   265 				return KErrNotSupported;
   266 				}
   267 			}
   268 			
   269 		else if (iStreamHeader[i].iFccType == KRiffChunkTypeVids) //if video stream
   270 			{
   271 			if(iStreamHeader[i].iFccHandler != KRiffChunkNameXvid) 
   272 				{
   273 				return KErrNotSupported;
   274 				}
   275 			if(videoEnabled)
   276 				{
   277 				return KErrCorrupt;	
   278 				}
   279 				
   280 			TUint8* temp =  rawform;
   281 			
   282 			iBitmapInfoHeader.iBiSize= Read32(rawform);rawform+=4;
   283             iBitmapInfoHeader.iBiWidth= Read32(rawform);rawform+=4;
   284             iBitmapInfoHeader.iBiHeight= Read32(rawform);rawform+=4;
   285             iBitmapInfoHeader.iBiPlanes= Read16(rawform);rawform+=2;
   286             iBitmapInfoHeader.iBiBitCount= Read16(rawform);rawform+=2;
   287             iBitmapInfoHeader.iBiCompression= Read32(rawform);rawform+=4;
   288             iBitmapInfoHeader.iBiSizeImage= Read32(rawform);rawform+=4;
   289             iBitmapInfoHeader.iBiXPelsPerMeter= Read32(rawform);rawform+=4;
   290             iBitmapInfoHeader.iBiYPelsPerMeter= Read32(rawform);rawform+=4;
   291             iBitmapInfoHeader.iBiClrUsed= Read32(rawform);rawform+=4;
   292             iBitmapInfoHeader.iBiClrImportant= Read32(rawform);rawform+=4;
   293             
   294             rawform = temp + chunklen;
   295 
   296 			iVideoIdx = i;
   297 			videoEnabled = ETrue;
   298 			}
   299 		else				//if unidentified stream types.
   300 			{
   301 			return KErrCorrupt;
   302 			}
   303 	
   304 		TUint32 temp = Read32(rawform);	
   305 		while (temp == KRiffChunkNameStrn || temp == KRiffChunkNameStrd || temp == KRiffChunkNameJunk || temp == KRiffChunkNameIndex || temp == KRiffChunkNameVprp) // Skipping the chunks
   306 			{
   307 			rawform+=4;
   308 			temp = Read32(rawform);
   309 			rawform+=4+temp;
   310 			temp = Read32(rawform);
   311 			}
   312 		}
   313 	
   314 	//added to skip the rest of the header to reach movi list. 
   315 	TInt bytesRead = rawform - pBufBegin;
   316 	iSourcePos = bytesRead;
   317 	
   318 	for (TInt i = 0; i < KReadBufferSize - bytesRead; i ++)
   319 		{
   320 		if(Read32(rawform) == KRiffChunkTypeMovi)
   321 			{
   322 			iSourcePos += i + 4;
   323 			iAudioPos = iSourcePos;
   324 			iVideoPos = iSourcePos;
   325 			break;
   326 			}
   327 		rawform += 1;	
   328 		}
   329 	
   330 	return KErrNone;
   331 	}
   332 
   333 /**
   334 Fills the aBuffer with video data depends on interleaved or not.
   335 @param aBuffer 
   336 */ 
   337 void CAviReader::FillVideoBufferL(TVideoInputBuffer* aBuffer)
   338 	{
   339 	if (!aBuffer)
   340 		{
   341 		User::Leave(KErrArgument);
   342 		}
   343 	iBufferFromDevVideo = aBuffer;
   344 	iVideoRequestMade = ETrue;
   345 
   346 	if (iMainHeader.iFlags == KAVIF_ISINTERLEAVED)
   347 		{
   348 		
   349 		//Here Audio and Video data are interleaved in the form of REc lists.
   350 		if (!iReadRequestMade) 
   351 			{
   352 			//Read request for REC list is not yet made. So read the REC list into the sourcebuffer.
   353 			ReadNextFrameL(TUid::Null(), iSourcePos);
   354 			iReadRequestMade = ETrue;
   355 			}
   356 
   357 		else if (iReadCompleted)
   358 			{
   359 			//REC list is already read into the video buffer.
   360 			//copy the data from the video buffer to devvideo buffer.
   361 			aBuffer->iData.Copy(iVideoBuffer->Data());
   362 			ReadComplete();
   363 			}
   364 		}
   365 
   366 	else
   367 		{
   368 		//There are no REC lists. Audio and Video is spread across the file. So we read audio and video
   369 		//chunks independently
   370 		ReadNextFrameL(KUidMediaTypeVideo, iVideoPos);
   371 		}
   372 	}
   373 
   374 /**
   375 Fills the aBuffer with audio data depends on interleaved or not.
   376 @param aBuffer 
   377 */ 
   378 void CAviReader::FillAudioBufferL(CMMFBuffer* aBuffer)
   379 	{
   380 	if (!aBuffer)
   381 		{
   382 		User::Leave(KErrArgument);
   383 		}
   384 	iBufferFromDevSound = aBuffer;
   385 	iAudioRequestMade = ETrue;
   386 	if (iMainHeader.iFlags == KAVIF_ISINTERLEAVED)
   387 		{
   388 		//Here Audio and Video data are interleaved in the form of REc lists.
   389 		if (!iReadRequestMade)
   390 			{
   391 			//Read request for REC list is not yet made. So read the REC list into the sourcebuffer.
   392 			ReadNextFrameL(TUid::Null(), iSourcePos);
   393 			iReadRequestMade = ETrue;
   394 			}
   395 		else if (iReadCompleted)
   396 			{
   397 			//audio frame is already read into the audio buffer
   398 			//copy the data from the audio buffer to devsound buffer.
   399 			CMMFDataBuffer* bufferFromSink = static_cast<CMMFDataBuffer*>(aBuffer);
   400 			bufferFromSink->Data().Copy(iAudioBuffer->Data());
   401 			ReadComplete();
   402 			}
   403 		}
   404 	else
   405 		{
   406 		if (iAudioBuffer)
   407 			{
   408 			BufferFilledL(iAudioBuffer);
   409 			}
   410 		else
   411 			{
   412 			//non-interleaved
   413 			ReadNextFrameL(KUidMediaTypeAudio, iAudioPos);
   414 			}
   415 		}
   416 	}			
   417 
   418 /**
   419 Identifies if the chunk is valid by the media type and fills the data in buffer
   420 @param aMediaType
   421 @param aPosition
   422 */
   423 void CAviReader::ReadNextFrameL(TUid aMediaType, TInt& aPosition)
   424 	{
   425 	TUint32 dwChunkId = 0;
   426 	TUint32 dwChunkSz = 0;
   427 	TUint8* rawForm = NULL;
   428 	
   429 	//We read chunkId and chunkSize first into the headerframe below. If Audio and Video chunks are found, data is read into the respective buffers 
   430 	//we skip chunkSize bytes if we come across any other blocks.
   431 	CMMFDescriptorBuffer* headerFrame = CMMFDescriptorBuffer::NewL(KChunkHeaderSize);
   432     CleanupStack::PushL(headerFrame);
   433     
   434 	for(;;)
   435 		{
   436 		iClip.ReadBufferL(headerFrame, aPosition);
   437 		TInt len = headerFrame->Data().Length();
   438 		if (len == 0)
   439 			{
   440 			SetMediaEOS(aMediaType);
   441 			break;
   442 			}
   443 			
   444 		rawForm = &(headerFrame->Data()[0]);
   445 		dwChunkId = Read32(rawForm);
   446 		if (!IsValidBlock(dwChunkId))
   447 			{
   448 			//Sometimes we dont get next chunk immediately after the Previous chunk(Padding). 
   449 			//we need to search for next valid data chunk ourselves if the chunkId read is not valid
   450 			if (!ReadNextFrameStartL(aPosition))
   451 				{
   452 				//no more data frames
   453 				SetMediaEOS(aMediaType);
   454 				break;
   455 				}
   456 			continue;//found valid chunk. so continue to read the chunk
   457 			}
   458 
   459 		rawForm += 4; //Skip ChunkId
   460 		aPosition += 4; //Skip ChunkId 
   461 		dwChunkSz = Read32(rawForm);
   462 							
   463 		rawForm+=4; //Skip ChunkSize
   464 		aPosition += 4; //Skip ChunkSIze
   465 
   466 		if (dwChunkSz == 0)
   467 			{
   468 			//We may get chunks of length Zero. So loop again to read the next chunk.
   469 			continue;
   470 			}
   471 		if (dwChunkId == KRiffChunkNameList)//list rec
   472 			{
   473 			if(iMainHeader.iFlags == KAVIF_ISINTERLEAVED)
   474 				{
   475 				//found REC list. Read the whole list into the SourceBuffer
   476 				delete iSourceBuffer;
   477 				iSourceBuffer = NULL;
   478 				iSourceBuffer = CMMFDescriptorBuffer::NewL(dwChunkSz);
   479 				iClip.ReadBufferL(iSourceBuffer,aPosition, this);
   480 				aPosition += dwChunkSz;//skip the list size
   481 				break;
   482 				}
   483 			else
   484 				{
   485 				continue;
   486 				}
   487 			}
   488 		else if (dwChunkId == KRiffChunkNameJunk)//junk
   489 			{
   490 			//found Junk chunk. Skip it.
   491 			aPosition += dwChunkSz;
   492 			}
   493 		else if ((dwChunkId == KRiffChunkName00db) || (dwChunkId == KRiffChunkName00dc)
   494 			|| (dwChunkId == KRiffChunkName01db) || (dwChunkId == KRiffChunkName01dc)) //video
   495 			{
   496 			if (aMediaType == KUidMediaTypeVideo)
   497 				{
   498 				//found video when aMediaType is Video. So read the video chunk into the videobuffer.
   499 				delete iVideoBuffer;
   500 				iVideoBuffer = NULL;
   501 				iVideoBuffer = CMMFDescriptorBuffer::NewL(dwChunkSz);
   502 				iClip.ReadBufferL(iVideoBuffer,aPosition, this);
   503 				aPosition += dwChunkSz;
   504 				break;
   505 				}
   506 			else
   507 				{
   508 				//found video when aMediaType is not Video. So Skip it.
   509 				aPosition += dwChunkSz;	
   510 				}
   511 			}
   512 		else if ((dwChunkId == KRiffChunkName00wb) || (dwChunkId == KRiffChunkName01wb)) //audio
   513 			{
   514 			if (aMediaType == KUidMediaTypeAudio)
   515 				{
   516 				//found audio when aMediaType is Audio. So read the audio chunk into the audiobuffer.
   517 				delete iAudioBuffer;
   518 				iAudioBuffer = NULL;
   519 				iAudioBuffer = CMMFDescriptorBuffer::NewL(dwChunkSz);
   520 				iClip.ReadBufferL(iAudioBuffer,aPosition, this);	
   521 				aPosition += dwChunkSz;
   522 				break;	
   523 				}
   524 			else
   525 				{
   526 				//found audio when aMediaType is not audio. So Skip it.
   527 				aPosition += dwChunkSz;
   528 				}		
   529 			}
   530 		else if (dwChunkId == KRiffChunkNameIdx1)//index block
   531 			{
   532 			aPosition += dwChunkSz;
   533 			//Reached index block. This is placed at the end of the data. No more data
   534 			SetMediaEOS(aMediaType);
   535 			break;
   536 			}
   537 	   }
   538 	CleanupStack::PopAndDestroy(headerFrame);
   539 	
   540 	}		
   541 
   542 
   543 /**
   544 Loops through until a valid chunk is identified.
   545 @param aStartPos
   546 @return ETrue if valid chunk is found.
   547 */
   548 TBool CAviReader::ReadNextFrameStartL(TInt& aStartPos)
   549 	{
   550 	TBool found = EFalse;
   551 	TInt count = 0;
   552 
   553 	CMMFDescriptorBuffer* buffer = CMMFDescriptorBuffer::NewL(KReadBufferSize);
   554     CleanupStack::PushL(buffer);
   555 	iClip.ReadBufferL(buffer, aStartPos);
   556 
   557 	TUint8* rawform = &(buffer->Data()[0]);
   558 	
   559 	while (count < KReadBufferSize)
   560 		{
   561 		if (IsValidBlock(Read32(rawform)))
   562 			{
   563 			found = ETrue;
   564 			break;
   565 			}
   566 		aStartPos++;
   567 		rawform++;
   568 		count++;
   569 		}
   570 	CleanupStack::PopAndDestroy(buffer);
   571 	return found;
   572 	}
   573 
   574 /**
   575 Identifies a valid audio and video chunk is present
   576 @param aChunkId
   577 @return ETrue if validblock is found else EFalse.
   578 */
   579 TBool CAviReader::IsValidBlock(TUint aChunkId) 
   580 	{
   581 	switch(aChunkId)
   582 		{
   583 		case KRiffChunkName00wb:
   584 		case KRiffChunkName01wb:
   585 		case KRiffChunkName00db:
   586 		case KRiffChunkName00dc:
   587 		case KRiffChunkName01db:
   588 		case KRiffChunkName01dc:	
   589 		case KRiffChunkNameList:
   590 		case KRiffChunkNameJunk:
   591 		case KRiffChunkNameIdx1:
   592 			return ETrue;
   593 		default:
   594 			return EFalse;
   595 		}
   596 	}			
   597 
   598 /**
   599 Fills the buffer with audio/Video data and informs the observer
   600 @param aBuffer
   601 */
   602 void CAviReader::BufferFilledL(CMMFBuffer* aBuffer)
   603 	{
   604 	if (!aBuffer)
   605 		{
   606 		User::Leave(KErrArgument);
   607 		}
   608 	if (aBuffer == iVideoBuffer)
   609 		{
   610 		//callback for video read when the file is not interleaved(No REC lists)
   611 		iBufferFromDevVideo->iData.Copy(iVideoBuffer->Data());
   612 		iObserver.VideoBufferFilled(iBufferFromDevVideo);
   613 		}
   614 	else if (aBuffer == iAudioBuffer) 
   615 		{
   616 		//callback for audio read when the file is not interleaved(No REC lists)
   617 		CMMFDataBuffer* bufferFromSink = static_cast<CMMFDataBuffer*>(iBufferFromDevSound);
   618 
   619 		TInt sinkBufLen = bufferFromSink->Data().MaxSize();
   620 		TInt audBufLen = iAudioBuffer->Data().Length();
   621 		
   622 		if (sinkBufLen < audBufLen)
   623 			{
   624 			bufferFromSink->Data().Copy(iAudioBuffer->Data().Ptr(), sinkBufLen);
   625 			CMMFDescriptorBuffer* tempBuffer = CMMFDescriptorBuffer::NewL(audBufLen - sinkBufLen);
   626 			tempBuffer->Data().Copy(iAudioBuffer->Data().Mid(sinkBufLen));
   627 			delete iAudioBuffer;
   628 			iAudioBuffer = tempBuffer;
   629 			}
   630 		else
   631 			{
   632 			// DEF113319 - call SetLastBuffer when sending last audio chunk
   633 			TInt position = 0;
   634 			position = (iMainHeader.iFlags == KAVIF_ISINTERLEAVED) ? iSourcePos : iAudioPos;
   635 			if(!IsAudioDataAvailableL(position))
   636 				{
   637 				bufferFromSink->SetLastBuffer(ETrue);
   638 				SetMediaEOS(KUidMediaTypeAudio);
   639 				}
   640 
   641 			bufferFromSink->Data().Copy(iAudioBuffer->Data());
   642 			delete iAudioBuffer;
   643 			iAudioBuffer = NULL;
   644 			}
   645 		iObserver.AudioBufferFilled();
   646 		}
   647 	else if (aBuffer == iSourceBuffer)//callback for REC list
   648 		{
   649 		//callback for REC list read. We need to extract video and audio chunks from the sourcebuffer
   650 		TUint8* rawform = &(iSourceBuffer->Data()[0]);
   651 		TInt desPos = 0; //position in descriptor
   652 
   653 		//Now we should be pointing to audio or video chunks
   654 		TInt bufLen = iSourceBuffer->Data().Length();
   655 		if(bufLen < 4)
   656 			{
   657 			User::Leave(KErrCorrupt);	
   658 			}
   659 		rawform += 4; //skip the fourcc of REC
   660 		desPos += 4; //byte count corresponding to where rawform points to
   661 		
   662 		if (bufLen - desPos < 8)
   663 		 	{
   664 		 	//if the buffer is not long enough to accomodate - chunk id and size leave
   665 		  	User::Leave(KErrCorrupt);
   666 		  	}
   667 
   668 		for (TUint8 i=0; i < iMainHeader.iStreams; i++)//we expect only 2 streams at the moment
   669 			{
   670 			if (desPos == bufLen) //caution check for the necessity of the block
   671 				{
   672 	 			//Sometimes we only have one stream in this list. No more data to read
   673 				break;
   674 				}
   675 
   676 			if (bufLen - desPos < 8 && i== 1)
   677 			 	{
   678 			 	//if the buffer is not long enough to accomodate - chunk id and size leave
   679 			  	break;
   680 			  	}
   681 
   682 			TUint32 dwChunkId = Read32(rawform);
   683 			rawform += 4; //Skip chunkId
   684 			desPos += 4;
   685 			TBool bAudioId = EFalse;
   686 			TBool bVideoId = EFalse;
   687 			switch (dwChunkId)	//identify chunk
   688 				{
   689 				case KRiffChunkName00db:
   690 				case KRiffChunkName00dc:
   691 				case KRiffChunkName01db:
   692 				case KRiffChunkName01dc:
   693 					bVideoId = ETrue;
   694 					break;
   695 				case KRiffChunkName00wb:
   696 				case KRiffChunkName01wb:
   697 					bAudioId = ETrue;
   698 					break;
   699 				default:
   700 					User::Leave(KErrCorrupt);
   701 				}
   702 			
   703 			if (!bAudioId && !bVideoId)
   704 				{
   705 				//we are supposed to get audio or video stream here. if anything else, we return KErrCorrupt				
   706 				User::Leave(KErrCorrupt);
   707 				}
   708 			TUint32 dwChunkSz = Read32(rawform);
   709 			if (dwChunkSz > bufLen - desPos)
   710 				{
   711 				User::Leave(KErrCorrupt); //caution - check	
   712 				}
   713 			rawform += 4; //Skip chunkSize
   714 			desPos += 4;
   715 			TPtr8 temp = iSourceBuffer->Data().MidTPtr(desPos, dwChunkSz);
   716 			if (bVideoId)// video
   717 				{
   718 				if (iVideoRequestMade)
   719 					{
   720 					//if video request is already made we can copy the data directly into the devvideo buffer
   721 					//instead of iVideoBuffer
   722 					iBufferFromDevVideo->iData.Copy(temp);
   723 					}
   724 				else 
   725 					{
   726 					//DevVideo request is not made. So copy the data into video buffer
   727 					delete iVideoBuffer;
   728 					iVideoBuffer = NULL;
   729 					iVideoBuffer = CMMFDescriptorBuffer::NewL(dwChunkSz);
   730 					iVideoBuffer->Data().Copy(temp);
   731 					}
   732 				}
   733 			else if (bAudioId)//audio
   734 				{
   735 				if (iAudioRequestMade)
   736 					{
   737 					//if audio request is already made, copy the data into devsound buffer
   738 					CMMFDataBuffer* bufferFromSink = static_cast<CMMFDataBuffer*>(iBufferFromDevSound);
   739 					bufferFromSink->Data().Copy(temp);
   740 					}
   741 				else 
   742 					{
   743 					//DevSound request is not made. copy the audio chunk into audio buffer
   744 					delete iAudioBuffer;
   745 					iAudioBuffer = NULL;
   746 					iAudioBuffer = CMMFDescriptorBuffer::NewL(dwChunkSz);
   747 					iAudioBuffer->Data().Copy(temp);
   748 					}
   749 				}
   750 			rawform	+= dwChunkSz;//Skip video/audio chunk
   751 			desPos += dwChunkSz;	
   752 			}
   753 		iReadCompleted = ETrue;//REC list is read
   754 		// we send the bufferfilled callbacks after both audio and video requests are made.
   755 		ReadComplete();
   756 		}
   757 	else
   758 		{
   759 		User::Leave(KErrCorrupt);
   760 		}
   761 	}
   762 
   763 /**
   764 Informs audio and video data in rec list is read and the buffer can
   765 now be sent for decoding.This function is specific for interleaved files
   766 where it is sent for decoding only after both audio and video data is read.
   767 */
   768 void CAviReader::ReadComplete()
   769 	{
   770 	if ((iAudioRequestMade) && (iVideoRequestMade))
   771 		{
   772 		//reset back everything for the next cycle
   773 		iReadRequestMade = EFalse;
   774 		iReadCompleted = EFalse;
   775 		iAudioRequestMade = EFalse;
   776 		iVideoRequestMade = EFalse;
   777 		iObserver.VideoBufferFilled(iBufferFromDevVideo);
   778 		iObserver.AudioBufferFilled();
   779 		}
   780 	}
   781 
   782 /**
   783 Resets the data positions in the file 
   784 */			
   785 void CAviReader::ResetL()
   786 	{
   787 	iVideoEos = EFalse;
   788 	iAudioEos = EFalse;
   789 	iAudioPos = iSourcePos;
   790 	iVideoPos = iSourcePos;
   791 	iReadRequestMade = EFalse;
   792 	iReadCompleted = EFalse;
   793 	iAudioRequestMade = EFalse;
   794 	iVideoRequestMade = EFalse;
   795 	iClip.SourceStopL();
   796 	}
   797 
   798 /**
   799 Identifies if video data in the clip is fully read.
   800 @return ETrue if end of videodata
   801 */			
   802 TBool CAviReader::IsVideoInputEnd()
   803 	{
   804 	return iVideoEos;		
   805 	}
   806 
   807 /**
   808 Identifies if audio data in the clip is fully read.
   809 @return ETrue if end of audiodata
   810 */		
   811 TBool CAviReader::IsAudioInputEnd()
   812 	{
   813 	return iAudioEos;		
   814 	}
   815 	
   816 /**
   817 Set the position in the file to play from
   818 @param aPosition - this is not used.
   819 @leave KErrNotSupported.
   820 */
   821 void CAviReader::SetPositionL(TInt /*aPosition*/)
   822 	{
   823 	//This will leave KErrNotSuuported as there is no support to
   824 	//seek the position in an .avi file.
   825 	User::Leave(KErrNotSupported);
   826 	}
   827 
   828 /**
   829 Returns if audio is enabled in an .avi file.
   830 @param aEnabled.
   831 */
   832 void CAviReader::AudioEnabled(TBool& aEnabled)
   833 	{
   834 	aEnabled = iAudioEnabled;
   835 	}
   836 	
   837 
   838 /**
   839 Returns the frame rate applied for video
   840 @param aFramesPerSecond
   841 */
   842 void CAviReader::FrameRate(TReal32 &aFramesPerSecond)
   843 	{
   844 	ASSERT(iVideoIdx > KInvalidMediaIdx);
   845 	if (iStreamHeader[iVideoIdx].iScale == 0)	
   846 		{
   847 		//If this value is 0 consider it as 1 second.
   848 		iStreamHeader[iVideoIdx].iScale = 1; 
   849 		}	
   850 	aFramesPerSecond = iStreamHeader[iVideoIdx].iRate;	
   851 	}
   852 
   853 /**
   854 Returns the sample rate applied for audio.
   855 @return audio samplerate 
   856 */	
   857 TInt CAviReader::SampleRate()
   858 	{
   859 	ASSERT(iAudioIdx > KInvalidMediaIdx);
   860 	return iPCMWaveFormat.iWaveFormat.iNSamplesPerSec ;
   861 	}
   862 
   863 /**
   864 Returns the number of channels set in audio.
   865 @return number of audio channels.
   866 */	
   867 TInt CAviReader::Channels()
   868 	{
   869 	ASSERT(iAudioIdx > KInvalidMediaIdx);
   870 	return iPCMWaveFormat.iWaveFormat.iNChannels;
   871 	}
   872 
   873 /**
   874 Returns the bits per sample for audio.
   875 @return bitspersample
   876 */
   877 TInt CAviReader::BitsPerSample()
   878 	{
   879 	ASSERT(iAudioIdx > KInvalidMediaIdx);
   880 	return iPCMWaveFormat.iBitsPerSample;
   881 	}
   882 	
   883 
   884 /**
   885 Returns the framesize of video file.
   886 @param aFrameSize
   887 */
   888 void CAviReader::VideoFrameSize(TSize &aFrameSize)
   889 	{
   890 	ASSERT(iVideoIdx > KInvalidMediaIdx);
   891 	aFrameSize.iHeight = iMainHeader.iHeight;
   892 	aFrameSize.iWidth =  iMainHeader.iWidth;
   893 	}	
   894 	
   895 /**
   896 Returns the Video codec used in the video file
   897 @param aMimeType -this is not used
   898 */
   899 void CAviReader::VideoMimeType(TDes8& /*aMimeType*/)
   900 	{
   901 	//there is no conversion from fcchandler to descriptor
   902 	}
   903 
   904 /**
   905 Returns the audioCodec used in the video file. 
   906 @param aCodec
   907 */	
   908 void CAviReader::AudioCodec(TFourCC& /*aCodec*/)
   909 	{
   910 	//there is no conversion from iFccHandler to descriptor
   911 	}
   912 
   913 /**
   914 Returns the duration of video file.
   915 @return Duration of the file in TTimeIntervalMicroSeconds
   916 */
   917 TTimeIntervalMicroSeconds CAviReader::Duration() const
   918 	{
   919 	ASSERT(iVideoIdx > KInvalidMediaIdx);
   920 	ASSERT(iStreamHeader[iVideoIdx].iRate);
   921 	return (iMainHeader.iTotalFrames*1000000)/iStreamHeader[iVideoIdx].iRate;				
   922 	}
   923 	
   924 /**
   925 Sets the playwindow for playing audio and video.
   926 @param aStart
   927 @param aEnd
   928 */	
   929 void CAviReader::SetPlayWindowL(TTimeIntervalMicroSeconds /*aStart*/,TTimeIntervalMicroSeconds /*aEnd*/)
   930 	{
   931 	//this will leave with KErrNotSupported as there is no
   932 	//support for seeking the position in the file.
   933 	User::Leave(KErrNotSupported);
   934 	}
   935 	
   936 /**
   937 Sets the end of audio and video data.
   938 @param aMediaType
   939 */	
   940 void CAviReader::SetMediaEOS(TUid aMediaType)	
   941 	{
   942 	if (aMediaType == KUidMediaTypeAudio) //end of audio
   943 		{
   944 		iAudioEos = ETrue;	
   945 		}
   946 	else if (aMediaType == KUidMediaTypeVideo)//end of video
   947 		{
   948 		iVideoEos = ETrue;
   949 		}
   950 	else //end of REC lists
   951 		{
   952 		iAudioEos = ETrue;
   953 		iVideoEos = ETrue;
   954 		}
   955 	}
   956 
   957 //MDataSink
   958 CMMFBuffer* CAviReader::CreateSinkBufferL(TMediaId /*aMediaId*/, TBool&/*aReference*/)
   959 	{
   960 	User::Leave(KErrNotSupported);
   961 	return NULL;
   962 	}
   963 
   964 void CAviReader::ConstructSinkL( const TDesC8& /*aInitData*/)
   965 	{
   966 	User::Leave(KErrNotSupported);
   967 	}
   968 	
   969 TFourCC CAviReader::SinkDataTypeCode(TMediaId /*aMediaId*/)
   970 	{
   971 	return 0;
   972 	}
   973 		
   974 void CAviReader::EmptyBufferL(CMMFBuffer* /*aBuffer*/, MDataSource* /*aSupplier*/, TMediaId /*aMediaId*/)
   975 	{
   976 	User::Leave(KErrNotSupported);
   977 	}
   978 	
   979 TBool CAviReader::CanCreateSinkBuffer()
   980 	{
   981 	return EFalse;	
   982 	}
   983 
   984 /**
   985 // DEF113319 - added to check last audio chunk
   986 Loops through to check whether valid audio chunk is available.
   987 @param aStartPos
   988 @return ETrue if valid audio chunk is found.
   989 */
   990 TBool CAviReader::IsAudioDataAvailableL(TInt aStartPos)
   991 	{
   992 	TBool foundValidAudioChunk = EFalse;
   993 	TUint32 dwChunkId = 0;
   994 	TUint8* rawform = NULL;
   995 
   996 	CMMFDescriptorBuffer* headerFrame = CMMFDescriptorBuffer::NewL(KChunkHeaderSize);
   997     CleanupStack::PushL(headerFrame);
   998 	
   999 	for(;;)
  1000 		{
  1001 		iClip.ReadBufferL(headerFrame, aStartPos);
  1002 		TInt len = headerFrame->Data().Length();
  1003 		if (len == 0)
  1004 			{
  1005 			// end of stream
  1006 			break;
  1007 			}
  1008 		rawform = &(headerFrame->Data()[0]);
  1009 		dwChunkId = Read32(rawform);
  1010 		
  1011 		if (!IsValidBlock(dwChunkId))
  1012 			{
  1013 			// No valid chunk id found ... 
  1014 			//Sometimes we dont get next chunk immediately after the Previous chunk(Padding). 
  1015 			//we need to search for next valid data chunk ourselves if the chunkId read is not valid
  1016 			if (!ReadNextFrameStartL(aStartPos))
  1017 				{
  1018 				// reached EOS 
  1019 				break;
  1020 				}
  1021 			continue;//found valid chunk. so continue to read the chunk
  1022 			}
  1023 		if ((dwChunkId == KRiffChunkName00wb) || (dwChunkId == KRiffChunkName01wb)) // check if its valid audio chunk
  1024 			{
  1025 			foundValidAudioChunk = ETrue;
  1026 			break;
  1027 			}
  1028 		// non audio chunk found, so go and look for next frame header
  1029 		rawform += 4; //Skip ChunkId
  1030 		aStartPos += ((Read32(rawform)) + 4 + 4); //Skip: 1. dwChunkSz, 2. ChunkSize(4), 3.ChunkId(4) 
  1031 		}
  1032 	CleanupStack::PopAndDestroy(headerFrame);
  1033 	return foundValidAudioChunk;
  1034 	}