mmserv/thumbnailengine/TneProcessorSrc/mp4parser.cpp
changeset 0 71ca22bcf22a
equal deleted inserted replaced
-1:000000000000 0:71ca22bcf22a
       
     1 /*
       
     2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   TNE Parser
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 // INCLUDE FILES
       
    21 #include    "mp4parser.h"
       
    22 #include    "TNEProcessorImpl.h"
       
    23 #include    "TNEVideosettings.h"
       
    24 
       
    25 // ASSERTIONS
       
    26 #define MPASSERT(x) __ASSERT_DEBUG(x, User::Panic(_L("CTNEProcessorImpl"), EInternalAssertionFailure))
       
    27 
       
    28 #ifdef _DEBUG
       
    29 #include <e32svr.h>
       
    30 #define PRINT(x) RDebug::Print x;
       
    31 #else
       
    32 #define PRINT(x)
       
    33 #endif
       
    34 
       
    35 // LOCAL CONSTANTS AND MACROS
       
    36 #ifdef _DEBUG
       
    37 const TInt KErrorCode = CParser::EParserFailure;
       
    38 #else
       
    39 const TInt KErrorCode = KErrGeneral;
       
    40 #endif
       
    41 
       
    42 const TUint KNumFramesInOneRun = 10;
       
    43 
       
    44 // ================= MEMBER FUNCTIONS =======================
       
    45 
       
    46 // C++ default constructor can NOT contain any code, that
       
    47 // might leave.
       
    48 //
       
    49 
       
    50 CMP4Parser::CMP4Parser()
       
    51 {       
       
    52 	iMP4Handle = 0;
       
    53 	iVideoType = 0;
       
    54 	iBytesRead = 0;
       
    55 	iFirstRead = ETrue;		// added for Mp4
       
    56 	iFirstFrameInfo = ETrue;  // added for Mp4
       
    57 	iOutputNumberOfFrames = 0; 
       
    58     iStreamSource = ESourceFile;
       
    59 	iFrameNumber=0;
       
    60 	iFirstTimeClipParsing=ETrue;
       
    61     iStartFrameIndex=0;		
       
    62 }
       
    63 
       
    64 // Two-phased constructor.
       
    65 
       
    66 CMP4Parser* CMP4Parser::NewL(CTNEProcessorImpl* aProcessor, RFile& aFileHandle)
       
    67 {
       
    68 	CMP4Parser *self = new (ELeave) CMP4Parser;
       
    69 	CleanupStack::PushL(self);    
       
    70 	
       
    71 	self->ConstructL(aProcessor, aFileHandle);
       
    72 
       
    73 	CleanupStack::Pop();  // self
       
    74 	
       
    75 	return self;
       
    76 }
       
    77 
       
    78 // Symbian OS default constructor can leave.
       
    79 
       
    80 void CMP4Parser::ConstructL(CTNEProcessorImpl* aProcessor, RFile& aFileHandle)
       
    81 {
       
    82 	MP4Err error;
       
    83 	iProcessor = aProcessor; 
       
    84 
       
    85 	// open MP4 library
       
    86     if ( iStreamSource == ESourceFile )
       
    87 		{
       
    88 			iFileHandle.Duplicate(aFileHandle);
       
    89 			error = MP4ParseOpenFileHandle(&iMP4Handle, &iFileHandle);
       
    90 		}
       
    91     else
       
    92 		{
       
    93 			error = MP4ParseOpen(&iMP4Handle, 0);        
       
    94 		}
       
    95 		
       
    96     if (error != MP4_OK)
       
    97 		{
       
    98             if (error == MP4_OUT_OF_MEMORY)
       
    99                 User::Leave(KErrNoMemory);
       
   100             else
       
   101                 User::Leave(KErrorCode);
       
   102 		}
       
   103 }
       
   104 
       
   105 // Destructor
       
   106 CMP4Parser::~CMP4Parser()
       
   107 {
       
   108 	// Close the Duplicate file handle
       
   109 	iFileHandle.Close();
       
   110 	
       
   111     if (iMP4Handle)
       
   112         MP4ParseClose(iMP4Handle);
       
   113 
       
   114     iMP4Handle = 0;
       
   115 }
       
   116 
       
   117 
       
   118 // ---------------------------------------------------------
       
   119 // CMP4Parser::GetNextFrameInformation
       
   120 // Get type (streaming-case), length and availability of next frame to be fetched
       
   121 // using MP4 library API functions
       
   122 // (other items were commented in a header).
       
   123 // ---------------------------------------------------------
       
   124 //
       
   125 
       
   126 TInt CMP4Parser::GetNextFrameInformation(TFrameType& aType, TUint& aLength, TBool& aIsAvailable)
       
   127 {   
       
   128 	
       
   129 	// If aType == EFrameTypeNone, the type of next frame is retrieved 
       
   130 	// (valid only in streaming case)
       
   131 	// Otherwise, only the length of next specified type of frame is retrieved
       
   132 	MPASSERT(iStreamSource != ESourceNone);            
       
   133 	
       
   134 	mp4_u32 type = MP4_TYPE_NONE;
       
   135 	MP4Err error;
       
   136 
       
   137 	aIsAvailable = 0;    
       
   138 	if ( iNextFrameType == EFrameTypeNone )
       
   139 		// if the mp4 library is reading a file, a frame has always been read when 
       
   140 		// we come here
       
   141 		// otherwise it might be that a complete frame was not available yet
       
   142 		// and we come here to ask again        
       
   143 	{
       
   144 		if ( aType == EFrameTypeNone ) 
       
   145 		{
       
   146 			MPASSERT(iStreamSource == ESourceUser);
       
   147 			
       
   148 			// get next frame type
       
   149 			error = MP4ParseNextFrameType(iMP4Handle, &type);
       
   150 
       
   151 			if ( error == MP4_NOT_AVAILABLE )
       
   152 				return KErrNone;                
       
   153 			else if ( error == MP4_NO_FRAME )                
       
   154 				return EParserEndOfStream; // no video or audio frames left, stream ended
       
   155 			else if ( error == MP4_INVALID_INPUT_STREAM )
       
   156 				return KErrCorrupt;
       
   157 			else if ( error != MP4_OK )
       
   158 				return KErrorCode;
       
   159             else
       
   160             {
       
   161                 MPASSERT(error == MP4_OK);
       
   162             }
       
   163 			
       
   164 			switch ( type ) 
       
   165 			{
       
   166 			case MP4_TYPE_H263_PROFILE_0:
       
   167 		    case MP4_TYPE_MPEG4_VIDEO:
       
   168 		    case MP4_TYPE_AVC_PROFILE_BASELINE:
       
   169 		    // @@ YHK HARI IMP Do we need to support other AVC profiles ??
       
   170           
       
   171 				MPASSERT( type == iVideoType );
       
   172 				iNextFrameType = EFrameTypeVideo;         
       
   173 				break;
       
   174 
       
   175 			default:
       
   176 				return KErrNotSupported;
       
   177 			}
       
   178 		}
       
   179 		else 
       
   180 		{
       
   181 			// library reads the file            
       
   182 			//MPASSERT(iStreamSource == ESourceFile);
       
   183 			type = iVideoType;
       
   184 			iNextFrameType = aType;
       
   185 		}
       
   186 		
       
   187 		// get length for the frame
       
   188 		mp4_u32 length = 0, mp4Specific = 0;
       
   189 		MPASSERT( type != MP4_TYPE_NONE );
       
   190 		if ( (iFirstFrameInfo) &&
       
   191 		     ((iVideoType == MP4_TYPE_MPEG4_VIDEO) || (iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE)) ) 		   
       
   192 		{
       
   193 			error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 0, 0, &mp4Specific );
       
   194 			iFirstFrameInfo = EFalse;
       
   195 		}
       
   196 		error = MP4ParseNextFrameSize(iMP4Handle, type, &length);
       
   197 		MPASSERT( error != MP4_NOT_AVAILABLE );
       
   198 		
       
   199 		if ( length == 0 || error == MP4_NO_REQUESTED_FRAME )
       
   200 		{            
       
   201 			// file-reading case: all frames of this type have been read
       
   202 			//   and the caller should try with the other type
       
   203 			MPASSERT( length == 0 );
       
   204 			iNextFrameType = EFrameTypeNone;
       
   205 			aLength = 0;            
       
   206 			return KErrNone;            
       
   207 		}
       
   208 		else if ( error == MP4_INVALID_INPUT_STREAM )
       
   209 			return KErrCorrupt;
       
   210 		else if ( error != MP4_OK )
       
   211 			return KErrorCode;
       
   212        else if ( length > iMaxVideoFrameLength )
       
   213             {
       
   214             PRINT((_L("CMP4Parser::GetNextFrameInformation() too large video frame size %d, return KErrCorrupt"),length));
       
   215 			return KErrCorrupt;
       
   216             }
       
   217         else
       
   218             iNextFrameLength = TUint(length + mp4Specific);
       
   219 
       
   220 	}
       
   221 	MPASSERT(iNextFrameType != EFrameTypeNone);
       
   222 	MPASSERT(iNextFrameLength != 0);
       
   223 	
       
   224 	// check if frame is available
       
   225 	if ( iStreamSource == ESourceUser )
       
   226 	{
       
   227 		error = MP4ParseIsFrameAvailable(iMP4Handle, type);
       
   228 		if ( error != MP4_OK && error != MP4_NOT_AVAILABLE )
       
   229 			return KErrorCode;
       
   230 		aIsAvailable = ( error == MP4_NOT_AVAILABLE ) ? EFalse : ETrue;
       
   231 	}
       
   232 	else 
       
   233 		aIsAvailable = ETrue;
       
   234 	
       
   235 	aType = iNextFrameType;
       
   236 	aLength = iNextFrameLength;	
       
   237 	
       
   238 	return KErrNone;
       
   239 }   
       
   240 
       
   241 // ---------------------------------------------------------
       
   242 // CMP4Parser::ReadFrames
       
   243 // Read the next frame(s) from file / stream
       
   244 // (other items were commented in a header).
       
   245 // ---------------------------------------------------------
       
   246 //
       
   247 
       
   248 TInt CMP4Parser::ReadFrames(TDes8& aDstBuffer, TFrameType aType, TUint32& aNumRead, 
       
   249 														TUint32& aTimeStamp)
       
   250 {
       
   251 
       
   252 // @@ YHK if the frame typ ei s audio do we need to skip 
       
   253 // it or can we hard code it to video type the 3GP lib 
       
   254 // will return the appropriate type of the frame information.
       
   255 
       
   256 
       
   257 	MP4Err error;
       
   258 	mp4_u32 returnedSize = 0;    
       
   259 	mp4_bool keyFrame = 0;
       
   260 		
       
   261 	MPASSERT( iNextFrameType != EFrameTypeNone && aType == iNextFrameType ); 
       
   262 	MPASSERT( iNextFrameLength != 0 );
       
   263 
       
   264 #ifdef _DEBUG
       
   265 	mp4_u32 type = MP4_TYPE_NONE; // buffer support
       
   266 	type = iVideoType; // buffer support
       
   267 	if (iStreamSource == ESourceUser)
       
   268 		MPASSERT( MP4ParseIsFrameAvailable(iMP4Handle, type) == MP4_OK );
       
   269 #endif
       
   270 
       
   271 	
       
   272 	if (aType == EFrameTypeVideo) 
       
   273 	{	
       
   274 		TUint32 iTimeStampInTicks=0;
       
   275 		mp4_u32 mp4Specific = 0;
       
   276 
       
   277 		if ( (iFirstRead) &&
       
   278 		     ((iVideoType == MP4_TYPE_MPEG4_VIDEO) || (iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE)) ) 		   
       
   279 		{
       
   280 			error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, (mp4_u8*)(aDstBuffer.Ptr() + aDstBuffer.Length()), 
       
   281 				mp4_u32( aDstBuffer.MaxLength() ), &mp4Specific );
       
   282 			iFirstRead = EFalse;
       
   283 		}
       
   284 		
       
   285 		error = MP4ParseReadVideoFrame(iMP4Handle, (mp4_u8*)(aDstBuffer.Ptr() + aDstBuffer.Length()+ mp4Specific), 
       
   286 			mp4_u32( aDstBuffer.MaxLength() ), &returnedSize, (mp4_u32*)&aTimeStamp,
       
   287 			&keyFrame, &iTimeStampInTicks);	
       
   288 
       
   289 		returnedSize += mp4Specific;
       
   290 		iFrameNumber++;
       
   291 		aNumRead = 1;
       
   292 	}
       
   293 	else 
       
   294 	{       
       
   295 		error = MP4ParseReadAudioFrames(iMP4Handle, (mp4_u8*)(aDstBuffer.Ptr()), 
       
   296 			mp4_u32(aDstBuffer.MaxLength()), &returnedSize, (mp4_u32*)&aTimeStamp, 
       
   297 			(mp4_u32*)&aNumRead, NULL);               
       
   298 	
       
   299 			
       
   300 		//PRINT((_L("audio TS:%d, "), aTimeStamp));
       
   301 	}
       
   302 	
       
   303 	MPASSERT(error != MP4_BUFFER_TOO_SMALL);    
       
   304 	aDstBuffer.SetLength(aDstBuffer.Length() + TInt(returnedSize));
       
   305 	iBytesRead += returnedSize;
       
   306 	iNextFrameType = EFrameTypeNone;
       
   307 	iNextFrameLength = 0;
       
   308 		
       
   309 	//PRINT((_L("error=%d, numReturned=%d, returnedSize=%d, bufferSize=%d\n"), 
       
   310 	//	error, aNumRead, returnedSize, aDstBuffer.MaxLength()));
       
   311 		
       
   312 	if (error == MP4_NOT_AVAILABLE)
       
   313 		return EParserNotEnoughData;    
       
   314 	else if ( error == MP4_INVALID_INPUT_STREAM )
       
   315 		return KErrCorrupt;
       
   316 	else if ( error != MP4_OK )
       
   317 		return KErrorCode;
       
   318     else
       
   319         return KErrNone;
       
   320 }
       
   321 
       
   322 
       
   323 // ---------------------------------------------------------
       
   324 // CMP4Parser::Reset
       
   325 // Resets the parser to its initial state
       
   326 // (other items were commented in a header).
       
   327 // ---------------------------------------------------------
       
   328 //
       
   329 
       
   330 TInt CMP4Parser::Reset()
       
   331 {
       
   332 	MP4Err error;
       
   333 	
       
   334 	if ( iStreamSource == ESourceFile )
       
   335 	{
       
   336 		mp4_u32 audioPos, videoPos;
       
   337 		
       
   338 		// seek to very beginning
       
   339 		error = MP4ParseSeek(iMP4Handle, 0, &audioPos, &videoPos, EFalse);
       
   340 		if ( error != MP4_OK )
       
   341 			return KErrorCode;
       
   342 		
       
   343 		MPASSERT( videoPos == 0 && audioPos == 0 );		
       
   344 		
       
   345 	}
       
   346 	else 
       
   347 	{
       
   348 		// close & open library to make sure old data is flushed
       
   349 		error = MP4ParseClose(iMP4Handle);
       
   350 		
       
   351 		if ( error != MP4_OK )
       
   352 			return KErrorCode;
       
   353 		error = MP4ParseOpen(&iMP4Handle, 0);
       
   354 		if ( error != MP4_OK )
       
   355 			return KErrorCode;                    
       
   356 	}
       
   357 	
       
   358 	iBytesRead = 0;
       
   359 	iNextFrameType = EFrameTypeNone;
       
   360 	iNextFrameLength = 0;
       
   361 	
       
   362 	return KErrNone;
       
   363 }
       
   364 
       
   365 
       
   366 // ---------------------------------------------------------
       
   367 // CMP4Parser::ParseHeaderL
       
   368 // Get relevant stream parameters by calling mp4 library functions
       
   369 // (other items were commented in a header).
       
   370 // ---------------------------------------------------------
       
   371 //
       
   372 
       
   373 TInt CMP4Parser::ParseHeaderL(CParser::TStreamParameters& aStreamParameters)
       
   374 {
       
   375 
       
   376     PRINT((_L("CMP4Parser::ParseHeaderL() begin")));
       
   377 
       
   378 	MP4Err error;
       
   379 	mp4_double frameRate = 0;    
       
   380 	TBool hasVideo = ETrue;
       
   381 	
       
   382 	// Reset channel info
       
   383 	aStreamParameters.iHaveVideo = EFalse;
       
   384 	aStreamParameters.iFileFormat = EFileFormatUnrecognized;
       
   385 	aStreamParameters.iVideoFormat = EVideoFormatNone;
       
   386 	aStreamParameters.iVideoLength = 0;
       
   387 	aStreamParameters.iStreamLength = 0;
       
   388 	aStreamParameters.iVideoPicturePeriodNsec = 0;
       
   389 	aStreamParameters.iCanSeek = EFalse;
       
   390 	aStreamParameters.iFrameRate=0;
       
   391 	aStreamParameters.iVideoTimeScale=0; 
       
   392 	iVideoType = 0;
       
   393 	iNumberOfFrames=0;
       
   394 	
       
   395 	// get video description
       
   396 	error = MP4ParseRequestVideoDescription(iMP4Handle, (mp4_u32 *)&aStreamParameters.iVideoLength,
       
   397 		&frameRate, &iVideoType, (mp4_u32 *)&aStreamParameters.iVideoWidth, 
       
   398 		(mp4_u32 *)&aStreamParameters.iVideoHeight, (mp4_u32 *)&aStreamParameters.iVideoTimeScale);
       
   399 
       
   400 	if ( error == MP4_NOT_AVAILABLE )
       
   401 		User::Leave(KErrorCode);
       
   402 	else if ( error == MP4_INVALID_INPUT_STREAM )
       
   403 		User::Leave(KErrCorrupt);
       
   404 	else if ( error == MP4_NO_VIDEO )  
       
   405 	{
       
   406 		hasVideo = EFalse;
       
   407 		aStreamParameters.iVideoWidth = aStreamParameters.iVideoHeight = 0;
       
   408 	}
       
   409 	else if ( error != MP4_OK )
       
   410 		User::Leave(KErrorCode);
       
   411     else
       
   412     {
       
   413         MPASSERT(error == MP4_OK);
       
   414     }
       
   415 
       
   416 
       
   417 	if (aStreamParameters.iVideoLength > 0)
       
   418 		aStreamParameters.iStreamLength = aStreamParameters.iVideoLength;
       
   419 	
       
   420 	aStreamParameters.iFrameRate = frameRate;
       
   421 
       
   422 	if(hasVideo)
       
   423 	{
       
   424 		iNumberOfFrames = GetNumberOfVideoFrames();
       
   425 		MPASSERT(iNumberOfFrames);
       
   426     		
       
   427 		MPASSERT(frameRate > 0);
       
   428 		if (frameRate > 0)
       
   429 			aStreamParameters.iVideoPicturePeriodNsec = TInt64( TReal(1000000000) / TReal(frameRate) );
       
   430 		else
       
   431 			aStreamParameters.iVideoPicturePeriodNsec = TInt64(33366667);
       
   432 		
       
   433 		if ( iVideoType == MP4_TYPE_H263_PROFILE_0 || iVideoType == MP4_TYPE_H263_PROFILE_3 )
       
   434 		{
       
   435 			TVideoClipProperties prop;
       
   436 			prop.iH263Level = 0;
       
   437 			MP4ParseGetVideoClipProperties(iMP4Handle, prop);
       
   438 
       
   439             iMaxVideoFrameLength = KMaxCodedPictureSizeQCIF;
       
   440 			if (prop.iH263Level == 45)
       
   441                 {
       
   442 				aStreamParameters.iVideoFormat = EVideoFormatH263Profile0Level45;
       
   443                 }
       
   444 			else 
       
   445                 {
       
   446 				aStreamParameters.iVideoFormat = EVideoFormatH263Profile0Level10;
       
   447                 }
       
   448 		}
       
   449 		else if ( iVideoType == MP4_TYPE_MPEG4_VIDEO )
       
   450             {
       
   451 			aStreamParameters.iVideoFormat = EVideoFormatMPEG4;		
       
   452             if ( aStreamParameters.iVideoWidth <= KTNEResolutionQCIF.iWidth )
       
   453                 {
       
   454                 iMaxVideoFrameLength = KMaxCodedPictureSizeMPEG4L0BQCIF;//distinction between L0 and L0B not possible here
       
   455                 }
       
   456             else if (aStreamParameters.iVideoWidth <= KTNEResolutionCIF.iWidth )
       
   457                 {
       
   458                 iMaxVideoFrameLength = KMaxCodedPictureSizeMPEG4CIF;
       
   459                 }
       
   460             else
       
   461                 {
       
   462                 // VGA
       
   463                 iMaxVideoFrameLength = KMaxCodedPictureSizeVGA;
       
   464                 }
       
   465             }
       
   466         else if ( iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE ||
       
   467         		  iVideoType == MP4_TYPE_AVC_PROFILE_MAIN ||
       
   468         		  iVideoType == MP4_TYPE_AVC_PROFILE_EXTENDED    )
       
   469             {
       
   470 			if (iVideoType == MP4_TYPE_AVC_PROFILE_BASELINE)
       
   471 				aStreamParameters.iVideoFormat = EVideoFormatAVCProfileBaseline;
       
   472 			else if (iVideoType == MP4_TYPE_AVC_PROFILE_MAIN)
       
   473 				aStreamParameters.iVideoFormat = EVideoFormatAVCProfileMain;
       
   474 			else if (iVideoType == MP4_TYPE_AVC_PROFILE_EXTENDED)
       
   475 				aStreamParameters.iVideoFormat = EVideoFormatAVCProfileExtended;
       
   476 			
       
   477             if ( aStreamParameters.iVideoWidth <= KTNEResolutionQCIF.iWidth )
       
   478                 {
       
   479                 iMaxVideoFrameLength = KMaxCodedPictureSizeMPEG4L0BQCIF;//distinction between L0 and L0B not possible here
       
   480                 }
       
   481             else if (aStreamParameters.iVideoWidth <= KTNEResolutionCIF.iWidth )
       
   482                 {
       
   483                 iMaxVideoFrameLength = KMaxCodedPictureSizeMPEG4CIF;
       
   484                 }
       
   485             else
       
   486                 {
       
   487                 // VGA
       
   488                 iMaxVideoFrameLength = KMaxCodedPictureSizeVGA;
       
   489                 }
       
   490             }
       
   491 	}	
       
   492 
       
   493 
       
   494 	if ( iVideoType == MP4_TYPE_MPEG4_VIDEO ||
       
   495 		 iVideoType == MP4_TYPE_MPEG4_VIDEO ||
       
   496 		 iVideoType == MP4_TYPE_NONE )
       
   497 		aStreamParameters.iFileFormat = EFileFormatMP4;
       
   498 
       
   499 	else if (iVideoType != MP4_TYPE_NONE)
       
   500 		aStreamParameters.iFileFormat = EFileFormat3GP;
       
   501 
       
   502 	if ( aStreamParameters.iStreamLength == 0 )
       
   503 		aStreamParameters.iFileFormat = EFileFormatUnrecognized;
       
   504 	
       
   505 	if ( aStreamParameters.iVideoFormat != EVideoFormatNone ) 
       
   506 	{
       
   507 		aStreamParameters.iHaveVideo = ETrue;
       
   508 	}
       
   509 		
       
   510 	aStreamParameters.iMaxPacketSize = 0;  // N/A
       
   511 	aStreamParameters.iLogicalChannelNumberVideo = 0;  // N/A
       
   512 	
       
   513 	// get stream description
       
   514 	error = MP4ParseRequestStreamDescription(iMP4Handle, (mp4_u32 *)&aStreamParameters.iStreamSize, 
       
   515 		(mp4_u32 *)&aStreamParameters.iStreamBitrate);    
       
   516 	if ( error != MP4_OK )     
       
   517 		User::Leave(KErrorCode);
       
   518 	
       
   519 	aStreamParameters.iReferencePicturesNeeded = 0;     
       
   520 	aStreamParameters.iNumScalabilityLayers = 0;
       
   521 	
       
   522 	// determine if the stream contains INTRA frames so seeking is possible
       
   523 	// If the stream contains more than one INTRA frame, seeking is 
       
   524 	// allowed. 
       
   525 	
       
   526 	if (hasVideo)
       
   527 	{
       
   528 		mp4_u32 position = aStreamParameters.iStreamLength + 1000;
       
   529 		mp4_u32 audioTime, videoTime;
       
   530 		
       
   531 		// Seek past stream duration to find out the position of last INTRA frame
       
   532 		error = MP4ParseSeek(iMP4Handle, position, &audioTime, &videoTime, ETrue);
       
   533 		if ( error != MP4_OK )     
       
   534 			User::Leave(KErrorCode);
       
   535 		
       
   536 		if (videoTime != 0) 
       
   537 		{
       
   538 			// at least two INTRAs
       
   539 			aStreamParameters.iCanSeek = ETrue;
       
   540 		}
       
   541 		
       
   542 		// rewind file back to beginning
       
   543 		error = MP4ParseSeek(iMP4Handle, 0, &audioTime, &videoTime, EFalse);
       
   544 		if ( error != MP4_OK )     
       
   545 			User::Leave(KErrorCode);
       
   546 	}
       
   547 
       
   548     PRINT((_L("CMP4Parser::ParseHeaderL() end")));
       
   549 
       
   550 	return KErrNone; 
       
   551 }
       
   552 
       
   553 // ---------------------------------------------------------
       
   554 // CMP4Parser::SeekOptimalIntraFrame
       
   555 // Seeks to INTRA frame position before given time
       
   556 // (other items were commented in a header).
       
   557 // ---------------------------------------------------------
       
   558 //
       
   559 TInt CMP4Parser::SeekOptimalIntraFrame(TTimeIntervalMicroSeconds aStartTime, TInt aIndex)
       
   560 {
       
   561 	MP4Err error = KErrNone; 
       
   562 	TInt revisedNumberOfFrames = 0;
       
   563 	mp4_u32 audioTime=0; 
       
   564 	mp4_u32 videoTime=0; 
       
   565 	mp4_u32 timeScale=0; 
       
   566 
       
   567 	// calculate the start time of the cut operation
       
   568 	TInt64 startTime = aStartTime.Int64() / TInt64(1000);    
       
   569 	mp4_u32 startPosition = (mp4_u32)( I64INT(startTime) ); 
       
   570 
       
   571 	// seek to the I-frame preceding the start time 
       
   572 	error = MP4ParseSeek(iMP4Handle, startPosition, &audioTime, &videoTime, ETrue);
       
   573 	if (error != MP4_OK)
       
   574 	{		
       
   575 		return KErrorCode; 
       
   576 	}
       
   577 	if (videoTime != 0) 
       
   578 	{
       
   579         // at least one INTRA frame upto its last P frame will be ignored 
       
   580 		// re-calculate the number of frames accordingly         
       
   581 
       
   582     	MPASSERT(aIndex > 0);            
       
   583             
       
   584 		// search backwards from cut point to intra to find the index of the intra frame            
       
   585 		TUint timeInMs;
       
   586 		TInt timeInTicks;
       
   587 		for (TInt i = aIndex; i >= 0; i--)
       
   588 		{
       
   589 			timeInMs = GetVideoFrameStartTime(i, &timeInTicks);
       
   590  			if ( timeInMs == videoTime )
       
   591 			{
       
   592                     iStartFrameIndex = i;
       
   593                     revisedNumberOfFrames = iNumberOfFrames - iStartFrameIndex;
       
   594                     break;
       
   595 			}
       
   596 		}
       
   597         
       
   598 		// update movie and clip number of frames         
       
   599         iOutputNumberOfFrames -= iStartFrameIndex;
       
   600 		iNumberOfFrames = revisedNumberOfFrames; 
       
   601 
       
   602 		// return to beginning of I-frame
       
   603 		error = MP4ParseSeek(iMP4Handle, startPosition, &audioTime, &videoTime, ETrue);
       
   604         if (error != MP4_OK)
       
   605         {		
       
   606             return KErrorCode; 
       
   607         }
       
   608 		else
       
   609 		{
       
   610 			iFrameNumber = iStartFrameIndex;
       
   611 		}
       
   612 
       
   613 	}
       
   614 	return KErrNone;
       
   615 }
       
   616 
       
   617 // ---------------------------------------------------------
       
   618 // CMP4Parser::GetNumberOfVideoFrames
       
   619 // Gets the number of video frames in clip
       
   620 // (other items were commented in a header).
       
   621 // ---------------------------------------------------------
       
   622 //
       
   623 TInt CMP4Parser::GetNumberOfVideoFrames()
       
   624 {
       
   625     mp4_u32 numberOfFrames = 0;
       
   626     MP4Err error = 0;    
       
   627 
       
   628     error = MP4ParseGetNumberOfVideoFrames(iMP4Handle, &numberOfFrames);
       
   629 
       
   630     if (error != MP4_OK)
       
   631         return 0;
       
   632 
       
   633     return numberOfFrames;
       
   634   
       
   635 }
       
   636 
       
   637 // ---------------------------------------------------------
       
   638 // CMP4Parser::GetVideoFrameSize
       
   639 // Gets the size of video frame at given index
       
   640 // (other items were commented in a header).
       
   641 // ---------------------------------------------------------
       
   642 //
       
   643 TInt CMP4Parser::GetVideoFrameSize(TInt aIndex)
       
   644 {
       
   645     mp4_u32 frameSize = 0;
       
   646 	mp4_u32 mp4Specific = 0;
       
   647     MP4Err error = 0;
       
   648 
       
   649 	if ( aIndex == 0 && iVideoType == MP4_TYPE_MPEG4_VIDEO )
       
   650 	{
       
   651 		error = MP4ParseReadVideoDecoderSpecificInfo( iMP4Handle, 0, 0, &mp4Specific );
       
   652 		
       
   653 		if ( error != MP4_OK && error != MP4_BUFFER_TOO_SMALL )
       
   654 			return KErrorCode;
       
   655 	}
       
   656 
       
   657     error = MP4ParseGetVideoFrameSize(iMP4Handle, aIndex, &frameSize);
       
   658 
       
   659     if (error != MP4_OK)
       
   660         return KErrorCode;
       
   661 
       
   662     return frameSize + mp4Specific;
       
   663 	
       
   664 }
       
   665 
       
   666 
       
   667 // @@ YHK need this for getting the optimal frame
       
   668 // ---------------------------------------------------------
       
   669 // CMP4Parser::GetVideoFrameStartTime
       
   670 // Returns frame start time in millisec - optional iTimestamp for start time in ticks
       
   671 // (other items were commented in a header).
       
   672 // ---------------------------------------------------------
       
   673 //
       
   674 TInt CMP4Parser::GetVideoFrameStartTime(TInt aIndex, TInt* aTimeStampInTicks)
       
   675 {
       
   676 
       
   677     MP4Err error = 0;
       
   678     mp4_u32 timeStampInMs = 0;
       
   679 
       
   680     MPASSERT(aTimeStampInTicks);
       
   681   
       
   682     error = MP4ParseGetVideoFrameStartTime(iMP4Handle, aIndex, (mp4_u32*)aTimeStampInTicks, &timeStampInMs);
       
   683 
       
   684     if (error != MP4_OK)
       
   685         return KErrorCode;
       
   686 
       
   687     return timeStampInMs;
       
   688   
       
   689 }
       
   690 
       
   691 // ---------------------------------------------------------
       
   692 // CMP4Parser::GetVideoFrameType
       
   693 // Gets the type of video frame at given index
       
   694 // (other items were commented in a header).
       
   695 // ---------------------------------------------------------
       
   696 //
       
   697 TInt8 CMP4Parser::GetVideoFrameType(TInt aIndex)
       
   698 {
       
   699 
       
   700     MP4Err error = 0;
       
   701     mp4_bool frameType;
       
   702     
       
   703     error = MP4ParseGetVideoFrameType(iMP4Handle, aIndex, &frameType);
       
   704 
       
   705     if (error != MP4_OK)
       
   706         return KErrGeneral;
       
   707  
       
   708 	return TInt8(frameType);
       
   709 }
       
   710 
       
   711 
       
   712 TInt CMP4Parser::GetVideoFrameRate(TReal& aFrameRate)
       
   713 {
       
   714 
       
   715     mp4_u32 length;
       
   716     mp4_double frameRate; 
       
   717     mp4_u32 videoType;
       
   718     mp4_u32 width;
       
   719     mp4_u32 height;
       
   720     mp4_u32 timeScale;
       
   721 
       
   722     MP4Err error = 0;
       
   723 
       
   724     // get video description
       
   725 	error = MP4ParseRequestVideoDescription(iMP4Handle, &length, &frameRate, 
       
   726         &videoType, &width, &height, &timeScale);		
       
   727 
       
   728     if ( error != 0 )
       
   729         return KErrGeneral;
       
   730     
       
   731     TReal temp = frameRate * 2.0;
       
   732     TInt temp2 = TInt(temp + 0.5);
       
   733 
       
   734     aFrameRate = temp2 / 2.0;
       
   735 
       
   736     return KErrNone;
       
   737 }
       
   738 
       
   739 // End of File