1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/mmplugins/lib3gp/impl/src/asyncfileparser.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,536 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +// INCLUDE FILES
1.20 +#include <e32base.h>
1.21 +#include <f32file.h>
1.22 +#include <f32file64.h>
1.23 +#include <3gplibrary/mp4lib.h>
1.24 +#include "mp4atom.h"
1.25 +#include "mp4memwrap.h"
1.26 +#include "asyncfileparser.h"
1.27 +
1.28 +// MACROS
1.29 +// Debug print macro
1.30 +#if defined(_DEBUG) && defined(_ASYNCFILEPARSERLOGGING)
1.31 +#include <e32svr.h>
1.32 +#define PRINT(x)
1.33 +#else
1.34 +#define PRINT(x)
1.35 +#endif
1.36 +
1.37 +// ============================ MEMBER FUNCTIONS ===============================
1.38 +
1.39 +// -----------------------------------------------------------------------------
1.40 +// CFileAsyncParser::CFileAsyncParser
1.41 +// C++ default constructor can NOT contain any code, that
1.42 +// might leave.
1.43 +// -----------------------------------------------------------------------------
1.44 +//
1.45 +CFileAsyncParser::CFileAsyncParser() : CActive( EPriorityHigh ), iDiskBufferPointer(NULL,0)
1.46 + {
1.47 +
1.48 + }
1.49 +
1.50 +// -----------------------------------------------------------------------------
1.51 +// CFileAsyncParser::ConstructL
1.52 +// Symbian 2nd phase constructor can leave.
1.53 +// -----------------------------------------------------------------------------
1.54 +//
1.55 +void CFileAsyncParser::ConstructL( MP4HandleStruct* aHandle, RFile64& aFile )
1.56 + {
1.57 + PRINT(_L("CFileAsyncParser::ConstructL() IN"));
1.58 + iError = KErrNone;
1.59 + iInputFile = &aFile;
1.60 + iHandle = aHandle;
1.61 + iAudioSize = 0;
1.62 + iReturnedAudioFrames = 0;
1.63 + iAudioTimeStamp = 0;
1.64 + iAudioTimeStamp2 = 1; // always fill timestamp2 too (null = dont fill)
1.65 + iAllDataInMemory = EFalse;
1.66 +
1.67 + if ( iHandle->readBufferSize == 0)
1.68 + {
1.69 + iReadBufferSize = READBUFSIZE;
1.70 + }
1.71 + else
1.72 + {
1.73 + iReadBufferSize = iHandle->readBufferSize;
1.74 + }
1.75 +
1.76 + iDiskBuffer = HBufC8::NewL(iReadBufferSize);
1.77 + iCurrentDiskReadPosition = 0;
1.78 + iCurrentBufferReadPosition = 0;
1.79 + CActiveScheduler::Add(this);
1.80 +
1.81 + PRINT(_L("CFileAsyncParser::ConstructL() OUT"));
1.82 + }
1.83 +
1.84 +// -----------------------------------------------------------------------------
1.85 +// CFileAsyncParser::NewL
1.86 +// Two-phased constructor.
1.87 +// -----------------------------------------------------------------------------
1.88 +//
1.89 +CFileAsyncParser* CFileAsyncParser::NewL( MP4HandleStruct* aHandle, RFile64& aFile )
1.90 + {
1.91 + CFileAsyncParser* self = new(ELeave) CFileAsyncParser;
1.92 + CleanupStack::PushL(self);
1.93 + self->ConstructL( aHandle, aFile );
1.94 + CleanupStack::Pop(self);
1.95 + return self;
1.96 + }
1.97 +
1.98 +// -----------------------------------------------------------------------------
1.99 +// Destructor
1.100 +// -----------------------------------------------------------------------------
1.101 +//
1.102 +CFileAsyncParser::~CFileAsyncParser()
1.103 + {
1.104 + PRINT(_L("CFileAsyncParser::~CFileAsyncParser() in"));
1.105 +
1.106 + if ( IsActive() )
1.107 + {
1.108 + if ( iAsyncReadOngoing )
1.109 + {
1.110 + Cancel();
1.111 + }
1.112 + }
1.113 +
1.114 + delete iDiskBuffer;
1.115 + PRINT(_L("CFileAsyncParser::~CFileAsyncParser() out"));
1.116 + }
1.117 +
1.118 +// -----------------------------------------------------------------------------
1.119 +// CFileAsyncParser::ReadAudioFrames( );
1.120 +// Writes incoming buffer data to internal buffers for writing to disk.
1.121 +// (other items were commented in a header).
1.122 +// -----------------------------------------------------------------------------
1.123 +//
1.124 +TInt CFileAsyncParser::ReadAudioFrames( mp4_u8 *buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
1.125 + {
1.126 + PRINT(_L("CFileAsyncParser::ReadAudioFrames()"));
1.127 + iProcessingAudio = ETrue;
1.128 + return ReadDataAsync( buffer, aPosition, aBytesToRead );
1.129 + }
1.130 +
1.131 +// -----------------------------------------------------------------------------
1.132 +// CFileAsyncParser::ReadVideoFrame( );
1.133 +// Writes incoming buffer data to internal buffers for writing to disk.
1.134 +// (other items were commented in a header).
1.135 +// -----------------------------------------------------------------------------
1.136 +//
1.137 +TInt CFileAsyncParser::ReadVideoFrame( mp4_u8* buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
1.138 + {
1.139 + PRINT(_L("CFileAsyncParser::ReadVideoFrame()"));
1.140 + iProcessingAudio = EFalse;
1.141 + return ReadDataAsync( buffer, aPosition, aBytesToRead );
1.142 + }
1.143 +
1.144 +
1.145 +// -----------------------------------------------------------------------------
1.146 +// CFileAsyncParser::ReadDataAsync( );
1.147 +// Reads data from file asynchronously.
1.148 +// (other items were commented in a header).
1.149 +// -----------------------------------------------------------------------------
1.150 +//
1.151 +TInt CFileAsyncParser::ReadDataAsync( mp4_u8 *buffer, mp4_i64 aPosition, mp4_u32 aBytesToRead )
1.152 + {
1.153 + PRINT(_L("CFileAsyncParser::ReadDataAsync() in"));
1.154 + iBuffer = buffer;
1.155 + if ( iAsyncReadOngoing )
1.156 + {
1.157 + return -1; // only one async read can be ongoing at one time;
1.158 + }
1.159 + if (!iDiskBuffer)
1.160 + {
1.161 + return -1;
1.162 + }
1.163 +
1.164 + // Is the new seek point inside the current disk buffer?
1.165 + if ( (iCurrentDiskReadPosition > aPosition) &&
1.166 + (( iCurrentDiskReadPosition - iDiskBuffer->Length() ) <= aPosition ))
1.167 + {
1.168 + // Yes
1.169 + iCurrentBufferReadPosition = iDiskBuffer->Length() - (iCurrentDiskReadPosition - aPosition);
1.170 + }
1.171 + else
1.172 + {
1.173 + // No, set current position and zero diskbuffer
1.174 + iCurrentBufferReadPosition = 0;
1.175 + iCurrentDiskReadPosition = (mp4_i64)aPosition;
1.176 + iDiskBuffer->Des().SetLength(0);
1.177 + }
1.178 +
1.179 + iBytesToRead = aBytesToRead;
1.180 + iBytesRead = 0;
1.181 + TInt available = 0;
1.182 +
1.183 + // How much data is available in diskbuffer.
1.184 + available = iDiskBuffer->Length() - iCurrentBufferReadPosition;
1.185 + if (available > iBytesToRead)
1.186 + {
1.187 + available = iBytesToRead;
1.188 + }
1.189 +
1.190 + // If any available copy it first to output buffer
1.191 + if (available )
1.192 + {
1.193 + memcpy(iBuffer, iDiskBuffer->Ptr() + iCurrentBufferReadPosition, available);
1.194 + iCurrentBufferReadPosition += available;
1.195 + iBytesRead += available;
1.196 + }
1.197 +
1.198 + // If we got everything from diskbuffer process it right away
1.199 + if (iBytesRead == iBytesToRead)
1.200 + {
1.201 + PRINT(_L("CFileAsyncParser::ReadDataAsync() Data found in memory, no need to read file - return right away"));
1.202 + iAllDataInMemory = ETrue;
1.203 + SetActive();
1.204 + TRequestStatus* tmp = &iStatus;
1.205 + User::RequestComplete(tmp, KErrNone);
1.206 + PRINT(_L("CFileAsyncParser::ReadDataAsync() out"));
1.207 + return MP4_OK;
1.208 + }
1.209 + else
1.210 + {
1.211 + // Need to read rest of the requested data from file.
1.212 + iAllDataInMemory = EFalse;
1.213 + }
1.214 +
1.215 + // Determine used readbuffer size
1.216 + if ( iHandle->readBufferSize == 0)
1.217 + {
1.218 + iReadBufferSize = READBUFSIZE;
1.219 + }
1.220 + else
1.221 + {
1.222 + iReadBufferSize = iHandle->readBufferSize;
1.223 + }
1.224 +
1.225 + // Increase disk read buffer size if requested frames are larger than current disk buffer.
1.226 + if ( (iBytesToRead > iReadBufferSize ) || (iReadBufferSize != iDiskBuffer->Des().MaxLength()) )
1.227 + {
1.228 + iReadBufferSize = iBytesToRead;
1.229 + if (iDiskBuffer)
1.230 + {
1.231 + delete iDiskBuffer;
1.232 + iDiskBuffer = NULL;
1.233 + TRAPD(memerror, iDiskBuffer = HBufC8::NewL(iReadBufferSize));
1.234 + if (memerror)
1.235 + {
1.236 + return MP4_OUT_OF_MEMORY;
1.237 + }
1.238 + else
1.239 + {
1.240 + iCurrentBufferReadPosition = 0;
1.241 + }
1.242 + }
1.243 + }
1.244 +
1.245 + iAsyncReadOngoing = ETrue;
1.246 + iDiskBufferPointer.Set(iDiskBuffer->Des());
1.247 + iCurrentDiskReadPosition = aPosition + iBytesRead;
1.248 + switch (iHandle->sourceType)
1.249 + {
1.250 + case MP4_SOURCE_RFILE:
1.251 + {
1.252 + PRINT(_L("CFileAsyncParser::ReadDataAsync() Data not in memory, reading RFile64"));
1.253 + RFile64* rfile = (RFile64*)iHandle->rfile;
1.254 + rfile->Read(iCurrentDiskReadPosition, iDiskBufferPointer, iDiskBufferPointer.MaxLength(), iStatus);
1.255 + break;
1.256 + }
1.257 + case MP4_SOURCE_CAF:
1.258 + {
1.259 + PRINT(_L("CFileAsyncParser::ReadDataAsync() Data not in memory, reading CAF object"));
1.260 + iHandle->cafError = iHandle->cfile->Read(iCurrentDiskReadPosition, iDiskBufferPointer, iDiskBufferPointer.MaxLength(), iStatus);
1.261 + if ( iHandle->cafError != KErrNone)
1.262 + return -2;
1.263 + break;
1.264 + }
1.265 + default:
1.266 + return -1;
1.267 + }
1.268 +
1.269 + if ( !IsActive() )
1.270 + {
1.271 + SetActive();
1.272 + }
1.273 + PRINT(_L("CFileAsyncParser::ReadDataAsync() out"));
1.274 + return 0;
1.275 + }
1.276 +
1.277 +
1.278 +
1.279 +// -----------------------------------------------------------------------------
1.280 +// CFileAsyncParser::DoCancel()
1.281 +// From CActive Cancels async request.
1.282 +// -----------------------------------------------------------------------------
1.283 +//
1.284 +void CFileAsyncParser::DoCancel()
1.285 + {
1.286 + PRINT(_L("CFileAsyncParser::DoCancel() in"));
1.287 + if (iAsyncReadOngoing)
1.288 + {
1.289 + if (iHandle->sourceType == MP4_SOURCE_RFILE)
1.290 + {
1.291 + // cancel read from file
1.292 + ((RFile64 *)(iHandle->rfile))->ReadCancel();
1.293 + }
1.294 + else if (iHandle->sourceType == MP4_SOURCE_CAF)
1.295 + {
1.296 + // cancel read from caf object
1.297 + iHandle->cfile->ReadCancel(iStatus);
1.298 + }
1.299 + iAsyncReadOngoing = EFalse;
1.300 + }
1.301 +
1.302 + PRINT(_L("CFileAsyncParser::DoCancel() out"));
1.303 + }
1.304 +
1.305 +// -----------------------------------------------------------------------------
1.306 +// CFileAsyncParser::ReturnAudioFrames()
1.307 +// Return audio frames to observer.
1.308 +// -----------------------------------------------------------------------------
1.309 +//
1.310 +void CFileAsyncParser::ReturnAudioFrames()
1.311 + {
1.312 + PRINT(_L("CFileAsyncParser::ReturnAudioFrames() in"));
1.313 + TInt error = KErrNone;
1.314 +
1.315 + // Update last accessed position in file pointer
1.316 + if (iHandle->audioSampleOffset + iHandle->audioSampleSize - 1 > iHandle->lastAccessedPosInFile)
1.317 + {
1.318 + iHandle->lastAccessedPosInFile = iHandle->audioSampleOffset + iHandle->audioSampleSize - 1;
1.319 + }
1.320 +
1.321 + // Fill audio frame size
1.322 + iAudioSize = iHandle->audioSampleSize;
1.323 +
1.324 + // Fill audio timestamp information
1.325 + iAudioTimeStamp = 0;
1.326 + iAudioTimeStamp2 = 1; // fill also timestamp2 (wont be filled if 0)
1.327 + error = convertAudioSampleToTime(iHandle, iHandle->moov->trakAudio->mdia, &iAudioTimeStamp, &iAudioTimeStamp2);
1.328 + if (error == MP4_OK)
1.329 + {
1.330 + // Fill iReturnedAudioFrames
1.331 + iReturnedAudioFrames = 0;
1.332 + error = CalculateAudioFrameCount();
1.333 + }
1.334 +
1.335 + // Move forward in audio samples
1.336 + if (error == MP4_OK)
1.337 + {
1.338 + error = advanceAudioSample(iHandle, iHandle->moov->trakAudio);
1.339 + if ( error == -1)
1.340 + {
1.341 + error = MP4_ERROR;
1.342 + }
1.343 + else if ( error == -2 )
1.344 + {
1.345 + error = MP4_OK;
1.346 + iHandle->audioLast = MP4TRUE;
1.347 + }
1.348 + }
1.349 +
1.350 + iAsyncReadOngoing = EFalse;
1.351 + iHandle->asyncObserver->M3GPMP4LibAudioFramesAvailable(error,
1.352 + iAudioSize,
1.353 + iAudioTimeStamp,
1.354 + iReturnedAudioFrames,
1.355 + iAudioTimeStamp2);
1.356 + PRINT(_L("CFileAsyncParser::ReturnAudioFrames() out"));
1.357 + }
1.358 +
1.359 +// -----------------------------------------------------------------------------
1.360 +// CFileAsyncParser::ReturnVideoFrame()
1.361 +// Return video frame to observer.
1.362 +// -----------------------------------------------------------------------------
1.363 +//
1.364 +void CFileAsyncParser::ReturnVideoFrame()
1.365 + {
1.366 + PRINT(_L("CFileAsyncParser::ReturnVideoFrame() in"));
1.367 + TInt error = KErrNone;
1.368 +
1.369 + // Update last accessed position in file pointer
1.370 + if (iHandle->videoFrameOffset + iHandle->videoFrameSize - 1 > iHandle->lastAccessedPosInFile)
1.371 + {
1.372 + iHandle->lastAccessedPosInFile = iHandle->videoFrameOffset + iHandle->videoFrameSize - 1;
1.373 + }
1.374 +
1.375 + // Fill video frame size
1.376 + iVideoSize = iHandle->videoFrameSize;
1.377 +
1.378 + // Fill video timestamp information
1.379 + iVideoTimeStamp = 0;
1.380 + iVideoTimeStamp2 = 1; // fill also timestamp2 (wont be filled if 0)
1.381 + error = convertVideoSampleToTime(iHandle, iHandle->moov->trakVideo->mdia, &iVideoTimeStamp, &iVideoTimeStamp2);
1.382 + if (error == MP4_OK)
1.383 + {
1.384 + // Fill iKeyFrame
1.385 + iVideoKeyFrame = 0;
1.386 + error = isVideoFrameKeyFrame(iHandle, iHandle->moov->trakVideo, &iVideoKeyFrame);
1.387 + }
1.388 +
1.389 + // Move forward in video frames
1.390 + if (error == MP4_OK)
1.391 + {
1.392 + error = advanceVideoFrame(iHandle, iHandle->moov->trakVideo);
1.393 + if ( error == -1)
1.394 + {
1.395 + error = MP4_ERROR;
1.396 + }
1.397 + else if ( error == -2 )
1.398 + {
1.399 + error = MP4_OK;
1.400 + iHandle->videoLast = MP4TRUE;
1.401 + }
1.402 + }
1.403 +
1.404 + iAsyncReadOngoing = EFalse;
1.405 + iHandle->asyncObserver->M3GPMP4LibVideoFrameAvailable(error,
1.406 + iVideoSize,
1.407 + iVideoTimeStamp,
1.408 + iVideoKeyFrame,
1.409 + iVideoTimeStamp2);
1.410 + PRINT(_L("CFileAsyncParser::ReturnVideoFrame() out"));
1.411 + }
1.412 +
1.413 +// -----------------------------------------------------------------------------
1.414 +// CFileAsyncParser::CalculateAudioFrameCount()
1.415 +// Return video frame to observer.
1.416 +// -----------------------------------------------------------------------------
1.417 +//
1.418 +TInt CFileAsyncParser::CalculateAudioFrameCount()
1.419 + {
1.420 + mp4_i32 frameLength = 0;
1.421 + mp4_u32 numOfFrames = 0;
1.422 + mp4_u8 *framepointer = 0;
1.423 + mp4_u32 rawAmrFrameLength[16] = {13,14,16,18,20,21,27,32,6,0,0,0,0,0,0,1};
1.424 + trackAtom *trak = iHandle->moov->trakAudio;
1.425 +
1.426 + if (!trak)
1.427 + {
1.428 + return -1;
1.429 + }
1.430 +
1.431 + /* AMR */
1.432 + if (trak->mdia->minf)
1.433 + if (trak->mdia->minf->stbl)
1.434 + if (trak->mdia->minf->stbl->stsd)
1.435 + if (iHandle->type & MP4_TYPE_AMR_NB)
1.436 + {
1.437 + framepointer = iBuffer;
1.438 + numOfFrames = 0;
1.439 + while ( iBytesRead > 0 )
1.440 + {
1.441 + frameLength = rawAmrFrameLength[(TInt)(((*framepointer) & 0x78) >> 3)];
1.442 + if ( frameLength == 0)
1.443 + {
1.444 + return -4;
1.445 + }
1.446 + iBytesRead -= frameLength;
1.447 + framepointer += frameLength;
1.448 + numOfFrames++;
1.449 + }
1.450 + iReturnedAudioFrames = numOfFrames;
1.451 + }
1.452 + else if (iHandle->type & MP4_TYPE_AMR_WB)
1.453 + {
1.454 + /* Return the number of sample entries listed for this particular sample entry index */
1.455 + if (trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1])
1.456 + if (trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]->damr)
1.457 + iReturnedAudioFrames = trak->mdia->minf->stbl->stsd->sawb[iHandle->audioSampleEntryIndex - 1]->damr->framesPerSample;
1.458 + }
1.459 + else
1.460 + {
1.461 + }
1.462 +
1.463 + /* MPEG-4 audio */
1.464 + if (trak->mdia->minf)
1.465 + if (trak->mdia->minf->stbl)
1.466 + if (trak->mdia->minf->stbl->stsd)
1.467 + if (trak->mdia->minf->stbl->stsd->mp4a[iHandle->audioSampleEntryIndex - 1])
1.468 + iReturnedAudioFrames = 1;
1.469 +
1.470 + /* QCELP 13K as QCELPSampleEntry*/
1.471 + if (trak->mdia->minf)
1.472 + if (trak->mdia->minf->stbl)
1.473 + if (trak->mdia->minf->stbl->stsd)
1.474 + if ((iHandle->type & MP4_TYPE_QCELP_13K) && (!iHandle->qcelpStoredAsMPEGAudio))
1.475 + {
1.476 + /* Return the number of sample entries listed for this particular sample entry index */
1.477 + if (trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1])
1.478 + if (trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]->dqcp)
1.479 + iReturnedAudioFrames = trak->mdia->minf->stbl->stsd->sqcp[iHandle->audioSampleEntryIndex - 1]->dqcp->framesPerSample;
1.480 + }
1.481 +
1.482 + /* QCELP 13K as MPEG-4 audio */
1.483 + if (trak->mdia->minf)
1.484 + if (trak->mdia->minf->stbl)
1.485 + if (trak->mdia->minf->stbl->stsd)
1.486 + if (trak->mdia->minf->stbl->stsd->mp4a[iHandle->audioSampleEntryIndex - 1])
1.487 + iReturnedAudioFrames = 1;
1.488 +
1.489 + return MP4_OK;
1.490 + }
1.491 +
1.492 +// -----------------------------------------------------------------------------
1.493 +// CFileAsyncParser::RunL()
1.494 +// From CActive Called when async request completes.
1.495 +// -----------------------------------------------------------------------------
1.496 +//
1.497 +void CFileAsyncParser::RunL()
1.498 + {
1.499 + PRINT(_L("CFileAsyncParser::RunL() in"));
1.500 + if ( iStatus != KErrNone )
1.501 + {
1.502 + PRINT((_L("CFileAsyncParser::RunL() error in previous async: %d "), iStatus.Int() ));
1.503 + iError = iStatus.Int();
1.504 + iHandle->asyncObserver->M3GPMP4LibAudioFramesAvailable(MP4_FILE_ERROR,0,0,0,0);
1.505 + return;
1.506 + }
1.507 +
1.508 + if (!iAllDataInMemory)
1.509 + {
1.510 + if ((mp4_u32)iDiskBuffer->Length() == 0) // EOF or error
1.511 + {
1.512 + iError = MP4_FILE_ERROR; // metadata info doesn't match file -> corrupted clip.
1.513 + }
1.514 +
1.515 + memcpy(iBuffer+iBytesRead, iDiskBuffer->Ptr(), iBytesToRead-iBytesRead);
1.516 + iCurrentBufferReadPosition += iBytesToRead-iBytesRead;
1.517 + iCurrentDiskReadPosition += iDiskBuffer->Length();
1.518 + iBytesRead = iBytesToRead;
1.519 +
1.520 + // set handle disk buffer sizes to zero just in case.
1.521 + iHandle->diskReadBufPos = 0;
1.522 + iHandle->diskReadSize = 0;
1.523 + iHandle->diskReadBufStart = 0;
1.524 + iHandle->diskReadPos = iCurrentDiskReadPosition;
1.525 + }
1.526 +
1.527 + if ( iProcessingAudio )
1.528 + {
1.529 + ReturnAudioFrames();
1.530 + }
1.531 + else
1.532 + {
1.533 + ReturnVideoFrame();
1.534 + }
1.535 +
1.536 + PRINT(_L("CFileAsyncParser::RunL() out"));
1.537 + }
1.538 +
1.539 +// End of File