mmplugins/lib3gp/impl/src/mp4parse.cpp
changeset 0 40261b775718
child 11 d5f04de580b7
--- /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