--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/lib3gp/impl/src/mp4parse.cpp Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,3329 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <3gplibrary/mp4config.h>
+#include <3gplibrary/mp4lib.h>
+#include "mp4atom.h"
+#include "mp4memwrap.h"
+#include "mp4file.h"
+#include "mp4buffer.h"
+#include "mp4endian.h"
+#include "mp4utils.h"
+
+using namespace ContentAccess;
+
+extern EXPORT_C MP4Err MP4ParseOpen(MP4Handle *apihandle,
+ MP4FileName filename)
+{
+ MP4HandleImp *handle = (MP4HandleStruct **)apihandle;
+ *handle = (MP4HandleImp)mp4malloc(sizeof(MP4HandleStruct));
+ if (*handle == NULL)
+ return MP4_OUT_OF_MEMORY;
+
+ (*handle)->file32Duplicate = NULL;
+ (*handle)->FileHandleFromOutside = EFalse;
+ (*handle)->sourceType = MP4_SOURCE_RFILE;
+
+ if (filename)
+ if (initFileRead(filename, *handle) == -1)
+ {
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_FILE_ERROR;
+ }
+
+ (*handle)->mem = listCreate();
+ if ((*handle)->mem == NULL)
+ {
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_OUT_OF_MEMORY;
+ }
+
+ if (((*handle)->buf = (mp4_u8 *)mp4malloc(TMPBUFSIZE)) == NULL)
+ {
+ listDestroyList((*handle)->mem);
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_OUT_OF_MEMORY;
+ }
+
+ if (((*handle)->diskReadBuf = (mp4_u8 *)mp4malloc(READBUFSIZE)) == NULL)
+ {
+ mp4free((*handle)->buf);
+ listDestroyList((*handle)->mem);
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_OUT_OF_MEMORY;
+ }
+
+ // register for stblib use
+ if (openStdlib() != MP4_OK)
+ {
+ mp4free((*handle)->diskReadBuf);
+ mp4free((*handle)->buf);
+ listDestroyList((*handle)->mem);
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+
+ return MP4_ERROR;
+ }
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseOpenFileHandle(MP4Handle *apihandle,
+ RFile *inputfile)
+{
+ MP4Err err;
+ RFile64 *f64 = new RFile64;
+ if (f64 == NULL)
+ {
+ return MP4_OUT_OF_MEMORY;
+ }
+ if (f64->Duplicate(*inputfile) != KErrNone)
+ {
+ delete f64;
+ return MP4_ERROR;
+ }
+ err = MP4ParseOpenFileHandle64(apihandle, f64);
+ if (err == MP4_OK)
+ {
+ MP4HandleImp* handle = (MP4HandleStruct **)apihandle;
+ (*handle)->file32Duplicate = (void*)(f64);
+ }
+ return err;
+}
+
+extern EXPORT_C MP4Err MP4ParseOpenFileHandle64(MP4Handle *apihandle,
+ RFile64 *inputfile)
+{
+ MP4HandleImp *handle = (MP4HandleStruct **)apihandle;
+ *handle = (MP4HandleImp)mp4malloc(sizeof(MP4HandleStruct));
+ if (*handle == NULL)
+ return MP4_OUT_OF_MEMORY;
+
+ (*handle)->file32Duplicate = NULL;
+ (*handle)->rfile = (void *)inputfile;
+ (*handle)->file = (*handle)->rfile;
+ (*handle)->FileHandleFromOutside = ETrue;
+ (*handle)->sourceType = MP4_SOURCE_RFILE;
+ if (inputfile == NULL)
+ {
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_FILE_ERROR;
+ }
+
+ (*handle)->mem = listCreate();
+ if ((*handle)->mem == NULL)
+ {
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_OUT_OF_MEMORY;
+ }
+
+ if (((*handle)->buf = (mp4_u8 *)mp4malloc(TMPBUFSIZE)) == NULL)
+ {
+ listDestroyList((*handle)->mem);
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_OUT_OF_MEMORY;
+ }
+
+ if (((*handle)->diskReadBuf = (mp4_u8 *)mp4malloc(READBUFSIZE)) == NULL)
+ {
+ mp4free((*handle)->buf);
+ listDestroyList((*handle)->mem);
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_OUT_OF_MEMORY;
+ }
+
+ // register for stblib use
+ if (openStdlib() != MP4_OK)
+ {
+ // clean up
+ mp4free((*handle)->diskReadBuf);
+ mp4free((*handle)->buf);
+ listDestroyList((*handle)->mem);
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+
+ return MP4_ERROR;
+ }
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseOpenCAF(MP4Handle *apihandle,
+ ContentAccess::CData *inputfile)
+{
+ MP4HandleImp *handle = (MP4HandleStruct **)apihandle;
+ *handle = (MP4HandleImp)mp4malloc(sizeof(MP4HandleStruct));
+ if (*handle == NULL)
+ return MP4_OUT_OF_MEMORY;
+
+ (*handle)->file32Duplicate = NULL;
+ (*handle)->cfile = inputfile;
+ (*handle)->file = (*handle)->cfile;
+ (*handle)->FileHandleFromOutside = ETrue;
+ (*handle)->sourceType = MP4_SOURCE_CAF;
+
+ if (inputfile == NULL)
+ {
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_FILE_ERROR;
+ }
+
+ (*handle)->mem = listCreate();
+ if ((*handle)->mem == NULL)
+ {
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_OUT_OF_MEMORY;
+ }
+
+ if (((*handle)->buf = (mp4_u8 *)mp4malloc(TMPBUFSIZE)) == NULL)
+ {
+ listDestroyList((*handle)->mem);
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_OUT_OF_MEMORY;
+ }
+
+ if (((*handle)->diskReadBuf = (mp4_u8 *)mp4malloc(READBUFSIZE)) == NULL)
+ {
+ mp4free((*handle)->buf);
+ listDestroyList((*handle)->mem);
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+ return MP4_OUT_OF_MEMORY;
+ }
+
+ // register for stblib use
+ if (openStdlib() != MP4_OK)
+ {
+ // clean up
+ mp4free((*handle)->diskReadBuf);
+ mp4free((*handle)->buf);
+ listDestroyList((*handle)->mem);
+ closeFile(*handle);
+ mp4free(*handle);
+ *handle = NULL;
+
+ return MP4_ERROR;
+ }
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseClose(MP4Handle apihandle)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle)
+ return MP4_ERROR;
+
+ if (handle->file)
+ closeFile(handle);
+
+ closeStdlib(); /* Free memory allocated by stdlib wrapper functions */
+
+ listDestroyList(handle->mem);
+
+ if (handle->diskReadBuf)
+ mp4free(handle->diskReadBuf);
+
+ if (handle->buf)
+ mp4free(handle->buf);
+
+ if (freeMOOV(handle->moov) < 0)
+ return MP4_ERROR;
+
+ if (freeFTYP(handle->ftyp) < 0)
+ return MP4_ERROR;
+
+ if (handle->file32Duplicate)
+ ((RFile64*)handle->file32Duplicate)->Close();
+
+ if (handle)
+ mp4free(handle);
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseRequestVideoDescription(MP4Handle apihandle,
+ mp4_u32 *videolength,
+ mp4_double *framerate,
+ mp4_u32 *videotype,
+ mp4_u32 *videowidth,
+ mp4_u32 *videoheight,
+ mp4_u32 *timescale)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle)
+ {
+ return MP4_ERROR;
+ }
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo)
+ return MP4_NO_VIDEO;
+
+ mp4_i32 videoError = 0;
+ videoError = determineVideoType(handle, videotype);
+ if ( videoError == -2 )
+ {
+ return MP4_NO_VIDEO;
+ }
+ else if ( videoError < 0 )
+ {
+ return MP4_ERROR;
+ }
+
+ if (determineVideoLength(handle, videolength) < 0)
+ return MP4_ERROR;
+
+ if (determineFrameRate(handle, framerate) < 0)
+ return MP4_ERROR;
+
+ if (determineVideoResolution(handle, videowidth, videoheight) < 0)
+ return MP4_ERROR;
+
+ if (determineVideoTimeScale(handle, timescale) < 0)
+ return MP4_ERROR;
+
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseRequestAudioDescription(MP4Handle apihandle,
+ mp4_u32 *audiolength,
+ mp4_u32 *audiotype,
+ mp4_u8 *framespersample,
+ mp4_u32 *timescale,
+ mp4_u32 *averagebitrate)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle)
+ {
+ return MP4_ERROR;
+ }
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ return MP4_ERROR;
+ if (!handle->moov->trakAudio)
+ return MP4_NO_AUDIO;
+
+ if (determineAudioLength(handle, audiolength) < 0)
+ return MP4_ERROR;
+
+ mp4_i32 audioError = 0;
+ audioError = determineAudioType(handle, audiotype);
+ if ( audioError == -2 )
+ {
+ return MP4_NO_AUDIO;
+ }
+ else if ( audioError < 0 )
+ {
+ return MP4_ERROR;
+ }
+
+ if (determineAudioFramesPerSample(handle, framespersample) < 0)
+ return MP4_ERROR;
+
+ if (determineAudioTimeScale(handle, timescale) < 0)
+ return MP4_ERROR;
+
+ if (averagebitrate != NULL)
+ if (determineAudioAverageBitRate(handle, averagebitrate) < 0)
+ return MP4_ERROR;
+
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseRequestStreamDescription(MP4Handle apihandle,
+ mp4_u32 *streamsize,
+ mp4_u32 *streamaveragebitrate)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (determineStreamSize(handle, streamsize) < 0)
+ return MP4_ERROR;
+
+ if (determineStreamAverageBitRate(handle, streamaveragebitrate, *streamsize) < 0)
+ return MP4_ERROR;
+
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseWriteData(MP4Handle apihandle,
+ mp4_u8 *buffer,
+ mp4_u32 bytestowrite)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (handle->file)
+ return MP4_ERROR;
+
+ if ((buffer == NULL) && (bytestowrite != 0))
+ return MP4_ERROR;
+
+ if (handle->LastWriteDataCalled == MP4TRUE)
+ return MP4_ERROR; // WriteData() call has been made before with bytestowrite=0, can not call again.
+
+ if (bytestowrite != 0)
+ {
+ if (addData(handle, buffer, bytestowrite) == -1)
+ return MP4_OUT_OF_MEMORY;
+ }
+ else
+ handle->LastWriteDataCalled = MP4TRUE;
+
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseGetBufferedBytes(MP4Handle apihandle,
+ mp4_u32 *bytes)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ *bytes = getBufferedBytes(handle);
+
+ if (handle->file)
+ return MP4_FILE_MODE;
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseNextFrameType(MP4Handle apihandle,
+ mp4_u32 *type)
+ {
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ /* No audio nor video */
+ if ((!handle->moov->trakAudio) && (!handle->moov->trakVideo))
+ return MP4_ERROR;
+
+ mp4_u32 audiotype = 0;
+ mp4_i32 audioerror = 0;
+ if (handle->moov->trakAudio)
+ {
+ audioerror = determineAudioType(handle, &audiotype);
+ }
+
+ mp4_u32 videotype = 0;
+ mp4_i32 videoerror = 0;
+ if (handle->moov->trakVideo)
+ {
+ videoerror = determineVideoType(handle, &videotype);
+ }
+
+ /* Audio track only */
+ if (handle->moov->trakAudio && !handle->moov->trakVideo)
+ {
+ if (audioerror == 0)
+ {
+ // if audio is of supported type, check if the last audio frame has been
+ // retrieved
+ if (handle->audioLast)
+ {
+ return MP4_NO_FRAME;
+ }
+ else
+ {
+ *type = audiotype;
+ return MP4_OK;
+ }
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+ }
+
+ /* Video track only */
+ if (handle->moov->trakVideo && !handle->moov->trakAudio)
+ {
+ if (videoerror == 0)
+ {
+ // if video is of supported type, check if the last video frame has been
+ // retrieved
+ if (handle->videoLast)
+ {
+ return MP4_NO_FRAME;
+ }
+ else
+ {
+ *type = videotype;
+ return MP4_OK;
+ }
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+ }
+
+ /* All audio has been read, but there is video left */
+ if (handle->audioLast && !handle->videoLast)
+ {
+ if (videoerror == 0)
+ {
+ *type = videotype;
+ return MP4_OK;
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+ }
+
+ /* All video has been read, but there is audio left */
+ if (handle->videoLast && !handle->audioLast)
+ {
+ if (audioerror == 0)
+ {
+ *type = audiotype;
+ return MP4_OK;
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+ }
+
+ /* All data has been read */
+ if (handle->audioLast && handle->videoLast)
+ {
+ return MP4_NO_FRAME;
+ }
+
+ if (handle->audioSampleOffset < handle->videoFrameOffset)
+ {
+ /* Next frame is audio */
+ if (audioerror == 0)
+ {
+ *type = audiotype;
+ return MP4_OK;
+ }
+ else if ( (audioerror == -2) && (videoerror == 0) )
+ {
+ *type = videotype;
+ return MP4_OK;
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+ }
+ else
+ {
+ /* Next frame is video */
+ if (videoerror == 0)
+ {
+ *type = videotype;
+ return MP4_OK;
+ }
+ else if ( (videoerror == -2) && (audioerror == 0) )
+ {
+ *type = audiotype;
+ return MP4_OK;
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+ }
+ }
+
+extern EXPORT_C MP4Err MP4ParseNextFrameSize(MP4Handle apihandle,
+ mp4_u32 type,
+ mp4_u32 *framesize)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ switch (type & handle->type)
+ {
+ case MP4_TYPE_MPEG4_VIDEO:
+ case MP4_TYPE_H263_PROFILE_0:
+ case MP4_TYPE_H263_PROFILE_3:
+ case MP4_TYPE_AVC_PROFILE_BASELINE:
+ case MP4_TYPE_AVC_PROFILE_MAIN:
+ case MP4_TYPE_AVC_PROFILE_EXTENDED:
+ case MP4_TYPE_AVC_PROFILE_HIGH:
+
+ /* There is a next video frame */
+
+ if (!handle->videoLast)
+ *framesize = handle->videoFrameSize;
+ else
+ {
+ *framesize = 0;
+
+ return MP4_NO_REQUESTED_FRAME;
+ }
+
+ break;
+
+ case MP4_TYPE_MPEG4_AUDIO:
+ case MP4_TYPE_AMR_NB:
+ case MP4_TYPE_AMR_WB:
+ case MP4_TYPE_QCELP_13K:
+
+ /* There is a next audio frame */
+
+ if (!handle->audioLast)
+ *framesize = handle->audioSampleSize;
+ else
+ {
+ *framesize = 0;
+
+ return MP4_NO_REQUESTED_FRAME;
+ }
+
+ break;
+
+ case MP4_TYPE_NONE:
+ default:
+
+ if (type == MP4_TYPE_MPEG4_VIDEO ||
+ type == MP4_TYPE_H263_PROFILE_0 ||
+ type == MP4_TYPE_H263_PROFILE_3 ||
+ type == MP4_TYPE_MPEG4_AUDIO ||
+ type == MP4_TYPE_AMR_NB ||
+ type == MP4_TYPE_AMR_WB ||
+ isAvcVideo(type) ||
+ type == MP4_TYPE_QCELP_13K
+ )
+ return MP4_NO_REQUESTED_FRAME;
+
+ return MP4_INVALID_TYPE;
+ }
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseReadVideoFrame(MP4Handle apihandle,
+ mp4_u8 *buffer,
+ mp4_u32 buffersize,
+ mp4_u32 *framesize,
+ mp4_u32 *timestamp,
+ mp4_bool *keyframe,
+ mp4_u32 *timestamp2)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ /* Is video available? */
+
+ if (!((handle->type & MP4_TYPE_MPEG4_VIDEO) ||
+ (handle->type & MP4_TYPE_H263_PROFILE_0) ||
+ (handle->type & MP4_TYPE_H263_PROFILE_3) ||
+ containsAvcVideo( handle->type ) ))
+ return MP4_ERROR;
+
+ /* Are there samples left? */
+
+ if (handle->videoLast)
+ return MP4_NO_FRAME;
+
+ if (!handle->moov)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo)
+ return MP4_ERROR;
+
+ switch (fetchVideoFrame(handle, handle->moov->trakVideo, buffer, buffersize, framesize, timestamp, keyframe, timestamp2))
+ {
+ case -1:
+ return MP4_ERROR;
+ case -2:
+ return MP4_BUFFER_TOO_SMALL;
+ case -3:
+ return MP4_NOT_AVAILABLE;
+ case -4:
+ return MP4_INVALID_INPUT_STREAM;
+ default:
+ break;
+ }
+
+ switch (advanceVideoFrame(handle, handle->moov->trakVideo))
+ {
+ case -1:
+ return MP4_ERROR;
+ case -2:
+ handle->videoLast = MP4TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseReadVideoDecoderSpecificInfo(MP4Handle apihandle,
+ mp4_u8 *buffer,
+ mp4_u32 buffersize,
+ mp4_u32 *decspecinfosize)
+ {
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ /* Is video type MPEG or AVC? */
+ if (!(handle->type & MP4_TYPE_MPEG4_VIDEO) &&
+ !(containsAvcVideo( handle->type )) )
+ {
+ return MP4_ERROR;
+ }
+
+ if (!handle->moov)
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakVideo)
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakVideo->mdia)
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakVideo->mdia->minf)
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd)
+ {
+ return MP4_ERROR;
+ }
+ if (handle->videoSampleEntryIndex > handle->moov->trakVideo->mdia->minf->stbl->stsd->entryCount)
+ {
+ return MP4_ERROR;
+ }
+
+ TInt index = handle->videoSampleEntryIndex - 1;
+ if (handle->videoSampleEntryIndex == 0)
+ {
+ // even though the video sample contains no actual data, if the video sample exist
+ // and contains decoder specific info, return it anyway
+ index = 0;
+ }
+
+ if (handle->type & MP4_TYPE_MPEG4_VIDEO)
+ {
+ /* Copy DecoderSpecificInfo into buffer */
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index])
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]->esd)
+ {
+ return MP4_ERROR;
+ }
+
+ *decspecinfosize = handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]->esd->decSpecificInfoSize;
+ if (buffersize < handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]->esd->decSpecificInfoSize)
+ {
+ return MP4_BUFFER_TOO_SMALL;
+ }
+
+ mp4memcpy(buffer,
+ handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]->esd->decSpecificInfo,
+ handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[index]->esd->decSpecificInfoSize);
+ }
+ else if ( containsAvcVideo( handle->type ) )
+ {
+ /* Copy the AVCDecoderConfigurationRecord into buffer */
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index])
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]->avcc)
+ {
+ return MP4_ERROR;
+ }
+
+ *decspecinfosize = handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]->avcc->avcConfigSize;
+ if (buffersize < handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]->avcc->avcConfigSize)
+ {
+ return MP4_BUFFER_TOO_SMALL;
+ }
+
+ mp4memcpy(buffer,
+ handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]->avcc->avcConfig,
+ handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[index]->avcc->avcConfigSize);
+ }
+
+ return MP4_OK;
+ }
+
+extern EXPORT_C MP4Err MP4ParseReadAudioFrames(MP4Handle apihandle,
+ mp4_u8 *buffer,
+ mp4_u32 buffersize,
+ mp4_u32 *audiosize,
+ mp4_u32 *timestamp,
+ mp4_u32 *returnedframes,
+ mp4_u32 *timestamp2)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ /* Is audio available? */
+
+ if (!((handle->type & MP4_TYPE_MPEG4_AUDIO) ||
+ (handle->type & MP4_TYPE_AMR_NB) ||
+ (handle->type & MP4_TYPE_AMR_WB) ||
+ (handle->type & MP4_TYPE_QCELP_13K)))
+ return MP4_ERROR;
+
+ /* Are there samples left? */
+
+ if (handle->audioLast)
+ return MP4_NO_FRAME;
+
+ if (!handle->moov)
+ return MP4_ERROR;
+ if (!handle->moov->trakAudio)
+ return MP4_ERROR;
+
+ switch (fetchAudioSample(handle, handle->moov->trakAudio, buffer, buffersize, audiosize, timestamp, returnedframes, timestamp2))
+ {
+ case -1:
+ return MP4_ERROR;
+ case -2:
+ return MP4_BUFFER_TOO_SMALL;
+ case -3:
+ return MP4_NOT_AVAILABLE;
+ case -4:
+ return MP4_INVALID_INPUT_STREAM;
+ default:
+ break;
+ }
+
+ switch (advanceAudioSample(handle, handle->moov->trakAudio))
+ {
+ case -1:
+ return MP4_ERROR;
+ case -2:
+ handle->audioLast = MP4TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseReadAudioDecoderSpecificInfo(MP4Handle apihandle,
+ mp4_u8 *buffer,
+ mp4_u32 buffersize,
+ mp4_u32 *decspecinfosize)
+ {
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakAudio)
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakAudio->mdia)
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakAudio->mdia->minf)
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakAudio->mdia->minf->stbl)
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd)
+ {
+ return MP4_ERROR;
+ }
+
+
+ TInt index = handle->audioSampleEntryIndex - 1;
+ if (handle->audioSampleEntryIndex == 0)
+ {
+ // even though the audio sample contains no actual data, if the audio sample exist
+ // and contains decoder specific info, return it anyway
+ index = 0;
+ }
+
+ /* Audio type */
+ if ((handle->type & MP4_TYPE_MPEG4_AUDIO) ||
+ ((handle->type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio)))
+ {
+ /* Copy DecoderSpecificInfo into buffer */
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index])
+ {
+ return MP4_ERROR;
+ }
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]->esd)
+ {
+ return MP4_ERROR;
+ }
+
+ *decspecinfosize = handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]->esd->decSpecificInfoSize;
+ if (buffersize < handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]->esd->decSpecificInfoSize)
+ {
+ return MP4_BUFFER_TOO_SMALL;
+ }
+
+ mp4memcpy(buffer,
+ handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]->esd->decSpecificInfo,
+ handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[index]->esd->decSpecificInfoSize);
+ }
+ else if ((handle->type & MP4_TYPE_AMR_NB) ||
+ (handle->type & MP4_TYPE_AMR_WB) ||
+ ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio)))
+ {
+ /* Copy DecoderSpecificInfo into buffer */
+ if (handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index] == NULL &&
+ handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index] == NULL &&
+ handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index] == NULL)
+ {
+ return MP4_ERROR;
+ }
+
+ if (handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index])
+ {
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr)
+ {
+ return MP4_ERROR;
+ }
+
+ *decspecinfosize = 9;
+ if (buffersize < *decspecinfosize)
+ {
+ return MP4_BUFFER_TOO_SMALL;
+ }
+
+ mp4memcpy(buffer, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr->vendor), 4);
+ mp4memcpy(buffer+4, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr->decoderVersion), 1);
+ mp4memcpy(buffer+5, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr->modeSet), 2);
+ mp4memcpy(buffer+7, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr->modeChangePeriod), 1);
+ mp4memcpy(buffer+8, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[index]->damr->framesPerSample), 1);
+ }
+
+ if (handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index])
+ {
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr)
+ {
+ return MP4_ERROR;
+ }
+
+ *decspecinfosize = 9;
+ if (buffersize < *decspecinfosize)
+ {
+ return MP4_BUFFER_TOO_SMALL;
+ }
+
+ mp4memcpy(buffer, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr->vendor), 4);
+ mp4memcpy(buffer+4, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr->decoderVersion), 1);
+ mp4memcpy(buffer+5, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr->modeSet), 2);
+ mp4memcpy(buffer+7, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr->modeChangePeriod), 1);
+ mp4memcpy(buffer+8, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[index]->damr->framesPerSample), 1);
+ }
+
+ if (handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index])
+ {
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index]->dqcp)
+ {
+ return MP4_ERROR;
+ }
+
+ *decspecinfosize = 6;
+ if (buffersize < *decspecinfosize)
+ {
+ return MP4_BUFFER_TOO_SMALL;
+ }
+
+ mp4memcpy(buffer, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index]->dqcp->vendor), 4);
+ mp4memcpy(buffer+4, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index]->dqcp->decoderVersion), 1);
+ mp4memcpy(buffer+5, &(handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[index]->dqcp->framesPerSample), 1);
+ }
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+
+ return MP4_OK;
+ }
+
+extern EXPORT_C MP4Err MP4ParseGetNextVideoTimestamp(MP4Handle apihandle,
+ mp4_u32 *timestamp,
+ mp4_u32 *timestamp2)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (handle->videoLast)
+ return MP4_END_OF_VIDEO;
+
+ if (convertVideoSampleToTime(handle, handle->moov->trakVideo->mdia, timestamp, timestamp2) < 0)
+ return MP4_ERROR;
+
+ switch (advanceVideoFrame(handle, handle->moov->trakVideo))
+ {
+ case -1:
+ return MP4_ERROR;
+ case -2:
+ handle->videoLast = MP4TRUE;
+ break;
+ default:
+ break;
+ }
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseIsStreamable(MP4Handle apihandle)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ /* There is no audio nor video */
+
+ if (!handle->audioSampleNum && !handle->videoSampleNum)
+ return MP4_ERROR;
+
+ /* There is audio, but no video */
+
+ if (handle->audioSampleNum && !handle->videoSampleNum)
+ {
+ if (!handle->moov)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio->mdia)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio->mdia->minf)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stco)
+ return MP4_ERROR;
+
+ if (handle->moov->trakAudio->mdia->minf->stbl->stco->entryCount < 2)
+ return MP4_OK;
+
+ if (getChunkOffset(handle->moov->trakAudio->mdia->minf->stbl, 0) <
+ getChunkOffset(handle->moov->trakAudio->mdia->minf->stbl, 1))
+ return MP4_OK;
+
+ return MP4_NOT_STREAMABLE;
+ }
+
+ /* There is video, but no audio */
+
+ if (handle->videoSampleNum && !handle->audioSampleNum)
+ {
+ if (!handle->moov)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stco)
+ return MP4_ERROR;
+
+ if (handle->moov->trakVideo->mdia->minf->stbl->stco->entryCount < 2)
+ return MP4_OK;
+
+ if (getChunkOffset(handle->moov->trakVideo->mdia->minf->stbl, 0) <
+ getChunkOffset(handle->moov->trakVideo->mdia->minf->stbl, 1))
+ return MP4_OK;
+
+ return MP4_NOT_STREAMABLE;
+ }
+
+ /* There are both audio and video */
+
+ if (handle->videoSampleNum && handle->audioSampleNum)
+ {
+ mp4_i64 diff;
+
+
+ if (!handle->moov)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio->mdia)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio->mdia->minf)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stco)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakAudio->mdia->minf->stbl->stco->entryCount)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stco)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stco->entryCount)
+ return MP4_ERROR;
+
+ diff = getChunkOffset(handle->moov->trakAudio->mdia->minf->stbl, 0) -
+ getChunkOffset(handle->moov->trakVideo->mdia->minf->stbl, 0);
+
+ /* If the distance between 1st audio and video chunk offsets is larger
+ than 50000, MP4 is not streamable. */
+
+ if (diff < -50000 || diff > 50000)
+ return MP4_NOT_STREAMABLE;
+
+ return MP4_OK;
+ }
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseSeek(MP4Handle apihandle,
+ mp4_u32 position,
+ mp4_u32 *audioPosition,
+ mp4_u32 *videoPosition,
+ mp4_bool keyframe)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ return MP4_ERROR;
+
+ handle->audioLast = MP4FALSE;
+ handle->videoLast = MP4FALSE;
+
+ /* There is no audio nor video */
+
+ if (!handle->audioSampleNum && !handle->videoSampleNum)
+ return MP4_ERROR;
+
+ /* There is only audio */
+
+ if (handle->audioSampleNum && !handle->videoSampleNum)
+ {
+ mp4_u32 audioSample;
+
+ if (!handle->moov->trakAudio)
+ return MP4_ERROR;
+ if (!handle->moov->trakAudio->mdia)
+ return MP4_ERROR;
+
+ if (convertTimeToSample(handle, handle->moov->trakAudio, position, &audioSample) < 0)
+ return MP4_CANT_SEEK;
+
+ if (goToAudioSample(handle, handle->moov->trakAudio, audioSample) < 0)
+ return MP4_ERROR;
+
+ if (convertAudioSampleToTime(handle, handle->moov->trakAudio->mdia, audioPosition, NULL) < 0)
+ return MP4_ERROR;
+
+ if (handle->file)
+ {
+ handle->lastAccessedPosInFile = handle->audioSampleOffset + handle->audioSampleSize - 1;
+ }
+ else
+ {
+ // check if there is enough data in the buffers
+ if (handle->audioSampleOffset + handle->audioSampleSize - 1 > getCumulativeBufferedBytes(handle))
+ {
+ if (handle->LastWriteDataCalled)
+ {
+ // user has indicated that no more data will be available
+ return MP4_CANT_SEEK;
+ }
+ else
+ {
+ // signal to user that more data needed
+ return MP4_NOT_AVAILABLE;
+ }
+ }
+ else if (handle->audioSampleOffset < handle->absPosition)
+ {
+ handle->absPosition = handle->audioSampleOffset;
+ }
+ }
+
+ return MP4_OK;
+ }
+
+ /* There is only video */
+ if (handle->videoSampleNum && !handle->audioSampleNum)
+ {
+ mp4_u32 videoSample;
+ mp4_u32 newVideoSample;
+
+ if (!handle->moov->trakVideo)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (convertTimeToSample(handle, handle->moov->trakVideo, position, &videoSample) < 0)
+ return MP4_CANT_SEEK;
+
+ if (keyframe)
+ {
+ if (findVideoKeyFrame(handle, handle->moov->trakVideo, videoSample, &newVideoSample) < 0)
+ {
+ return MP4_CANT_SEEK;
+ }
+ videoSample = newVideoSample;
+ }
+
+ if (goToVideoSample(handle, handle->moov->trakVideo, videoSample) < 0)
+ {
+ return MP4_ERROR;
+ }
+
+ if (convertVideoSampleToTime(handle, handle->moov->trakVideo->mdia, videoPosition, NULL) < 0)
+ {
+ return MP4_ERROR;
+ }
+
+ if (handle->file)
+ {
+ handle->lastAccessedPosInFile = handle->videoFrameOffset + handle->videoFrameSize - 1;
+ }
+ else // input is a stream
+ {
+ // check if there is enough data in the buffers
+ if (handle->videoFrameOffset + handle->videoFrameSize > getCumulativeBufferedBytes(handle))
+ {
+ if (handle->LastWriteDataCalled)
+ {
+ // user has indicated that no more data will be available
+ return MP4_CANT_SEEK;
+ }
+ else
+ {
+ // signal to user that more data needed
+ return MP4_NOT_AVAILABLE;
+ }
+ }
+ else
+ {
+ handle->absPosition = handle->videoFrameOffset;
+ }
+ }
+
+ return MP4_OK;
+ }
+
+ /* There is audio and video */
+
+ if (handle->videoSampleNum && handle->audioSampleNum)
+ {
+ mp4_u32 audioSample;
+ mp4_u32 videoSample;
+ mp4_u32 newVideoSample;
+
+
+ if (!handle->moov->trakAudio)
+ return MP4_ERROR;
+ if (!handle->moov->trakAudio->mdia)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (convertTimeToSample(handle, handle->moov->trakVideo, position, &videoSample) < 0)
+ return MP4_CANT_SEEK;
+
+ if (keyframe)
+ {
+ if (findVideoKeyFrame(handle, handle->moov->trakVideo, videoSample, &newVideoSample) < 0)
+ return MP4_CANT_SEEK;
+
+ videoSample = newVideoSample;
+ }
+
+ if (goToVideoSample(handle, handle->moov->trakVideo, videoSample) < 0)
+ return MP4_ERROR;
+
+ if (convertVideoSampleToTime(handle, handle->moov->trakVideo->mdia, videoPosition, NULL) < 0)
+ return MP4_ERROR;
+
+ if (handle->file)
+ {
+ handle->lastAccessedPosInFile = handle->videoFrameOffset + handle->videoFrameSize - 1;
+ }
+ else // input is a stream
+ {
+ // check if there is enough data in the buffers
+ if (handle->videoFrameOffset + handle->videoFrameSize > getCumulativeBufferedBytes(handle))
+ {
+ if (handle->LastWriteDataCalled)
+ {
+ // user has indicated that no more data will be available
+ return MP4_CANT_SEEK;
+ }
+ else
+ {
+ // signal to user that more data needed
+ return MP4_NOT_AVAILABLE;
+ }
+ }
+ else
+ {
+ handle->absPosition = handle->videoFrameOffset;
+ }
+ }
+
+ /* Audio */
+
+ if (convertTimeToSample(handle, handle->moov->trakAudio, *videoPosition, &audioSample) < 0)
+ return MP4_CANT_SEEK;
+
+ if (goToAudioSample(handle, handle->moov->trakAudio, audioSample) < 0)
+ return MP4_ERROR;
+
+ if (convertAudioSampleToTime(handle, handle->moov->trakAudio->mdia, audioPosition, NULL) < 0)
+ return MP4_ERROR;
+
+ if (handle->file)
+ {
+ if (handle->audioSampleOffset + handle->audioSampleSize - 1 > handle->lastAccessedPosInFile)
+ {
+ handle->lastAccessedPosInFile = handle->audioSampleOffset + handle->audioSampleSize - 1;
+ }
+ }
+ else // input is a stream
+ {
+ // check if there is enough data in the buffers
+ if (handle->audioSampleOffset + handle->audioSampleSize - 1 > getCumulativeBufferedBytes(handle))
+ {
+ if (handle->LastWriteDataCalled)
+ {
+ // user has indicated that no more data will be available
+ return MP4_CANT_SEEK;
+ }
+ else
+ {
+ // signal to user that more data needed
+ return MP4_NOT_AVAILABLE;
+ }
+ }
+ else if (handle->audioSampleOffset < handle->absPosition)
+ {
+ handle->absPosition = handle->audioSampleOffset;
+ }
+ }
+
+ return MP4_OK;
+ }
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseIsFrameAvailable(MP4Handle apihandle,
+ mp4_u32 type)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ switch (type & handle->type)
+ {
+ case MP4_TYPE_MPEG4_VIDEO:
+ case MP4_TYPE_H263_PROFILE_0:
+ case MP4_TYPE_H263_PROFILE_3:
+ case MP4_TYPE_AVC_PROFILE_BASELINE:
+ case MP4_TYPE_AVC_PROFILE_MAIN:
+ case MP4_TYPE_AVC_PROFILE_EXTENDED:
+ case MP4_TYPE_AVC_PROFILE_HIGH:
+
+ /* There is no frame available if last sample has been reached */
+
+ if (handle->videoLast)
+ return MP4_NO_REQUESTED_FRAME;
+
+ /* Input in a file => it is available */
+
+ if (handle->file)
+ return MP4_OK;
+
+ /* If frame has been buffered, it is available */
+
+ if (handle->videoFrameOffset + handle->videoFrameSize <=
+ getCumulativeBufferedBytes(handle))
+ return MP4_OK;
+ else
+ return MP4_NOT_AVAILABLE;
+
+ case MP4_TYPE_MPEG4_AUDIO:
+ case MP4_TYPE_AMR_NB:
+ case MP4_TYPE_AMR_WB:
+ case MP4_TYPE_QCELP_13K:
+
+ /* There is no frame available if last sample has been reached */
+
+ if (handle->audioLast)
+ return MP4_NO_REQUESTED_FRAME;
+
+ /* Input in a file => it is available */
+
+ if (handle->file)
+ return MP4_OK;
+
+ /* If frame has been buffered, it is available */
+
+ if (handle->audioSampleOffset + handle->audioSampleSize <=
+ getCumulativeBufferedBytes(handle))
+ return MP4_OK;
+ else
+ return MP4_NOT_AVAILABLE;
+
+ case MP4_TYPE_NONE:
+ default:
+
+ return MP4_NO_REQUESTED_FRAME;
+ }
+}
+
+extern EXPORT_C MP4Err MP4ParseGetLastPosition(MP4Handle apihandle,
+ mp4_u32 *position)
+{
+ return MP4ParseGetLastPosition64(apihandle, (mp4_u64 *)position);
+}
+
+extern EXPORT_C MP4Err MP4ParseGetLastPosition64(MP4Handle apihandle,
+ mp4_u64 *position)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->file)
+ {
+ *position = handle->absPosition; // return the latest accessed absolute byte location of the stream.
+ return MP4_OK;
+ }
+ *position = handle->lastAccessedPosInFile;
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseGetNumberOfVideoFrames(MP4Handle apihandle,
+ mp4_u32 *numberOfFrames)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ return MP4_ERROR;
+
+ if (handle->moov->trakVideo)
+ {
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsz)
+ return MP4_ERROR;
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+
+ *numberOfFrames = handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount;
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseGetVideoFrameSize(MP4Handle apihandle,
+ mp4_u32 index,
+ mp4_u32 *frameSize)
+ {
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ return MP4_ERROR;
+
+ if (handle->moov->trakVideo)
+ {
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsz)
+ return MP4_ERROR;
+
+ // ensure the index entered is within bound
+ if (index >= handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount)
+ return MP4_ERROR;
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+
+ *frameSize = handle->moov->trakVideo->mdia->minf->stbl->stsz->entrySize[index];
+ return MP4_OK;
+ }
+
+extern EXPORT_C MP4Err MP4ParseGetVideoFrameStartTime(MP4Handle apihandle,
+ mp4_u32 index,
+ mp4_u32 *timestamp,
+ mp4_u32 *timestampms)
+{
+ mp4_u32 tmptime=0;
+ mp4_u32 sample=0;
+ mp4_u32 entry=0;
+ mp4_u32 videoSampleNumber = index+1;
+
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ {
+ return MP4_ERROR;
+ }
+
+ if (handle->moov->trakVideo)
+ {
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stts)
+ return MP4_ERROR;
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+
+ for (;;)
+ {
+ if (sample + handle->moov->trakVideo->mdia->minf->stbl->stts->sampleCount[entry] < videoSampleNumber)
+ {
+ sample += handle->moov->trakVideo->mdia->minf->stbl->stts->sampleCount[entry];
+ tmptime += (handle->moov->trakVideo->mdia->minf->stbl->stts->sampleCount[entry] *
+ handle->moov->trakVideo->mdia->minf->stbl->stts->sampleDelta[entry]);
+ entry++;
+ if (entry == handle->moov->trakVideo->mdia->minf->stbl->stts->entryCount)
+ return MP4_ERROR;
+ }
+ else
+ {
+ tmptime += ((videoSampleNumber - sample - 1) * handle->moov->trakVideo->mdia->minf->stbl->stts->sampleDelta[entry]);
+ break;
+ }
+ }
+ if (handle->moov->trakVideo->mdia->mdhd->timeScale == 0)
+ {
+ return MP4_ERROR;
+ }
+
+ *timestamp = tmptime;
+
+ *timestampms =(mp4_u32)((mp4_double)tmptime * (mp4_double)1000 /
+ (mp4_double)handle->moov->trakVideo->mdia->mdhd->timeScale + (mp4_double)0.5);
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseGetVideoFrameType(MP4Handle apihandle,
+ mp4_u32 index,
+ mp4_bool *frametype)
+ {
+ mp4_u32 i;
+ mp4_u32 videoSampleNumber = index+1;
+ mp4_bool keyFrame = MP4FALSE;
+
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ return MP4_ERROR;
+
+ if (handle->moov->trakVideo)
+ {
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stss)
+ return MP4_ERROR;
+
+ // if the video frame index is out of bounds
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsz ||
+ videoSampleNumber > handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount)
+ return MP4_ERROR;
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+
+ for (i=0; i < handle->moov->trakVideo->mdia->minf->stbl->stss->entryCount; i++)
+ {
+ if (handle->moov->trakVideo->mdia->minf->stbl->stss->sampleNumber[i] == videoSampleNumber)
+ {
+ keyFrame = MP4TRUE;
+ break;
+ }
+ }
+
+ *frametype = keyFrame;
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseGetVideoSampleEntryIndex(MP4Handle apihandle, mp4_u32 *videosampleentryindex)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov->trakVideo)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (handle->videoSampleEntryIndex == 0) /* can't be zero. Sample Entry index must be at least 1*/
+ return MP4_ERROR;
+ else
+ *videosampleentryindex = handle->videoSampleEntryIndex;
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseGetAudioSampleEntryIndex(MP4Handle apihandle, mp4_u32 *audiosampleentryindex)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov->trakAudio)
+ return MP4_ERROR;
+ if (!handle->moov->trakAudio->mdia)
+ return MP4_ERROR;
+
+ if (handle->audioSampleEntryIndex == 0) /* can't be zero. Sample Entry index must be at least 1*/
+ return MP4_ERROR;
+ else
+ *audiosampleentryindex = handle->audioSampleEntryIndex;
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseGetQCELPStorageMode(MP4Handle apihandle, mp4_u8 *qcelpStorageMode)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov->trakAudio)
+ return MP4_ERROR;
+ if (!handle->moov->trakAudio->mdia)
+ return MP4_ERROR;
+ if (!(handle->type & MP4_TYPE_QCELP_13K))
+ return MP4_ERROR;
+
+ if(handle->qcelpStoredAsMPEGAudio)
+ *qcelpStorageMode = 1;
+ else
+ *qcelpStorageMode = 0;
+
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4GetVideoFrameProperties(MP4Handle apihandle,mp4_u32 startindex,mp4_u32 sizeofarray,TFrameInfoParameters* aFrameInfoArray)
+{
+
+ mp4_u32 tmptime=0;
+ mp4_u32 sample=0;
+ mp4_u32 entry=0;
+ mp4_u32 videoSampleNumber = (startindex+sizeofarray)+1;
+ mp4_u32 i;
+ mp4_u32 j;
+ mp4_u32 index;
+ mp4_u32 actualIndex;
+
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ TBool sampleSyncTableExists = ETrue;
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+
+ if (!handle->moov)
+ return MP4_ERROR;
+
+ if (handle->moov->trakVideo)
+ {
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsz) //for size
+ return MP4_ERROR;
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stss) //for type
+ {
+ // If sample sync table doesn't exist mark all frames as intra / random access point
+ sampleSyncTableExists = EFalse;
+ }
+
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stts) //For timeStamp
+ return MP4_ERROR;
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+
+
+ if (handle->moov->trakVideo->mdia->mdhd->timeScale == 0) //For timeStamp
+ {
+ return MP4_ERROR;
+ }
+
+ if((startindex+sizeofarray) > handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount) //more than number of frames
+ {
+ return MP4_ERROR;
+ }
+
+ if(aFrameInfoArray == NULL)
+ {
+ return MP4_NO_OUTPUT_BUFFER;
+ }
+
+ if ( sampleSyncTableExists )
+ {
+ for (i=0; i < handle->moov->trakVideo->mdia->minf->stbl->stss->entryCount; i++) //set all types to true
+ {
+ //because counting is stored from 1 but index from 0
+ mp4_u32 currFrame = handle->moov->trakVideo->mdia->minf->stbl->stss->sampleNumber[i] - 1;
+
+ if ((currFrame >= startindex) && (currFrame < (startindex + sizeofarray)))
+ {
+ aFrameInfoArray[currFrame - startindex].iType = MP4TRUE;
+ }
+ }
+ }
+
+ index=0; //initialize to beginning
+ actualIndex=0;//array indexer
+
+ for(;;)
+ {
+ if(index< videoSampleNumber)
+ {
+ for(j=0;j<handle->moov->trakVideo->mdia->minf->stbl->stts->sampleCount[entry];j++)
+ {
+ if(index >=startindex)
+ {
+ //first initialize flag to false if not previously set to true.
+ if(aFrameInfoArray[actualIndex].iType != MP4TRUE)
+ {
+ aFrameInfoArray[actualIndex].iType = MP4FALSE;
+ }
+ //aFrameInfoArray[index].iStartTime = tmptime + handle->moov->trakVideo->mdia->minf->stbl->stts->sampleDelta[entry];
+ if(index==0) //so first frame of entire clip
+ {
+ aFrameInfoArray[actualIndex].iStartTime =0;
+ }
+ else
+ {
+ aFrameInfoArray[actualIndex].iStartTime = (mp4_u32)((mp4_double)tmptime * (mp4_double)1000 /
+ (mp4_double)handle->moov->trakVideo->mdia->mdhd->timeScale + (mp4_double)0.5);
+ }
+ aFrameInfoArray[actualIndex].iSize = handle->moov->trakVideo->mdia->minf->stbl->stsz->entrySize[index];
+ // If sample sync table doesn't exist mark all frames as intra / random access point
+ if (!sampleSyncTableExists)
+ {
+ aFrameInfoArray[actualIndex].iType = MP4TRUE;
+ }
+ actualIndex++; //point to next index in array
+ }
+ tmptime += handle->moov->trakVideo->mdia->minf->stbl->stts->sampleDelta[entry];
+ //Now insert size before incrementing index
+ if(index == videoSampleNumber-2)
+ break;
+ index++;
+ }
+ if(index==videoSampleNumber-2)
+ break;
+ sample += handle->moov->trakVideo->mdia->minf->stbl->stts->sampleCount[entry];
+ entry++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseGetVideoClipProperties(MP4Handle apihandle, TVideoClipProperties& aVideoClipProperties)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ if (!handle)
+ {
+ return MP4_ERROR;
+ }
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia->minf)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd)
+ return MP4_ERROR;
+
+ /* Assume that the video type is the same for all sample entries. Just get the video type from the first one */
+ if (handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0])
+ {
+ if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263)
+ return MP4_ERROR;
+
+ if (handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263->h263Level)
+ {
+ aVideoClipProperties.iH263Level = handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263->h263Level;
+ return MP4_OK;
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+ }
+ else
+ {
+ return MP4_ERROR;
+ }
+}
+
+extern EXPORT_C MP4Err MP4ParseGetUserDataAtom(MP4Handle apihandle,
+ mp4_u8& udtaLocation,
+ mp4_u32 udtaAtomType,
+ mp4_u8* buffer,
+ mp4_u32& bufferSize,
+ mp4_u32& atomIndex )
+ {
+ mp4_u32 size = 0;
+ mp4_u64 largesize = 0;
+ mp4_u32 type = 0;
+ mp4_i32 bytesread = 0;
+ mp4_i32 totalbytesread = 0;
+ MP4Err retError = MP4_OK;
+ userDataAtom* udta = NULL;
+ mp4_bool found = MP4FALSE;
+ mp4_u32 foundIndex = 0;
+
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle)
+ {
+ return MP4_ERROR;
+ }
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {// if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (!handle->moov)
+ return MP4_ERROR;
+
+ // Check where to read udta from.
+ switch ( udtaLocation )
+ {
+ case MP4_UDTA_NONE:
+ {
+ retError = MP4_UDTA_NOT_FOUND;
+ break;
+ }
+ case MP4_UDTA_MOOV:
+ {
+ if ( !handle->moov->udta )
+ {
+ retError = MP4_UDTA_NOT_FOUND;
+ break;
+ }
+ else
+ {
+ udta = handle->moov->udta;
+ }
+ break;
+ }
+ case MP4_UDTA_VIDEOTRAK:
+ {
+ if ( !handle->moov->trakVideo )
+ {
+ retError = MP4_UDTA_NOT_FOUND;
+ break;
+ }
+ if ( !handle->moov->trakVideo->udta )
+ {
+ retError = MP4_UDTA_NOT_FOUND;
+ }
+ else
+ {
+ udta = handle->moov->trakVideo->udta;
+ }
+ break;
+ }
+ case MP4_UDTA_AUDIOTRAK:
+ {
+ if (!handle->moov->trakAudio)
+ {
+ retError = MP4_UDTA_NOT_FOUND;
+ break;
+ }
+ if ( !handle->moov->trakAudio->udta )
+ {
+ retError = MP4_UDTA_NOT_FOUND;
+ }
+ else
+ {
+ udta = handle->moov->trakAudio->udta;
+ }
+ break;
+ }
+ default:
+ {
+ retError = MP4_INVALID_TYPE;
+ }
+ }
+
+ if ( retError == MP4_OK ) // valid UDTA found.
+ {
+ if ( !udta->atomhdr )
+ {
+ retError = MP4_UDTA_NOT_FOUND;
+ }
+ if ( !udta->atomcontentloc || (udta->atomcontentsize == 0) )
+ {
+ retError = MP4_UDTA_NOT_FOUND;
+ }
+
+ // seek to UDTA atom in memory structure or file.
+ if (handle->file) /* Input is in a file */
+ {
+ if (seekFileAbs(handle, udta->atomcontentloc) != 0)
+ return MP4_CANT_SEEK;
+ }
+ else
+ {
+ handle->absPosition = udta->atomcontentloc;
+ }
+
+ // search for wanted atom from UDTA and read it to buffer
+ while ( totalbytesread < (mp4_i32)udta->atomcontentsize )
+ {
+ if (peekData(handle, handle->buf, 16) < 0)
+ return MP4_ERROR;
+
+ size = u32endian(*((mp4_u32 *)handle->buf));
+ type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+ if ( type == udtaAtomType )
+ {
+ if ( atomIndex == foundIndex )
+ {
+ if ( size == 1 )
+ {
+ largesize = u64endian(*((mp4_u64*)(handle->buf+8)));
+ size = (mp4_u32)I64INT(largesize);
+ }
+ if ( size > bufferSize )
+ {
+ // Although the output buffer supplied by the caller is
+ // not large enough to store the sub user atom's content, keep
+ // parsing thru the whole user data to retrieve the highest index
+ // to be returned thru the atomIndex parameter
+ bufferSize = size;
+ retError = MP4_OUTPUT_BUFFER_TOO_SMALL;
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return MP4_ERROR;
+ }
+ else
+ {
+ bytesread = readData(handle, buffer, size);
+ if (bytesread < 0)
+ return MP4_ERROR;
+ bufferSize = bytesread;
+ }
+
+ totalbytesread += bytesread;
+ foundIndex += 1;
+ found = MP4TRUE;
+ }
+ else
+ {
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return MP4_ERROR;
+ totalbytesread += bytesread;
+ foundIndex += 1;
+ }
+ }
+ else
+ {
+ bytesread = readUnknown(handle);
+ if (bytesread < 0)
+ return MP4_ERROR;
+ totalbytesread += bytesread;
+ }
+ }
+ }
+
+ if ( ( atomIndex > foundIndex ) || !found )
+ {
+ retError = MP4_UDTA_NOT_FOUND;
+ }
+
+ // fill how many wanted type atom there is in asked UDTA.
+ if ( found )
+ {
+ atomIndex = foundIndex - 1;
+ }
+ else
+ {
+ atomIndex = 0;
+ }
+
+ // fill udtaLocation
+ udtaLocation = MP4_UDTA_NONE;
+
+ if ( handle->moov->udta )
+ {
+ udtaLocation |= MP4_UDTA_MOOV;
+ }
+ if ( handle->moov->trakVideo )
+ {
+ if ( handle->moov->trakVideo->udta )
+ {
+ udtaLocation |= MP4_UDTA_VIDEOTRAK;
+ }
+ }
+ if ( handle->moov->trakAudio )
+ {
+ if ( handle->moov->trakAudio->udta )
+ {
+ udtaLocation |= MP4_UDTA_AUDIOTRAK;
+ }
+ }
+
+ return retError;
+ }
+
+extern EXPORT_C MP4Err MP4ParseNextVideoFrameDependencies(MP4Handle apihandle, mp4_u8* aDependsOn, mp4_u8* aIsDependentOn, mp4_u8* aHasRedundancy)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+ mp4_u32 type = 0;
+
+ if (!handle)
+ {
+ return MP4_ERROR;
+ }
+ if(!aDependsOn || !aIsDependentOn || !aHasRedundancy)
+ {
+ return MP4_NO_OUTPUT_BUFFER;
+ }
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ return MP4_INVALID_INPUT_STREAM;
+ }
+
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ if (determineVideoType(handle, &type) < 0)
+ {
+ return MP4_ERROR;
+ }
+ if( !isAvcVideo(type) )
+ {
+ *aDependsOn = 0; // Unknown
+ *aIsDependentOn = 0; // Unknown
+ *aHasRedundancy = 0; // Unknown
+ return MP4_OK;
+ }
+
+ if (!handle->moov)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia->minf)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia->minf->stbl)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo->mdia->minf->stbl->sdtp)
+ {
+ *aDependsOn = 0; // Unknown
+ *aIsDependentOn = 0; // Unknown
+ *aHasRedundancy = 0; // Unknown
+ return MP4_OK;
+ }
+ if (!handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep)
+ {
+ return MP4_ERROR;
+ }
+
+ if (handle->videoSampleNum <= 0)
+ {
+ return MP4_ERROR;
+ }
+
+ if(handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sDependsOn > 2 ||
+ handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sIsDependentOn > 2 ||
+ handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sHasRedundancy > 2)
+ {
+ return MP4_ERROR;
+ }
+ *aDependsOn = handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sDependsOn;
+ *aIsDependentOn = handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sIsDependentOn;
+ *aHasRedundancy = handle->moov->trakVideo->mdia->minf->stbl->sdtp->dep[handle->videoSampleNum - 1].sHasRedundancy;
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseReadAudioFramesAsync(MP4Handle apihandle, M3GPMP4LibAsyncObserver* aObserver, mp4_u8 *buffer, mp4_u32* buffersize)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle->file)
+ {
+ // async operation is only supported for files.
+ return MP4_FILE_ERROR;
+ }
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+ return MP4_NOT_AVAILABLE;
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ handle->asyncObserver = aObserver;
+
+ /* Is audio available? */
+ if (!((handle->type & MP4_TYPE_MPEG4_AUDIO) ||
+ (handle->type & MP4_TYPE_AMR_NB) ||
+ (handle->type & MP4_TYPE_AMR_WB) ||
+ (handle->type & MP4_TYPE_QCELP_13K)))
+ return MP4_ERROR;
+
+ /* Are there samples left? */
+ if (handle->audioLast)
+ return MP4_NO_FRAME;
+
+ if (!handle->moov)
+ return MP4_ERROR;
+ if (!handle->moov->trakAudio)
+ return MP4_ERROR;
+
+ switch (fetchAudioSampleAsync(handle, handle->moov->trakAudio, buffer, buffersize))
+ {
+ case -1:
+ return MP4_ERROR;
+ case -2:
+ return MP4_BUFFER_TOO_SMALL;
+ case -4:
+ return MP4_INVALID_INPUT_STREAM;
+ case MP4_OUT_OF_MEMORY:
+ return MP4_OUT_OF_MEMORY;
+ default:
+ break;
+ }
+ return MP4_OK;
+}
+
+extern EXPORT_C MP4Err MP4ParseReadVideoFrameAsync(MP4Handle apihandle,
+ M3GPMP4LibAsyncObserver* aObserver,
+ mp4_u8* buffer,
+ mp4_u32* buffersize)
+{
+ MP4HandleImp handle = (MP4HandleImp)apihandle;
+
+ if (!handle->file)
+ {
+ // async operation is only supported for files.
+ return MP4_FILE_ERROR;
+ }
+
+ if (!handle->metaDataComplete)
+ {
+ switch (metaDataAvailable(handle))
+ {
+ case 0:
+
+ return MP4_NOT_AVAILABLE;
+
+ case 1:
+ handle->cafError = KErrNone;
+ if (readMetaData(handle) < 0)
+ {
+ // Reading of meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ freeMOOV(handle->moov);
+ handle->moov = NULL;
+
+ if ( handle->cafError != KErrNone )
+ {
+ // if CAF/DRM caused the error return it instead of generic errorcode.
+ return handle->cafError;
+ }
+ else
+ {
+ return MP4_INVALID_INPUT_STREAM;
+ }
+ }
+ handle->metaDataComplete = MP4TRUE;
+ break;
+
+ case -2:
+ // Reading of FTYP meta data failed, so free up any allocated memory
+ freeFTYP(handle->ftyp);
+ handle->ftyp = NULL;
+ return MP4_ERROR;
+
+ case -1:
+ default:
+ return MP4_ERROR;
+ }
+ }
+
+ /* Is video available? */
+ if (!((handle->type & MP4_TYPE_MPEG4_VIDEO) ||
+ (handle->type & MP4_TYPE_H263_PROFILE_0) ||
+ (handle->type & MP4_TYPE_H263_PROFILE_3) ||
+ containsAvcVideo( handle->type ) ))
+ return MP4_ERROR;
+
+ /* Are there samples left? */
+ if (handle->videoLast)
+ return MP4_NO_FRAME;
+
+ handle->asyncObserver = aObserver;
+
+ if (!handle->moov)
+ return MP4_ERROR;
+ if (!handle->moov->trakVideo)
+ return MP4_ERROR;
+
+ switch (fetchVideoFrameAsync(handle, handle->moov->trakVideo, buffer, buffersize ))
+ {
+ case -1:
+ return MP4_ERROR;
+ case -2:
+ return MP4_BUFFER_TOO_SMALL;
+ case -3:
+ return MP4_NOT_AVAILABLE;
+ case -4:
+ return MP4_INVALID_INPUT_STREAM;
+ case MP4_OUT_OF_MEMORY:
+ return MP4_OUT_OF_MEMORY;
+ default:
+ break;
+ }
+
+ return MP4_OK;
+}
+
+extern EXPORT_C void MP4CancelReadFrame(MP4Handle ahandle)
+ {
+ MP4HandleImp handle = (MP4HandleImp)ahandle;
+
+ if (handle->asyncReader)
+ {
+ handle->asyncReader->Cancel();
+ }
+ }
+
+// End of File