os/mm/mmplugins/lib3gp/impl/src/asyncfileparser.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 FILES
    17 #include <e32base.h>
    18 #include <f32file.h>
    19 #include <f32file64.h>
    20 #include <3gplibrary/mp4lib.h>
    21 #include "mp4atom.h"
    22 #include "mp4memwrap.h"
    23 #include "asyncfileparser.h"
    24 
    25 // MACROS
    26 // Debug print macro
    27 #if defined(_DEBUG) && defined(_ASYNCFILEPARSERLOGGING)
    28 #include <e32svr.h>
    29 #define PRINT(x)
    30 #else
    31 #define PRINT(x)
    32 #endif
    33 
    34 // ============================ MEMBER FUNCTIONS ===============================
    35 
    36 // -----------------------------------------------------------------------------
    37 // CFileAsyncParser::CFileAsyncParser
    38 // C++ default constructor can NOT contain any code, that
    39 // might leave.
    40 // -----------------------------------------------------------------------------
    41 //
    42 CFileAsyncParser::CFileAsyncParser() : CActive( EPriorityHigh ), iDiskBufferPointer(NULL,0)
    43     {
    44     
    45     }
    46 
    47 // -----------------------------------------------------------------------------
    48 // CFileAsyncParser::ConstructL
    49 // Symbian 2nd phase constructor can leave.
    50 // -----------------------------------------------------------------------------
    51 //
    52 void CFileAsyncParser::ConstructL( MP4HandleStruct* aHandle, RFile64& aFile )
    53     {
    54     PRINT(_L("CFileAsyncParser::ConstructL() IN"));
    55     iError = KErrNone;
    56     iInputFile = &aFile;
    57     iHandle = aHandle;    
    58 	iAudioSize = 0;
    59 	iReturnedAudioFrames = 0;
    60 	iAudioTimeStamp = 0; 		
    61 	iAudioTimeStamp2 = 1;   // always fill timestamp2 too (null = dont fill)
    62 	iAllDataInMemory = EFalse; 
    63 	
    64 	if ( iHandle->readBufferSize == 0)
    65 	{
    66 		iReadBufferSize = READBUFSIZE;
    67 	}
    68 	else
    69 	{
    70 		iReadBufferSize = iHandle->readBufferSize;
    71 	}	
    72 	
    73 	iDiskBuffer = HBufC8::NewL(iReadBufferSize);
    74 	iCurrentDiskReadPosition = 0;
    75 	iCurrentBufferReadPosition = 0;
    76     CActiveScheduler::Add(this);
    77     
    78     PRINT(_L("CFileAsyncParser::ConstructL() OUT"));
    79     }
    80 
    81 // -----------------------------------------------------------------------------
    82 // CFileAsyncParser::NewL
    83 // Two-phased constructor.
    84 // -----------------------------------------------------------------------------
    85 //
    86 CFileAsyncParser* CFileAsyncParser::NewL( MP4HandleStruct* aHandle, RFile64& aFile )
    87     {
    88     CFileAsyncParser* self = new(ELeave) CFileAsyncParser;
    89     CleanupStack::PushL(self);
    90     self->ConstructL( aHandle, aFile );
    91     CleanupStack::Pop(self);
    92     return self;
    93     }
    94 
    95 // -----------------------------------------------------------------------------
    96 // Destructor
    97 // -----------------------------------------------------------------------------
    98 //
    99 CFileAsyncParser::~CFileAsyncParser()
   100     {
   101     PRINT(_L("CFileAsyncParser::~CFileAsyncParser() in"));
   102 
   103     if ( IsActive() )
   104         {
   105         if ( iAsyncReadOngoing )
   106             {
   107             Cancel();
   108             }
   109         }
   110 
   111     delete iDiskBuffer;
   112     PRINT(_L("CFileAsyncParser::~CFileAsyncParser() out"));
   113     }
   114 
   115 // -----------------------------------------------------------------------------
   116 // CFileAsyncParser::ReadAudioFrames(  );
   117 // Writes incoming buffer data to internal buffers for writing to disk.
   118 // (other items were commented in a header).
   119 // -----------------------------------------------------------------------------
   120 //
   121 TInt CFileAsyncParser::ReadAudioFrames( mp4_u8 *buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
   122 	{
   123 	PRINT(_L("CFileAsyncParser::ReadAudioFrames()"));
   124 	iProcessingAudio = ETrue;
   125 	return ReadDataAsync( buffer, aPosition, aBytesToRead );
   126 	}
   127 
   128 // -----------------------------------------------------------------------------
   129 // CFileAsyncParser::ReadVideoFrame( );
   130 // Writes incoming buffer data to internal buffers for writing to disk.
   131 // (other items were commented in a header).
   132 // -----------------------------------------------------------------------------
   133 //
   134 TInt CFileAsyncParser::ReadVideoFrame( mp4_u8* buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
   135 	{
   136 	PRINT(_L("CFileAsyncParser::ReadVideoFrame()"));
   137 	iProcessingAudio = EFalse;
   138 	return ReadDataAsync( buffer, aPosition, aBytesToRead );
   139 	}
   140 
   141 
   142 // -----------------------------------------------------------------------------
   143 // CFileAsyncParser::ReadDataAsync(  );
   144 // Reads data from file asynchronously.
   145 // (other items were commented in a header).
   146 // -----------------------------------------------------------------------------
   147 //
   148 TInt CFileAsyncParser::ReadDataAsync( mp4_u8 *buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
   149 	{
   150 	PRINT(_L("CFileAsyncParser::ReadDataAsync() in"));
   151 	iBuffer = buffer;
   152 	if ( iAsyncReadOngoing )
   153 		{
   154 		return -1; // only one async read can be ongoing at one time;	
   155 		}
   156 	if (!iDiskBuffer)
   157 		{
   158 		return -1;
   159 		}
   160 		
   161   	// Is the new seek point inside the current disk buffer?
   162   	if ( (iCurrentDiskReadPosition > aPosition) &&  
   163   		 (( iCurrentDiskReadPosition - iDiskBuffer->Length() ) <= aPosition  ))
   164   		{
   165     	// Yes
   166 	    iCurrentBufferReadPosition = iDiskBuffer->Length() - (iCurrentDiskReadPosition - aPosition);
   167   		}
   168   	else
   169   		{
   170     	// No, set current position and zero diskbuffer
   171 		iCurrentBufferReadPosition = 0;
   172 		iCurrentDiskReadPosition = (mp4_i64)aPosition;
   173 		iDiskBuffer->Des().SetLength(0);
   174 		}
   175 		
   176 	iBytesToRead = aBytesToRead;
   177 	iBytesRead = 0;
   178 	TInt available = 0;
   179 	
   180 	// How much data is available in diskbuffer.
   181 	available =  iDiskBuffer->Length() - iCurrentBufferReadPosition;
   182 	if (available > iBytesToRead)
   183 	{
   184 	  available = iBytesToRead;
   185 	}
   186 
   187 	// If any available copy it first to output buffer
   188 	if (available ) 
   189 	{
   190 	  memcpy(iBuffer, iDiskBuffer->Ptr() + iCurrentBufferReadPosition, available);
   191 	  iCurrentBufferReadPosition += available;
   192 	  iBytesRead += available;
   193 	}
   194 
   195 	// If we got everything from diskbuffer process it right away
   196 	if (iBytesRead == iBytesToRead)
   197 	{
   198 		PRINT(_L("CFileAsyncParser::ReadDataAsync() Data found in memory, no need to read file - return right away"));
   199 		iAllDataInMemory = ETrue;
   200 		SetActive();
   201         TRequestStatus* tmp = &iStatus;
   202         User::RequestComplete(tmp, KErrNone);
   203         PRINT(_L("CFileAsyncParser::ReadDataAsync() out"));
   204 		return MP4_OK;
   205 	}
   206 	else
   207 	{
   208 		// Need to read rest of the requested data from file.
   209 		iAllDataInMemory = EFalse;
   210 	}
   211 
   212 	// Determine used readbuffer size
   213 	if ( iHandle->readBufferSize == 0)
   214 	{
   215 		iReadBufferSize = READBUFSIZE;
   216 	}
   217 	else
   218 	{
   219 		iReadBufferSize = iHandle->readBufferSize;
   220 	}
   221 	
   222 	// Increase disk read buffer size if requested frames are larger than current disk buffer.
   223 	if ( (iBytesToRead > iReadBufferSize ) || (iReadBufferSize != iDiskBuffer->Des().MaxLength()) )
   224 	{
   225         iReadBufferSize = iBytesToRead;
   226         if (iDiskBuffer)
   227         {
   228             delete iDiskBuffer;
   229             iDiskBuffer = NULL;
   230             TRAPD(memerror, iDiskBuffer = HBufC8::NewL(iReadBufferSize));
   231             if (memerror)
   232             {
   233 	            return MP4_OUT_OF_MEMORY;
   234             }
   235             else
   236             {
   237 				iCurrentBufferReadPosition = 0;
   238             }
   239         }
   240 	}
   241 
   242 	iAsyncReadOngoing = ETrue;
   243 	iDiskBufferPointer.Set(iDiskBuffer->Des());
   244 	iCurrentDiskReadPosition = aPosition + iBytesRead;
   245 	switch (iHandle->sourceType)
   246 	  {
   247 	    case MP4_SOURCE_RFILE:
   248 	    {
   249 		  PRINT(_L("CFileAsyncParser::ReadDataAsync() Data not in memory, reading RFile64"));	    
   250 	      RFile64* rfile = (RFile64*)iHandle->rfile;
   251 	      rfile->Read(iCurrentDiskReadPosition, iDiskBufferPointer, iDiskBufferPointer.MaxLength(), iStatus);
   252 	      break;
   253 	    }
   254 	    case MP4_SOURCE_CAF:
   255 	    {
   256 		  PRINT(_L("CFileAsyncParser::ReadDataAsync() Data not in memory, reading CAF object"));	    	    
   257 	      iHandle->cafError = iHandle->cfile->Read(iCurrentDiskReadPosition, iDiskBufferPointer, iDiskBufferPointer.MaxLength(), iStatus);
   258 	      if ( iHandle->cafError != KErrNone)
   259 	        return -2;
   260 	      break;
   261 	    }
   262 	    default:
   263 	      return -1;
   264 	  }
   265 
   266     if ( !IsActive() )
   267 	    {
   268 	    SetActive();
   269 	    }
   270 	PRINT(_L("CFileAsyncParser::ReadDataAsync() out"));
   271 	return 0;
   272 	}
   273 
   274 
   275 
   276 // -----------------------------------------------------------------------------
   277 // CFileAsyncParser::DoCancel()
   278 // From CActive Cancels async request.
   279 // -----------------------------------------------------------------------------
   280 //
   281 void CFileAsyncParser::DoCancel()
   282     {
   283     PRINT(_L("CFileAsyncParser::DoCancel() in"));
   284     if (iAsyncReadOngoing)
   285     	{
   286     	if (iHandle->sourceType == MP4_SOURCE_RFILE)
   287     	    {
   288     	    // cancel read from file
   289     	    ((RFile64 *)(iHandle->rfile))->ReadCancel();
   290         	}
   291     	else if (iHandle->sourceType == MP4_SOURCE_CAF)
   292         	{
   293         	// cancel read from caf object
   294         	iHandle->cfile->ReadCancel(iStatus);
   295         	}
   296     	iAsyncReadOngoing = EFalse;
   297     	}
   298     
   299     PRINT(_L("CFileAsyncParser::DoCancel() out"));
   300     }
   301 
   302 // -----------------------------------------------------------------------------
   303 // CFileAsyncParser::ReturnAudioFrames()
   304 // Return audio frames to observer.
   305 // -----------------------------------------------------------------------------
   306 //
   307 void CFileAsyncParser::ReturnAudioFrames()
   308 	{
   309 	PRINT(_L("CFileAsyncParser::ReturnAudioFrames() in"));
   310 	TInt error = KErrNone;
   311 	
   312 	// Update last accessed position in file pointer
   313     if (iHandle->audioSampleOffset + iHandle->audioSampleSize - 1 > iHandle->lastAccessedPosInFile)
   314 	    {
   315 	    iHandle->lastAccessedPosInFile = iHandle->audioSampleOffset + iHandle->audioSampleSize - 1;
   316 	    }
   317 	
   318 	// Fill audio frame size
   319 	iAudioSize = iHandle->audioSampleSize;
   320 	
   321 	// Fill audio timestamp information
   322 	iAudioTimeStamp = 0;
   323 	iAudioTimeStamp2 = 1; // fill also timestamp2 (wont be filled if 0)
   324 	error = convertAudioSampleToTime(iHandle, iHandle->moov->trakAudio->mdia, &iAudioTimeStamp, &iAudioTimeStamp2);	
   325 	if (error == MP4_OK)
   326 		{
   327 		// Fill iReturnedAudioFrames
   328 		iReturnedAudioFrames = 0;
   329 		error = CalculateAudioFrameCount();
   330 		}
   331 	
   332 	// Move forward in audio samples
   333 	if (error == MP4_OK)
   334 		{
   335 		error = advanceAudioSample(iHandle, iHandle->moov->trakAudio);
   336 		if ( error == -1)
   337 			{
   338 			error = MP4_ERROR;
   339 			}
   340 		else if ( error == -2 )
   341 			{
   342 			error = MP4_OK;
   343 			iHandle->audioLast = MP4TRUE;
   344 			}
   345 		}
   346 
   347 	iAsyncReadOngoing = EFalse;
   348 	iHandle->asyncObserver->M3GPMP4LibAudioFramesAvailable(error, 
   349     													  iAudioSize,
   350     													  iAudioTimeStamp,
   351     													  iReturnedAudioFrames,
   352     										  			  iAudioTimeStamp2);
   353 	PRINT(_L("CFileAsyncParser::ReturnAudioFrames() out"));		
   354 	}
   355 
   356 // -----------------------------------------------------------------------------
   357 // CFileAsyncParser::ReturnVideoFrame()
   358 // Return video frame to observer.
   359 // -----------------------------------------------------------------------------
   360 //
   361 void CFileAsyncParser::ReturnVideoFrame()
   362 	{
   363 	PRINT(_L("CFileAsyncParser::ReturnVideoFrame() in"));
   364 	TInt error = KErrNone;
   365 	
   366 	// Update last accessed position in file pointer
   367     if (iHandle->videoFrameOffset + iHandle->videoFrameSize - 1 > iHandle->lastAccessedPosInFile)
   368 	    {
   369 	    iHandle->lastAccessedPosInFile = iHandle->videoFrameOffset + iHandle->videoFrameSize - 1;
   370 	    }
   371 	
   372 	// Fill video frame size
   373 	iVideoSize = iHandle->videoFrameSize;
   374 	
   375 	// Fill video timestamp information
   376 	iVideoTimeStamp = 0;
   377 	iVideoTimeStamp2 = 1; // fill also timestamp2 (wont be filled if 0)
   378 	error = convertVideoSampleToTime(iHandle, iHandle->moov->trakVideo->mdia, &iVideoTimeStamp, &iVideoTimeStamp2);	
   379 	if (error == MP4_OK)
   380 		{
   381 		// Fill iKeyFrame
   382 		iVideoKeyFrame = 0;
   383 		error = isVideoFrameKeyFrame(iHandle, iHandle->moov->trakVideo, &iVideoKeyFrame);
   384 		}
   385 	
   386 	// Move forward in video frames
   387 	if (error == MP4_OK)
   388 		{
   389 		error = advanceVideoFrame(iHandle, iHandle->moov->trakVideo);
   390 		if ( error == -1)
   391 			{
   392 			error = MP4_ERROR;
   393 			}
   394 		else if ( error == -2 )
   395 			{
   396 			error = MP4_OK;
   397 			iHandle->videoLast = MP4TRUE;
   398 			}
   399 		}
   400 
   401 	iAsyncReadOngoing = EFalse;
   402 	iHandle->asyncObserver->M3GPMP4LibVideoFrameAvailable(error,
   403         										   		  iVideoSize, 
   404         										  		  iVideoTimeStamp, 
   405         										   		  iVideoKeyFrame, 
   406         										   		  iVideoTimeStamp2);
   407 	PRINT(_L("CFileAsyncParser::ReturnVideoFrame() out"));		
   408 	}
   409 
   410 // -----------------------------------------------------------------------------
   411 // CFileAsyncParser::CalculateAudioFrameCount()
   412 // Return video frame to observer.
   413 // -----------------------------------------------------------------------------
   414 //
   415 TInt CFileAsyncParser::CalculateAudioFrameCount()
   416 	{
   417   	mp4_i32 frameLength = 0;
   418   	mp4_u32 numOfFrames = 0;
   419   	mp4_u8 *framepointer = 0;
   420   	mp4_u32 rawAmrFrameLength[16] = {13,14,16,18,20,21,27,32,6,0,0,0,0,0,0,1};	
   421 	trackAtom *trak = iHandle->moov->trakAudio;
   422 	
   423 	if (!trak)
   424 		{
   425 		return -1;
   426 		}
   427 
   428 	/* AMR */
   429 	if (trak->mdia->minf)
   430 	if (trak->mdia->minf->stbl)
   431 	  if (trak->mdia->minf->stbl->stsd)
   432 	    if (iHandle->type & MP4_TYPE_AMR_NB)
   433 	    {
   434 	        framepointer = iBuffer;
   435 	        numOfFrames = 0;
   436 	        while ( iBytesRead > 0 )
   437 	        {
   438 	            frameLength = rawAmrFrameLength[(TInt)(((*framepointer) & 0x78) >> 3)];
   439 	            if ( frameLength == 0)
   440 	            {
   441 	                return -4;
   442 	            }
   443 	            iBytesRead -= frameLength;
   444 	            framepointer += frameLength;
   445 	            numOfFrames++;
   446 	        }
   447 	        iReturnedAudioFrames = numOfFrames;
   448 	    }
   449 	    else if (iHandle->type & MP4_TYPE_AMR_WB)
   450 	    {
   451 		  /* Return the number of sample entries listed for this particular sample entry index */
   452 	      if (trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1])
   453 	        if (trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]->damr)
   454 	          iReturnedAudioFrames = trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]->damr->framesPerSample;
   455 	    }
   456 	    else
   457 	    {
   458 	    }
   459 
   460 	/* MPEG-4 audio */
   461 	if (trak->mdia->minf)
   462 	if (trak->mdia->minf->stbl)
   463 	  if (trak->mdia->minf->stbl->stsd)
   464 	    if (trak->mdia->minf->stbl->stsd->mp4a[iHandle->audioSampleEntryIndex - 1])
   465 	      iReturnedAudioFrames = 1;
   466 
   467 	/* QCELP 13K as QCELPSampleEntry*/
   468 	if (trak->mdia->minf)
   469 	if (trak->mdia->minf->stbl)
   470 	  if (trak->mdia->minf->stbl->stsd)
   471 	    if ((iHandle->type & MP4_TYPE_QCELP_13K) && (!iHandle->qcelpStoredAsMPEGAudio))
   472 	    {
   473 		  /* Return the number of sample entries listed for this particular sample entry index */
   474 	      if (trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1])
   475 	        if (trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]->dqcp)
   476 	          iReturnedAudioFrames = trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]->dqcp->framesPerSample;
   477 	    }
   478 
   479 	/* QCELP 13K as MPEG-4 audio */
   480 	if (trak->mdia->minf)
   481 	if (trak->mdia->minf->stbl)
   482 	  if (trak->mdia->minf->stbl->stsd)
   483 	    if (trak->mdia->minf->stbl->stsd->mp4a[iHandle->audioSampleEntryIndex - 1])
   484 	      iReturnedAudioFrames = 1;
   485 
   486 	return MP4_OK;	
   487 	}
   488 
   489 // -----------------------------------------------------------------------------
   490 // CFileAsyncParser::RunL()
   491 // From CActive Called when async request completes.
   492 // -----------------------------------------------------------------------------
   493 //
   494 void CFileAsyncParser::RunL()
   495     {
   496     PRINT(_L("CFileAsyncParser::RunL() in"));
   497     if ( iStatus != KErrNone )
   498         {
   499         PRINT((_L("CFileAsyncParser::RunL() error in previous async: %d "), iStatus.Int() ));
   500         iError = iStatus.Int();
   501 		iHandle->asyncObserver->M3GPMP4LibAudioFramesAvailable(MP4_FILE_ERROR,0,0,0,0);
   502         return;
   503         }
   504 
   505     if (!iAllDataInMemory)
   506 	    {
   507 		if ((mp4_u32)iDiskBuffer->Length() == 0) // EOF or error
   508 		{
   509 			iError = MP4_FILE_ERROR; // metadata info doesn't match file -> corrupted clip.
   510 		}
   511 		
   512 		memcpy(iBuffer+iBytesRead, iDiskBuffer->Ptr(), iBytesToRead-iBytesRead);
   513 	  	iCurrentBufferReadPosition += iBytesToRead-iBytesRead;
   514 	  	iCurrentDiskReadPosition += iDiskBuffer->Length();
   515 		iBytesRead = iBytesToRead;
   516 	  	
   517 	  	// set handle disk buffer sizes to zero just in case.
   518 	  	iHandle->diskReadBufPos = 0;
   519 		iHandle->diskReadSize = 0;
   520 		iHandle->diskReadBufStart = 0;
   521 		iHandle->diskReadPos = iCurrentDiskReadPosition;
   522     	}
   523 
   524 	if ( iProcessingAudio )
   525 		{
   526 		ReturnAudioFrames();
   527 		}
   528 	else
   529 		{
   530 		ReturnVideoFrame();	
   531 		}
   532     
   533     PRINT(_L("CFileAsyncParser::RunL() out"));
   534     }
   535 
   536 //  End of File