mmplugins/lib3gp/impl/src/atom.cpp
changeset 0 40261b775718
child 23 545d349d14da
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/lib3gp/impl/src/atom.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,8900 @@
+// 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 "mp4buffer.h"
+#include "mp4endian.h"
+#include "mp4file.h"
+#include "mp4utils.h"
+
+// MACROS
+// Debug print macro
+#ifdef _DEBUG
+#include <e32svr.h>
+//#define PRINT(x) RDebug::Print x
+#define PRINT(x)
+#else
+#define PRINT(x)
+#endif
+
+mp4_i32 readBoxHeader(MP4HandleImp handle, mp4_i64* size, mp4_u32* type);
+ 
+/*
+ * Function:
+ *
+ *   mp4_i32 metaDataAvailable(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ *   This function determines whether meta data is available for reading
+ *   or not.
+ *
+ *   Meta data is available if the input is in a file.
+ *
+ *   When reading from a stream, meta data is considered available if
+ *   it is in the beginning of the stream and the entire Moov atom has
+ *   been received. FTYP atom is allowed before MOOV atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *
+ * Return value:
+ *
+ *   0                Meta data is not available because enough data has not
+ *                    been inserted into the library
+ *   1                Meta data is available
+ *   Negative value   Meta data is not available because of fatal error
+ *
+ */
+mp4_i32 metaDataAvailable(MP4HandleImp handle)
+{
+  mp4_u32 size;
+  mp4_u32 type;
+
+
+  /* Meta data is available if the input is in a file or if a complete file has been inputted as a stream*/
+
+  if (handle->file)
+    return 1;
+
+  /* When reading from a stream, meta data is considered available if
+     it is in the beginning of the stream and the entire MOOV atom has
+     been received. FTYP atom is allowed before MOOV atom. */
+
+  if (!handle->ftypRead)
+  {
+    if (peekData(handle, handle->buf, 8) < 0) /* 8 bytes are not available */
+        return 0;
+
+    size = u32endian(*((mp4_u32 *)handle->buf));
+    type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+    if (type == ATOMTYPE_FTYP)
+    {
+      if (getBufferedBytes(handle) - handle->position < size) /* FTYP is not available */
+        return 0;
+      if ((handle->ftyp = (fileTypeAtom *)mp4malloc(sizeof(fileTypeAtom))) == NULL)
+        return -100;
+      if (readFTYP(handle, handle->ftyp) < 0)
+        return -2;
+    }
+  }
+
+  // Now the ftyp is read. No need to chedk MOOV presence for full files in the memory.
+  if (handle->LastWriteDataCalled == MP4TRUE)
+      return 1;
+
+  if (handle->LastWriteDataCalled == MP4FALSE)
+  {//Whole stream is not fed to the internal memory yet. 
+   for (;;)
+    {
+      if (peekData(handle, handle->buf, 8) < 0)
+        return 0;
+
+      size = u32endian(*((mp4_u32 *)handle->buf));
+      type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+      if (type == ATOMTYPE_MOOV)
+        {
+        if (getBufferedBytes(handle) - handle->absPosition >= size) /* Entire Moov is available */
+            {
+            return 1;        
+            }
+        else
+            {
+            return 0;
+            }
+        }
+
+      if ((mp4_i32)size <= 0)
+        return -1;
+
+      handle->absPosition+=size;
+    }
+  }
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readFTYP(MP4HandleImp handle,
+ *                    fileTypeAtom *ftyp)
+ *
+ * Description:
+ *
+ *   This function parses one FTYP atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   ftyp               FTYP pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readFTYP(MP4HandleImp handle, fileTypeAtom *ftyp)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+  mp4_u32 n = 0;
+  mp4_i32 compatiblebrandsize = 0;
+
+
+  if ((ftyp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, ftyp->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (ftyp->atomhdr->type != ATOMTYPE_FTYP)
+    return -1;
+
+  if (ftyp->atomhdr->size < 16) // 8(header)+8bytes needed for major and minor brand
+    return -1;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  ftyp->majorBrand = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  ftyp->minorVersion = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  if (ftyp->atomhdr->size == (mp4_u32)totalbytesread)
+    return totalbytesread;
+
+  compatiblebrandsize = (mp4_i32)ftyp->atomhdr->size - totalbytesread;
+  if ( compatiblebrandsize < 4 )   // at this point we must have at least 1 compatible brand
+    return -1;
+  if ( compatiblebrandsize > 20*4) // maximum of 20 compatible brands 4byte entries
+    return -1;
+  if ( compatiblebrandsize % 4 ) // must be able to divide by 4
+    return -1;
+
+  ftyp->compatibleBrands = (mp4_u32 *)mp4malloc( compatiblebrandsize );
+  if (ftyp->compatibleBrands == NULL)
+    return -1;
+
+  while ((mp4_u32)totalbytesread < ftyp->atomhdr->size)
+  {
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+
+    ftyp->compatibleBrands[n] = u32endian(*((mp4_u32 *)handle->buf));
+
+    n++;
+    totalbytesread += bytesread;
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readMetaData(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ *   This function reads the meta data from the file/stream and stores
+ *   the information in the atom structures available via handle.
+ *
+ * Parameters:
+ *
+ *   handle  MP4 library handle
+ *
+ * Return value:
+ *
+ *   Negative value   Error
+ *   >= 0             Success. Value tells the number of bytes read.
+ *
+ */
+mp4_i32 readMetaData(MP4HandleImp handle)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if (handle->file)
+  {
+    mp4_u64 size;
+    mp4_u32 type;
+
+
+    if (seekFileAbs(handle, 0) < 0)
+      return -1;
+
+    /* Seek to the start of FTYP atom */
+
+    for (;;)
+    {
+      if (readBoxHeader(handle, &size, &type) <0)
+        return -1;
+
+      if (type == ATOMTYPE_FTYP)
+      {
+        /* Read FTYP */
+
+        if ((handle->ftyp = (fileTypeAtom *)mp4malloc(sizeof(fileTypeAtom))) == NULL)
+          return -100;
+        bytesread = readFTYP(handle, handle->ftyp);
+        if (bytesread < 0)
+          return -3;
+        totalbytesread += bytesread;
+
+        break;
+      }
+
+      if (size <= 0)
+        return -1;
+
+      if (seekFile(handle, size) != 0)
+        return -1;
+    }
+
+    if (seekFileAbs(handle, 0) < 0)
+      return -1;
+
+    /* Seek to the start of MOOV atom */
+    for (;;)
+    {
+      if (readBoxHeader(handle, &size, &type) <0)
+        return -1;
+
+      if (type == ATOMTYPE_MOOV)
+        break;
+
+      if (size <= 0)
+        return -1;
+
+      if (seekFile(handle, size) != 0)
+        return -1;
+    }
+  }
+
+  // If all data of a file is in the memory and the file does not have MOOV box right after FTYP, 
+  // then we need to seek for the location of the MOOV first
+
+  if (handle->LastWriteDataCalled == MP4TRUE)
+  { 
+    mp4_u32 size;
+    mp4_u32 type;
+    // Seek until the beginning of MOOV box.
+    for(;;)
+    {
+        if (peekData(handle, handle->buf, 8) < 0)
+            return -1;
+
+        size = u32endian(*((mp4_u32 *)handle->buf));
+        type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+    
+        if (type == ATOMTYPE_MOOV)
+          break;
+
+        if ((mp4_i32)size <= 0)
+          return -1;
+
+        if (discardData(handle, size) < 0)
+          return -1;
+    }
+  }
+
+  if ((handle->moov = (movieAtom *)mp4malloc(sizeof(movieAtom))) == NULL)
+    return -100;
+
+  bytesread = readMoov(handle, handle->moov);
+  if (bytesread < 0)
+    return -3;
+  totalbytesread += bytesread;
+
+  if (handle->moov->trakAudio)
+  {
+    mp4_u32 audiotype;
+	mp4_i32 errorAudio = 0;
+
+	errorAudio = determineAudioType(handle, &audiotype);
+    if ( errorAudio == 0 )
+    {
+	   	handle->type |= audiotype;    	
+    
+	    /* Move to the beginning of the 1st audio frame */
+	    switch (advanceAudioSample(handle, handle->moov->trakAudio))
+	    {
+	    case -1:
+	      return -1;
+	    case -2:
+	      handle->audioLast = MP4TRUE;
+	      break;
+	    default:
+	      break;
+	    }
+	}
+	else if (errorAudio == -2)
+	{
+		handle->type |= audiotype;	
+	}
+	else
+	{
+		return -1;
+	}
+  }
+
+  if (handle->moov->trakVideo)
+  {
+    mp4_u32 videotype;
+    mp4_i32 errorVideo = 0;
+
+	errorVideo = determineVideoType(handle, &videotype);
+    if ( errorVideo == 0 )
+    {
+	   	handle->type |= videotype;    	
+    
+    	/* Move to the beginning of the 1st video frame */
+	    switch (advanceVideoFrame(handle, handle->moov->trakVideo))
+	    {
+	    case -1:
+	      return -1;
+	    case -2:
+	       handle->videoLast = MP4TRUE;
+	      break;
+	    default:
+	      break;
+	    }
+	}
+	else if (errorVideo == -2)
+	{
+	   	handle->type |= videotype;	
+	}
+	else
+	{
+		return -1;
+	}
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readMoov(MP4HandleImp handle,
+ *                    movieAtom *moov)
+ *
+ * Description:
+ *
+ *   This function parses one MOOV atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   moov               MOOV pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMoov(MP4HandleImp handle, movieAtom *moov)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((moov->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, moov->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (moov->atomhdr->type != ATOMTYPE_MOOV)
+    return -1;
+
+  while ((mp4_u32)totalbytesread < handle->moov->atomhdr->size)
+  {
+    mp4_u32 type;
+
+
+    if (peekData(handle, handle->buf, 8) < 0)
+      return -1;
+
+    type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+    switch (type)
+    {
+    case ATOMTYPE_MVHD:
+
+      if (moov->mvhd) /* MVHD has already been read, more than one is not allowed */
+        return -1;
+
+      if ((moov->mvhd = (movieHeaderAtom *)mp4malloc(sizeof(movieHeaderAtom))) == NULL)
+        return -100;
+
+      bytesread = readMVHD(handle, moov->mvhd);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_IODS:
+
+      if (moov->iods) /* IODS has already been read, more than one is not allowed */
+        return -1;
+
+      if ((moov->iods = (objectDescriptorAtom *)mp4malloc(sizeof(objectDescriptorAtom))) == NULL)
+        return -100;
+
+      bytesread = readIODS(handle, moov->iods);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_TRAK:
+
+      {
+        trackAtom *ta;
+
+        if ((ta = (trackAtom *)mp4malloc(sizeof(trackAtom))) == NULL)
+          return -100;
+
+        bytesread = readTRAK(handle, ta);
+        if (bytesread < 0)
+        {
+          if (freeTRAK(ta) < 0)
+            return -1;
+          return -1;
+        }
+        totalbytesread += bytesread;
+
+        if (!ta->mdia)
+        {
+          if (freeTRAK(ta) < 0)
+            return -1;
+          return -1;
+        }
+        if (!ta->mdia->hdlr)
+        {
+          if (freeTRAK(ta) < 0)
+            return -1;
+          return -1;
+        }
+
+        if (ta->mdia->hdlr->handlerType != HANDLERTYPE_VIDE &&
+            ta->mdia->hdlr->handlerType != HANDLERTYPE_SOUN) /* Track is neither video nor audio */
+        {
+          /* Do nothing with the unknown track */
+          if (freeTRAK(ta) < 0)
+            return -1;
+          break;
+        }
+
+        if (ta->mdia->hdlr->handlerType == HANDLERTYPE_VIDE)
+        {
+	        if (moov->trakVideo) /* Video Track already read */
+	        {
+	          if (freeTRAK(ta) < 0)
+	            return -1;
+	        }
+	        else
+	        {
+	          moov->trakVideo = ta;
+	        }
+        }
+		else if (ta->mdia->hdlr->handlerType == HANDLERTYPE_SOUN)
+        {
+	        if (moov->trakAudio) /* Audio Track already read */
+	        {
+	          if (freeTRAK(ta) < 0)
+	            return -1;
+	        }
+	        else
+	        {
+	          moov->trakAudio = ta;
+	        }
+        }
+        else
+        {
+        }
+        break;
+      }
+
+    case ATOMTYPE_UDTA:
+
+      {
+      if (moov->udta) /* UDTA has already been read */
+          {
+          bytesread = readUnknown(handle);
+          if (bytesread < 0)
+            return -1;
+          totalbytesread += bytesread;
+          break;
+          }
+
+
+      if ((moov->udta = (userDataAtom *)mp4malloc(sizeof(userDataAtom))) == NULL)
+        return -100;
+
+      bytesread = readUDTA(handle, moov->udta);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+      }
+
+    default:
+
+      bytesread = readUnknown(handle);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+    }
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readAtomheader(MP4HandleImp handle,
+ *                          atomHeader *ah)
+ *
+ * Description:
+ *
+ *   This function reads an atom header and stores the information
+ *   in ah.
+ *
+ * Parameters:
+ *
+ *   handle           MP4 library handle
+ *   ah               atomHeader structure that is used to store the
+ *                    information
+ *
+ * Return value:
+ *
+ *   Negative value   Error
+ *   >= 0             Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readAtomHeader(MP4HandleImp handle, atomHeader *ah)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+  //PRINT((_L("readAtomHeader")));
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  ah->size = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  ah->type = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  if (ah->size == 1)
+  {
+    bytesread = readData(handle, handle->buf, 8);
+    if (bytesread < 0)
+      return -1;
+    ah->largeSize = u64endian(*((mp4_u64 *)handle->buf));
+    totalbytesread += bytesread;
+  }
+
+  if (ah->type == ATOMTYPE_UUID)
+  {
+    bytesread = readData(handle, handle->buf, 16);
+    if (bytesread < 0)
+      return -1;
+    mp4memcpy(ah->extendedType, handle->buf, 16);
+    totalbytesread += bytesread;
+  }
+
+  //PRINT((_L("   size %u, size %Lu, type %c%c%c%c"), ah->size, ah->largeSize,((unsigned char *)(&ah->type))[3], ((unsigned char *)(&ah->type))[2], ((unsigned char *)(&ah->type))[1], ((unsigned char *)(&ah->type))[0]));
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readFullAtomHeader(MP4HandleImp handle,
+ *                              atomHeader *ah)
+ *
+ * Description:
+ *
+ *   This function reads a full atom header and stores the information
+ *   in ah.
+ *
+ * Parameters:
+ *
+ *   handle           MP4 library handle
+ *   ah               atomHeader structure that is used to store the
+ *                    information
+ *
+ * Return value:
+ *
+ *   Negative value   Error
+ *   >= 0             Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readFullAtomHeader(MP4HandleImp handle, atomHeader *ah)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+  //PRINT((_L("readFullAtomHeader")));
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  ah->size = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  ah->type = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  ah->version = *(handle->buf);
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 3);
+  if (bytesread < 0)
+    return -1;
+  mp4memcpy(ah->flags, handle->buf, 3);
+  totalbytesread += bytesread;
+
+  //PRINT((_L("   size %u, size %Lu, type %c%c%c%c"), ah->size, ah->largeSize,((unsigned char *)(&ah->type))[3], ((unsigned char *)(&ah->type))[2], ((unsigned char *)(&ah->type))[1], ((unsigned char *)(&ah->type))[0]));
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readMVHD(MP4HandleImp handle,
+ *                    movieHeaderAtom *mvhd)
+ *
+ * Description:
+ *
+ *   This function parses one MVHD atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   mvhd               MVHD pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMVHD(MP4HandleImp handle, movieHeaderAtom *mvhd)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((mvhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, mvhd->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (mvhd->atomhdr->type != ATOMTYPE_MVHD)
+    return -1;
+
+  if (mvhd->atomhdr->version == 1) /* 64 bit */
+  {
+    bytesread = readData(handle, handle->buf, 8);
+    if (bytesread < 0)
+      return -1;
+    mvhd->creationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 8);
+    if (bytesread < 0)
+      return -1;
+    mvhd->modificationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    mvhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 8);
+    if (bytesread < 0)
+      return -1;
+    mvhd->duration64 = u64endian(*((mp4_u64 *)handle->buf));
+    totalbytesread += bytesread;
+  }
+  else /* 32 bit */
+  {
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    mvhd->creationTime = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    mvhd->modificationTime = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    mvhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    mvhd->duration = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+  }
+
+  bytesread = discardData(handle, 76);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  mvhd->nextTrackID = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readIODS(MP4HandleImp handle,
+ *                    objectDescriptorAtom *iods)
+ *
+ * Description:
+ *
+ *   This function parses one IODS atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   iods               IODS pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readIODS(MP4HandleImp handle, objectDescriptorAtom *iods)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((iods->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, iods->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (iods->atomhdr->type != ATOMTYPE_IODS)
+    return -1;
+
+  bytesread = discardData(handle, iods->atomhdr->size - totalbytesread);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readTRAK(MP4HandleImp handle,
+ *                    trackAtom *trak)
+ *
+ * Description:
+ *
+ *   This function parses one TRAK atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   trak               TRAK pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readTRAK(MP4HandleImp handle, trackAtom *trak)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((trak->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, trak->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (trak->atomhdr->type != ATOMTYPE_TRAK)
+    return -1;
+
+
+  while ((mp4_u32)totalbytesread < trak->atomhdr->size)
+  {
+    mp4_u32 type;
+
+
+    if (peekData(handle, handle->buf, 8) < 0)
+      return -1;
+
+    type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+    switch (type)
+    {
+    case ATOMTYPE_TKHD:
+
+      if (trak->tkhd) /* MVHD has already been read, more than one is not allowed */
+        return -1;
+
+      if ((trak->tkhd = (trackHeaderAtom *)mp4malloc(sizeof(trackHeaderAtom))) == NULL)
+        return -100;
+
+      bytesread = readTKHD(handle, trak->tkhd);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_TREF:
+
+      if (trak->tref) /* TREF has already been read, more than one is not allowed */
+        return -1;
+
+      if ((trak->tref = (trackReferenceAtom *)mp4malloc(sizeof(trackReferenceAtom))) == NULL)
+        return -100;
+
+      bytesread = readTREF(handle, trak->tref);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_EDTS:
+
+      if (trak->edts) /* EDTS has already been read, more than one is not allowed */
+        return -1;
+
+      if ((trak->edts = (editListContainerAtom *)mp4malloc(sizeof(editListContainerAtom))) == NULL)
+        return -100;
+
+      bytesread = readEDTS(handle, trak->edts);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_MDIA:
+
+      if (trak->mdia) /* MDIA has already been read, more than one is not allowed */
+        return -1;
+
+      if ((trak->mdia = (mediaAtom *)mp4malloc(sizeof(mediaAtom))) == NULL)
+        return -100;
+
+      bytesread = readMDIA(handle, trak->mdia);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_UDTA:
+      {
+      if (trak->udta) /* UDTA has already been read */
+          {
+          bytesread = readUnknown(handle);
+          if (bytesread < 0)
+            return -1;
+          totalbytesread += bytesread;
+          break;
+          }
+
+      if ((trak->udta = (userDataAtom *)mp4malloc(sizeof(userDataAtom))) == NULL)
+        return -100;
+
+      bytesread = readUDTA(handle, trak->udta);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+      }
+
+    default:
+
+      bytesread = readUnknown(handle);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+    }
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readUnknown(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ *   This function reads one atom of unknown type. Atom contents are
+ *   discarded.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readUnknown(MP4HandleImp handle)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+  mp4_u32 size;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  size = u32endian(*((mp4_u32 *)handle->buf));
+  if ( size < 4 )
+  {
+  	return -1;
+  }
+
+  if ( handle->file )
+  {
+  	if ( seekFile(handle, size - totalbytesread) < 0 )
+  	{
+  	   return -1;	
+  	}
+  	else
+  	{
+  	   return size;	
+  	}
+  }
+  else
+  {
+  	bytesread = discardData(handle, size - totalbytesread);
+	  if (bytesread < 0)
+    	return -1;
+  	totalbytesread += bytesread;
+  }
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readTKHD(MP4HandleImp handle,
+ *                    trackHeaderAtom *tkhd)
+ *
+ * Description:
+ *
+ *   This function parses one TKHD atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   tkhd               TKHD pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readTKHD(MP4HandleImp handle, trackHeaderAtom *tkhd)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((tkhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, tkhd->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (tkhd->atomhdr->type != ATOMTYPE_TKHD)
+    return -1;
+
+  if (tkhd->atomhdr->version == 1) /* 64 bit */
+  {
+    bytesread = readData(handle, handle->buf, 8);
+    if (bytesread < 0)
+      return -1;
+    tkhd->creationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 8);
+    if (bytesread < 0)
+      return -1;
+    tkhd->modificationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    tkhd->trackID = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    tkhd->reserved = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 8);
+    if (bytesread < 0)
+      return -1;
+    tkhd->duration64 = u64endian(*((mp4_u64 *)handle->buf));
+    totalbytesread += bytesread;
+  }
+  else /* 32 bit */
+  {
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    tkhd->creationTime = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    tkhd->modificationTime = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    tkhd->trackID = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    tkhd->reserved = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    tkhd->duration = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+  }
+
+  bytesread = discardData(handle, 52);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  tkhd->width = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  tkhd->height = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readTREF(MP4HandleImp handle,
+ *                    trackReferenceAtom *tref)
+ *
+ * Description:
+ *
+ *   This function parses one TREF atom and discards the contents.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   tref               TREF pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readTREF(MP4HandleImp handle, trackReferenceAtom *tref)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((tref->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, tref->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (tref->atomhdr->type != ATOMTYPE_TREF)
+    return -1;
+
+  bytesread = discardData(handle, tref->atomhdr->size - totalbytesread);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readEDTS(MP4HandleImp handle,
+ *                    editListContainerAtom *edts)
+ *
+ * Description:
+ *
+ *   This function parses one EDTS atom and discards the contents.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   edts               EDTS pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readEDTS(MP4HandleImp handle, editListContainerAtom *edts)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((edts->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, edts->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (edts->atomhdr->type != ATOMTYPE_EDTS)
+    return -1;
+
+  bytesread = discardData(handle, edts->atomhdr->size - totalbytesread);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readMDIA(MP4HandleImp handle,
+ *                    mediaAtom *mdia)
+ *
+ * Description:
+ *
+ *   This function parses one MDIA atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   mdia               MDIA pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMDIA(MP4HandleImp handle, mediaAtom *mdia)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((mdia->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, mdia->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (mdia->atomhdr->type != ATOMTYPE_MDIA)
+    return -1;
+
+
+  while ((mp4_u32)totalbytesread < mdia->atomhdr->size)
+  {
+    mp4_u32 type;
+
+
+    if (peekData(handle, handle->buf, 8) < 0)
+      return -1;
+
+    type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+    switch (type)
+    {
+    case ATOMTYPE_MDHD:
+
+      if (mdia->mdhd) /* MDHD has already been read, more than one is not allowed */
+        return -1;
+
+      if ((mdia->mdhd = (mediaHeaderAtom *)mp4malloc(sizeof(mediaHeaderAtom))) == NULL)
+        return -100;
+
+      bytesread = readMDHD(handle, mdia->mdhd);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_HDLR:
+
+      if (mdia->hdlr) /* HDLR has already been read, more than one is not allowed */
+        return -1;
+
+      if ((mdia->hdlr = (handlerAtom *)mp4malloc(sizeof(handlerAtom))) == NULL)
+        return -100;
+
+      bytesread = readHDLR(handle, mdia->hdlr);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_MINF:
+
+      if (mdia->minf) /* MINF has already been read, more than one is not allowed */
+        return -1;
+
+      if ((mdia->minf = (mediaInformationAtom *)mp4malloc(sizeof(mediaInformationAtom))) == NULL)
+        return -100;
+
+      bytesread = readMINF(handle, mdia->minf);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    default:
+
+      bytesread = readUnknown(handle);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+    }
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readMDHD(MP4HandleImp handle,
+ *                    mediaHeaderAtom *mdhd)
+ *
+ * Description:
+ *
+ *   This function parses one MDHD atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   mdhd               MDHD pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMDHD(MP4HandleImp handle, mediaHeaderAtom *mdhd)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((mdhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, mdhd->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (mdhd->atomhdr->type != ATOMTYPE_MDHD)
+    return -1;
+
+
+  if (mdhd->atomhdr->version == 1) /* 64 bit */
+  {
+    bytesread = readData(handle, handle->buf, 8);
+    if (bytesread < 0)
+      return -1;
+    mdhd->creationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 8);
+    if (bytesread < 0)
+      return -1;
+    mdhd->modificationTime64 = u64endian(*((mp4_u64 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    mdhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 8);
+    if (bytesread < 0)
+      return -1;
+    mdhd->duration64 = u64endian(*((mp4_u64 *)handle->buf));
+    totalbytesread += bytesread;
+  }
+  else /* 32 bit */
+  {
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    mdhd->creationTime = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    mdhd->modificationTime = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    mdhd->timeScale = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+
+    bytesread = readData(handle, handle->buf, 4);
+    if (bytesread < 0)
+      return -1;
+    mdhd->duration = u32endian(*((mp4_u32 *)handle->buf));
+    totalbytesread += bytesread;
+  }
+
+  bytesread = discardData(handle, 4);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readHDLR(MP4HandleImp handle,
+ *                    handlerAtom *hdlr)
+ *
+ * Description:
+ *
+ *   This function parses one HDLR atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   hdlr               HDLR pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readHDLR(MP4HandleImp handle, handlerAtom *hdlr)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((hdlr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, hdlr->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (hdlr->atomhdr->type != ATOMTYPE_HDLR)
+    return -1;
+
+
+  bytesread = discardData(handle, 4);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  hdlr->handlerType = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, hdlr->atomhdr->size - totalbytesread);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readMINF(MP4HandleImp handle,
+ *                    mediaInformationAtom *minf)
+ *
+ * Description:
+ *
+ *   This function parses one MINF atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   minf               MINF pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMINF(MP4HandleImp handle, mediaInformationAtom *minf)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((minf->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, minf->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (minf->atomhdr->type != ATOMTYPE_MINF)
+    return -1;
+
+
+  while ((mp4_u32)totalbytesread < minf->atomhdr->size)
+  {
+    mp4_u32 type;
+
+
+    if (peekData(handle, handle->buf, 8) < 0)
+      return -1;
+
+    type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+    switch (type)
+    {
+    case ATOMTYPE_VMHD:
+
+      if (minf->vmhd || minf->smhd) /* VMHD or SMHD has already been read, more than one is not allowed */
+        return -1;
+
+      if ((minf->vmhd = (videoMediaHeaderAtom *)mp4malloc(sizeof(videoMediaHeaderAtom))) == NULL)
+        return -100;
+
+      bytesread = readVMHD(handle, minf->vmhd);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_SMHD:
+
+      if (minf->smhd || minf->vmhd) /* SMHD or VMHD has already been read, more than one is not allowed */
+        return -1;
+
+      if ((minf->smhd = (soundMediaHeaderAtom *)mp4malloc(sizeof(soundMediaHeaderAtom))) == NULL)
+        return -100;
+
+      bytesread = readSMHD(handle, minf->smhd);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_DINF:
+
+      if (minf->dinf) /* DINF has already been read, more than one is not allowed */
+        return -1;
+
+      if ((minf->dinf = (dataInformationAtom *)mp4malloc(sizeof(dataInformationAtom))) == NULL)
+        return -100;
+
+      bytesread = readDINF(handle, minf->dinf);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_STBL:
+
+      if (minf->stbl) /* STBL has already been read, more than one is not allowed */
+        return -1;
+
+      if ((minf->stbl = (sampleTableAtom *)mp4malloc(sizeof(sampleTableAtom))) == NULL)
+        return -100;
+
+      bytesread = readSTBL(handle, minf->stbl);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    default:
+
+      bytesread = readUnknown(handle);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+    }
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readVMHD(MP4HandleImp handle,
+ *                    videoMediaHeaderAtom *vmhd)
+ *
+ * Description:
+ *
+ *   This function parses one VMHD atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   vmhd               VMHD pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readVMHD(MP4HandleImp handle, videoMediaHeaderAtom *vmhd)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((vmhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, vmhd->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (vmhd->atomhdr->type != ATOMTYPE_VMHD)
+    return -1;
+
+
+  bytesread = discardData(handle, vmhd->atomhdr->size - totalbytesread);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSMHD(MP4HandleImp handle,
+ *                    soundMediaHeaderAtom *smhd)
+ *
+ * Description:
+ *
+ *   This function parses one SMHD atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   smhd               SMHD pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSMHD(MP4HandleImp handle, soundMediaHeaderAtom *smhd)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((smhd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, smhd->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (smhd->atomhdr->type != ATOMTYPE_SMHD)
+    return -1;
+
+
+  bytesread = discardData(handle, smhd->atomhdr->size - totalbytesread);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readDINF(MP4HandleImp handle,
+ *                    dataInformationAtom *dinf)
+ *
+ * Description:
+ *
+ *   This function parses one DINF atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   dinf               DINF pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readDINF(MP4HandleImp handle, dataInformationAtom *dinf)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((dinf->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, dinf->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (dinf->atomhdr->type != ATOMTYPE_DINF)
+    return -1;
+
+
+  while ((mp4_u32)totalbytesread < dinf->atomhdr->size)
+  {
+    mp4_u32 type;
+
+
+    if (peekData(handle, handle->buf, 8) < 0)
+      return -1;
+
+    type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+    switch (type)
+    {
+    case ATOMTYPE_DREF:
+
+      if (dinf->dref) /* DINF has already been read, more than one is not allowed */
+        return -1;
+
+      if ((dinf->dref = (dataReferenceAtom *)mp4malloc(sizeof(dataReferenceAtom))) == NULL)
+        return -100;
+
+      bytesread = readDREF(handle, dinf->dref);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    default:
+
+      return -1;
+    }
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readDREF(MP4HandleImp handle,
+ *                    dataReferenceAtom *dref)
+ *
+ * Description:
+ *
+ *   This function parses one DREF atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   dref               DREF pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readDREF(MP4HandleImp handle, dataReferenceAtom *dref)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((dref->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, dref->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (dref->atomhdr->type != ATOMTYPE_DREF)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  dref->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  if (dref->entryCount != 1)
+    return -1;
+
+  while ((mp4_u32)totalbytesread < dref->atomhdr->size)
+  {
+    bytesread = readUnknown(handle);
+    if (bytesread < 0)
+      return -1;
+    totalbytesread += bytesread;
+  }
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readURL(MP4HandleImp handle,
+ *                   dataEntryURLAtom *url)
+ *
+ * Description:
+ *
+ *   This function parses one URL atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   url                URL pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readURL(MP4HandleImp handle, dataEntryURLAtom *url)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((url->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, url->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (url->atomhdr->type != ATOMTYPE_URL)
+    return -1;
+
+
+  if (!(url->atomhdr->flags[0] == 0x00 &&
+        url->atomhdr->flags[1] == 0x00 &&
+        url->atomhdr->flags[2] == 0x01))
+    return -1;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readURN(MP4HandleImp handle,
+ *                   dataEntryURNAtom *urn)
+ *
+ * Description:
+ *
+ *   This function parses one URN atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   urn                URN pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readURN(MP4HandleImp handle, dataEntryURNAtom *urn)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((urn->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, urn->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (urn->atomhdr->type != ATOMTYPE_URN)
+    return -1;
+
+
+  if (!(urn->atomhdr->flags[0] == 0x00 &&
+        urn->atomhdr->flags[1] == 0x00 &&
+        urn->atomhdr->flags[2] == 0x01))
+    return -1;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSTBL(MP4HandleImp handle,
+ *                    sampleTableAtom *stbl)
+ *
+ * Description:
+ *
+ *   This function parses one STBL atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   stbl               STBL pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTBL(MP4HandleImp handle, sampleTableAtom *stbl)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((stbl->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, stbl->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (stbl->atomhdr->type != ATOMTYPE_STBL)
+    return -1;
+
+
+  while ((mp4_u32)totalbytesread < stbl->atomhdr->size)
+  {
+    mp4_u32 type;
+
+
+    if (peekData(handle, handle->buf, 8) < 0)
+      return -1;
+
+    type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+    switch (type)
+    {
+    case ATOMTYPE_STTS:
+
+      if (stbl->stts) /* STTS has already been read, more than one is not allowed */
+        return -1;
+
+      if ((stbl->stts = (timeToSampleAtom *)mp4malloc(sizeof(timeToSampleAtom))) == NULL)
+        return -100;
+
+      bytesread = readSTTS(handle, stbl->stts);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_CTTS:
+
+      if (stbl->ctts) /* CTTS has already been read, more than one is not allowed */
+        return -1;
+
+      if ((stbl->ctts = (compositionTimeToSampleAtom *)mp4malloc(sizeof(compositionTimeToSampleAtom))) == NULL)
+        return -100;
+
+      bytesread = readCTTS(handle, stbl->ctts);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_STSS:
+
+      if (stbl->stss) /* STSS has already been read, more than one is not allowed */
+        return -1;
+
+      if ((stbl->stss = (syncSampleAtom *)mp4malloc(sizeof(syncSampleAtom))) == NULL)
+        return -100;
+
+      bytesread = readSTSS(handle, stbl->stss);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_STSD:
+
+      if (stbl->stsd) /* STSD has already been read, more than one is not allowed */
+        return -1;
+
+      if ((stbl->stsd = (sampleDescriptionAtom *)mp4malloc(sizeof(sampleDescriptionAtom))) == NULL)
+        return -100;
+
+      bytesread = readSTSD(handle, stbl->stsd);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_STSZ:
+
+      if (stbl->stsz) /* STSZ or STZ2 has already been read, more than one is not allowed */
+        return -1;
+
+      if ((stbl->stsz = (sampleSizeAtom *)mp4malloc(sizeof(sampleSizeAtom))) == NULL)
+        return -100;
+
+      bytesread = readSTSZ(handle, stbl->stsz);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_STZ2:
+
+      if (stbl->stsz) /* STSZ or STZ2 has already been read, more than one is not allowed */
+        return -1;
+
+      if ((stbl->stsz = (sampleSizeAtom *)mp4malloc(sizeof(sampleSizeAtom))) == NULL)
+        return -100;
+
+      bytesread = readSTZ2(handle, stbl->stsz);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_STSC:
+
+      if (stbl->stsc) /* STSC has already been read, more than one is not allowed */
+        return -1;
+
+      if ((stbl->stsc = (sampleToChunkAtom *)mp4malloc(sizeof(sampleToChunkAtom))) == NULL)
+        return -100;
+
+      bytesread = readSTSC(handle, stbl->stsc);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_STCO:
+
+      if (stbl->stco) /* STCO or CO64 has already been read, more than one is not allowed */
+        return -1;
+
+      if ((stbl->stco = (chunkOffsetAtom *)mp4malloc(sizeof(chunkOffsetAtom))) == NULL)
+        return -100;
+      
+      stbl->is32BitOffsets = ETrue;
+      bytesread = readSTCO(handle, stbl->stco);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_CO64:
+
+      if (stbl->stco64) /* STCO or CO64 has already been read, more than one is not allowed */
+        return -1;
+
+      if ((stbl->stco64 = (chunkOffset64Atom *)mp4malloc(sizeof(chunkOffset64Atom))) == NULL)
+        return -100;
+      
+      stbl->is32BitOffsets = EFalse;
+      bytesread = readCO64(handle, stbl->stco64);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    case ATOMTYPE_SDTP:
+      if (stbl->sdtp) /* SDTP has already been read, more than one is not allowed */
+        return -1;
+      
+      if ((stbl->sdtp = (sampleDependencyAtom *)mp4malloc(sizeof(sampleDependencyAtom))) == NULL)
+        return -100;
+
+      if (!stbl->stsz)
+    	  {
+    	  return -1;
+    	  }
+
+	  // sample_count of SDTP is taken from the sample_count in the Sample Size Box ('stsz') or
+	  // Compact Sample Size Box (‘stz2’). 
+	  bytesread = readSDTP(handle, stbl->sdtp, stbl->stsz->sampleCount);
+    	  
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+      break;
+
+    default: /* Other atoms are not needed */
+
+      bytesread = readUnknown(handle);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+    }
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSTTS(MP4HandleImp handle,
+ *                    timeToSampleAtom *stts)
+ *
+ * Description:
+ *
+ *   This function parses one STTS atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   stts               STTS pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTTS(MP4HandleImp handle, timeToSampleAtom *stts)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+  mp4_u32 i;
+
+
+  if ((stts->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, stts->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (stts->atomhdr->type != ATOMTYPE_STTS)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  stts->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+  
+  if ( stts->entryCount )
+  {
+	  stts->sampleCount = (mp4_u32 *)mp4malloc(stts->entryCount * sizeof(mp4_u32));
+	  if (stts->sampleCount == NULL)
+	    return -1;
+	  stts->sampleDelta = (mp4_i32 *)mp4malloc(stts->entryCount * sizeof(mp4_i32));
+	  if (stts->sampleDelta == NULL)
+	    return -1;
+
+	  for (i = 0; i < stts->entryCount; i++)
+	  {
+	    bytesread = readData(handle, handle->buf, 8);
+	    if (bytesread < 0)
+	      return -1;
+
+	    stts->sampleCount[i] = u32endian(*((mp4_u32 *)handle->buf));
+	    stts->sampleDelta[i] = i32endian(*((mp4_i32 *)(handle->buf+4)));
+
+	    totalbytesread += bytesread;
+	  }
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readCTTS(MP4HandleImp handle,
+ *                    compositionTimeToSampleAtom *ctts)
+ *
+ * Description:
+ *
+ *   This function parses one CTTS atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   ctts               CTTS pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readCTTS(MP4HandleImp handle, compositionTimeToSampleAtom *ctts)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+  mp4_u32 i;
+
+
+  if ((ctts->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, ctts->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (ctts->atomhdr->type != ATOMTYPE_CTTS)
+    return -1;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  ctts->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  if ( ctts->entryCount )
+  {
+	  ctts->sampleCount = (mp4_u32 *)mp4malloc(ctts->entryCount * sizeof(mp4_u32));
+	  if (ctts->sampleCount == NULL)
+	    return -1;
+	  ctts->sampleOffset = (mp4_u32 *)mp4malloc(ctts->entryCount * sizeof(mp4_u32));
+	  if (ctts->sampleOffset == NULL)
+	    return -1;
+
+	  for (i = 0; i < ctts->entryCount; i++)
+	  {
+	    bytesread = readData(handle, handle->buf, 8);
+	    if (bytesread < 0)
+	      return -1;
+
+	    ctts->sampleCount[i] = u32endian(*((mp4_u32 *)handle->buf));
+	    ctts->sampleOffset[i] = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+	    totalbytesread += bytesread;
+	  }
+  }
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSTSS(MP4HandleImp handle,
+ *                    syncSampleAtom *stss)
+ *
+ * Description:
+ *
+ *   This function parses one STSS atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   stss               STSS pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTSS(MP4HandleImp handle, syncSampleAtom *stss)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+  mp4_u32 i;
+
+
+  if ((stss->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, stss->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (stss->atomhdr->type != ATOMTYPE_STSS)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  stss->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  if ( stss->entryCount )
+  {
+	  stss->sampleNumber = (mp4_u32 *)mp4malloc(stss->entryCount * sizeof(mp4_u32));
+	  if (stss->sampleNumber == NULL)
+	    return -1;
+
+	  for (i = 0; i < stss->entryCount; i++)
+	  {
+	    bytesread = readData(handle, handle->buf, 4);
+	    if (bytesread < 0)
+	      return -1;
+
+	    stss->sampleNumber[i] = u32endian(*((mp4_u32 *)handle->buf));
+
+	    totalbytesread += bytesread;
+	  }
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSTSD(MP4HandleImp handle,
+ *                    sampleDescriptionAtom *stsd)
+ *
+ * Description:
+ *
+ *   This function parses one STSD atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   stsd               STSD pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTSD(MP4HandleImp handle, sampleDescriptionAtom *stsd)
+	{
+	mp4_i32 bytesread;
+	mp4_i32 totalbytesread = 0;
+	mp4_u32 totalsampleentriesread = 0;
+	mp4_u32 unknownsampleentriesread = 0;
+	mp4_bool skipentries = 0;
+
+	if ((stsd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+        {
+        // for memory cleanup set entrycount to allocated num of entries.
+        stsd->entryCount = totalsampleentriesread;
+	    return -100;
+        }
+
+	bytesread = readFullAtomHeader(handle, stsd->atomhdr);
+	if (bytesread < 0)
+	    {
+	    // for memory cleanup set entrycount to allocated num of entries.
+	    stsd->entryCount = totalsampleentriesread;
+	    return -1;
+	    }
+	totalbytesread += bytesread;
+
+	if (stsd->atomhdr->type != ATOMTYPE_STSD)
+	    {
+	    // for memory cleanup set entrycount to allocated num of entries.
+	    stsd->entryCount = totalsampleentriesread;
+	    return -1;
+	    }
+
+	bytesread = readData(handle, handle->buf, 4);
+	if (bytesread < 0)
+	    {
+	    // for memory cleanup set entrycount to allocated num of entries.
+	    stsd->entryCount = totalsampleentriesread;
+	    return -1;
+	    }
+	stsd->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+	totalbytesread += bytesread;
+
+	mp4_u32 type;
+	while ((mp4_u32)totalbytesread < stsd->atomhdr->size)
+		{	
+		// if the number of entries read already surpasses the number of entries specified 
+		// within the STSD atom, the file is corrupted.
+		if ((totalsampleentriesread + unknownsampleentriesread) >= stsd->entryCount)
+			{
+			// for memory cleanup set entrycount to allocated num of entries.
+			stsd->entryCount = totalsampleentriesread;
+  	  		return -1;    	    	
+			}
+
+		// read the next sample type
+		if (peekData(handle, handle->buf, 8) < 0)
+	        {
+	        // for memory cleanup set entrycount to allocated num of entries.
+	        stsd->entryCount = totalsampleentriesread;
+		    return -1;
+	        }
+		type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+    
+		// if the max sample entiries supported by the library has been reached 
+		if ((stsd->entryCount > STSDMAXSAMPLEENTRYCOUNT) && (totalsampleentriesread == STSDMAXSAMPLEENTRYCOUNT))
+			{
+			// skip reading the rest of the entries to make sure no more than max count of sample entries 
+			// will be processed, so that cleanup will always work. 
+			type = 0;
+			skipentries = 1;
+			}
+
+		switch (type)
+			{
+			case ATOMTYPE_MP4V:
+				{
+				if (stsd->mp4v[totalsampleentriesread]) /* MP4V[totalsampleentriesread] has already been read, more than one is not allowed */ 
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+		
+				if ((stsd->mp4v[totalsampleentriesread] = (visualSampleEntry *)mp4malloc(sizeof(visualSampleEntry))) == NULL)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -100;
+			        }
+		
+				bytesread = readMP4V(handle, stsd->mp4v[totalsampleentriesread]);
+				totalsampleentriesread++;
+				if (bytesread < 0)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+				totalbytesread += bytesread;
+				break;
+				}
+
+			case ATOMTYPE_MP4A:
+				{	
+				if (stsd->mp4a[totalsampleentriesread]) /* MP4A[totalsampleentriesread] has already been read, more than one is not allowed */
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+
+				if ((stsd->mp4a[totalsampleentriesread] = (audioSampleEntry *)mp4malloc(sizeof(audioSampleEntry))) == NULL)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -100;
+			        }
+
+				bytesread = readMP4A(handle, stsd->mp4a[totalsampleentriesread]);
+				totalsampleentriesread++;
+				if (bytesread < 0)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+				totalbytesread += bytesread;
+				break;
+				}
+
+			case ATOMTYPE_MP4S:
+				{
+				if (stsd->mp4s[totalsampleentriesread]) /* MP4S has already been read, more than one is not allowed */
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+
+				if ((stsd->mp4s[totalsampleentriesread] = (mpegSampleEntry *)mp4malloc(sizeof(mpegSampleEntry))) == NULL)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -100;
+			        }
+
+				bytesread = readMP4S(handle, stsd->mp4s[totalsampleentriesread]);
+				totalsampleentriesread++;
+				if (bytesread < 0)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+				totalbytesread += bytesread;
+				}
+				break;
+
+			case ATOMTYPE_S263:
+				{
+				if (stsd->s263[totalsampleentriesread]) /* MP4S has already been read, more than one is not allowed */
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+
+				if ((stsd->s263[totalsampleentriesread] = (h263SampleEntry *)mp4malloc(sizeof(h263SampleEntry))) == NULL)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -100;
+			        }
+
+				bytesread = readS263(handle, stsd->s263[totalsampleentriesread]);
+				totalsampleentriesread++;
+				if (bytesread < 0)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+				totalbytesread += bytesread;
+				}
+				break;
+
+			case ATOMTYPE_SAMR:
+				{
+				if (stsd->samr[totalsampleentriesread]) /* SAMR has already been read, more than one is not allowed */
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+
+				if ((stsd->samr[totalsampleentriesread] = (amrSampleEntry *)mp4malloc(sizeof(amrSampleEntry))) == NULL)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -100;
+			        }
+
+				bytesread = readSAMR(handle, stsd->samr[totalsampleentriesread]);
+				totalsampleentriesread++;
+				if (bytesread < 0)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+				totalbytesread += bytesread;
+				}
+				break;
+
+			case ATOMTYPE_SAWB:
+				{
+				if (stsd->sawb[totalsampleentriesread]) /* SAWB has already been read, more than one is not allowed */
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+
+				if ((stsd->sawb[totalsampleentriesread] = (amrSampleEntry *)mp4malloc(sizeof(amrSampleEntry))) == NULL)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -100;
+			        }
+
+				bytesread = readSAWB(handle, stsd->sawb[totalsampleentriesread]);
+				totalsampleentriesread++;
+				if (bytesread < 0)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+				totalbytesread += bytesread;
+				}
+				break;
+
+			case ATOMTYPE_AVC1:
+				{
+				if (stsd->avc1[totalsampleentriesread]) /* AVC1 has already been read, more than one is not allowed */
+					{
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+					}
+				if ((stsd->avc1[totalsampleentriesread] = (avcSampleEntry *)mp4malloc(sizeof(avcSampleEntry))) == NULL)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -100;
+			        }
+
+				bytesread = readAVC1(handle, stsd->avc1[totalsampleentriesread]);
+				totalsampleentriesread++;
+				if (bytesread < 0)
+					{
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+				totalbytesread += bytesread;
+				}
+				break;
+
+			case ATOMTYPE_SQCP:
+				{
+				if (stsd->sqcp[totalsampleentriesread]) /* SQCP has already been read, more than one is not allowed */
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+				if ((stsd->sqcp[totalsampleentriesread] = (qcelpSampleEntry *)mp4malloc(sizeof(qcelpSampleEntry))) == NULL)
+			        {
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -100;
+			        }
+
+				bytesread = readSQCP(handle, stsd->sqcp[totalsampleentriesread]);
+				totalsampleentriesread++;
+				if (bytesread < 0)
+					{
+			        // for memory cleanup set entrycount to allocated num of entries.
+			        stsd->entryCount = totalsampleentriesread;
+				    return -1;
+			        }
+				totalbytesread += bytesread;
+				}
+				break;
+
+			default: /* Other atoms are not needed */
+				// no need to increment totalsampleentriesread as no memory is allocated for unsupported 
+				// or unrecognized sample types.  Alternatively, increment the count of unknown samples.   
+				// This is for ensure if a non-audio/video track can properly be parsed without being 
+				// recongized as an invalid format file.
+				unknownsampleentriesread++;
+				bytesread = readUnknown(handle);
+				if (bytesread < 0)
+		    		{
+		    		// for memory cleanup set entrycount to allocated num of entries.
+		    		stsd->entryCount = totalsampleentriesread;
+		    		return -1;
+		    		}
+				totalbytesread += bytesread;
+				break;
+			}
+		}
+
+	// if the STSD atom's entry count is NOT the same as the number (supported & unsupported) entries parsed,
+	// the atom is likely a corrupted one. 
+	if ((totalsampleentriesread + unknownsampleentriesread) != stsd->entryCount)
+		{
+		// for memory cleanup set entrycount to allocated num of entries.
+		stsd->entryCount = totalsampleentriesread;
+		return -1;
+		}
+	else 
+		{
+		// if the STSD atom's entry count is the same as the number of (supported & unsupported) entries 
+		// parsed, check if some entries are skipped because the max sample entry count has been reached  
+		if (skipentries) 
+			{
+			// if STSDMAXSAMPLEENTRYCOUNT was reached edit entrycount to make sure cleanup works.
+			stsd->entryCount = STSDMAXSAMPLEENTRYCOUNT;
+			}
+		else if (unknownsampleentriesread > 0)
+			{
+			// unknown (unsupported) sample entries present, set the STSD entry count to the actual 
+			// number of supported sample entries detected
+			stsd->entryCount = totalsampleentriesread;
+			}
+		}
+  
+	return totalbytesread;
+	}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSTSZ(MP4HandleImp handle,
+ *                    sampleSizeAtom *stsz)
+ *
+ * Description:
+ *
+ *   This function parses one STSZ atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   stsz               STSZ pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTSZ(MP4HandleImp handle, sampleSizeAtom *stsz)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((stsz->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, stsz->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (stsz->atomhdr->type != ATOMTYPE_STSZ)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  stsz->sampleSize = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  stsz->sampleCount = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  // zero size samplesize means samples have different sizes, and those sizes are stored in sampleSizeEntries.
+  if ((stsz->sampleCount) && (stsz->sampleSize == 0))
+  {
+    mp4_u32 i;
+
+    // check validity of stsz->sampleCount before allocating entrysize table.
+    if ( handle->moov->mvhd )
+        {
+        if ( handle->moov->mvhd->timeScale > 0 )
+            {
+            TUint magicNumberMaxSamplesInSec = MAXSAMPLESPERSECOND;
+            TUint maxSampleCount;
+
+            if ( handle->moov->mvhd->atomhdr->version == 1 ) // 64bit duration
+                {
+                maxSampleCount = I64INT(handle->moov->mvhd->duration64 / TUint(handle->moov->mvhd->timeScale) + 1) * magicNumberMaxSamplesInSec;
+                }
+            else    // 32bit duration
+                {
+                maxSampleCount = TUint((TUint( handle->moov->mvhd->duration  ) / TUint(handle->moov->mvhd->timeScale) + 1)) * magicNumberMaxSamplesInSec;
+                }
+
+            if ( maxSampleCount < stsz->sampleCount )
+                {
+                // corrupted 
+                return -1;
+                }
+            }
+        }
+
+    // allocate stsz->entrySize table
+    stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
+    if (stsz->entrySize == NULL)
+      return -1;
+
+    for (i = 0; i < stsz->sampleCount; i++)
+    {
+      bytesread = readData(handle, handle->buf, 4);
+      if (bytesread < 0)
+        return -1;
+
+      stsz->entrySize[i] = u32endian(*((mp4_u32 *)handle->buf));
+
+      totalbytesread += bytesread;
+    }
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSTZ2(MP4HandleImp handle,
+ *                    sampleSizeAtom *stsz)
+ *
+ * Description:
+ *
+ *   This function parses one STZ2 atom.
+ *
+ *   The result is placed in STSZ structure.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   stsz               STSZ pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTZ2(MP4HandleImp handle, sampleSizeAtom *stsz)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+  mp4_u8  fieldsize;
+
+
+  if ((stsz->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, stsz->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (stsz->atomhdr->type != ATOMTYPE_STZ2)
+    return -1;
+
+
+  bytesread = discardData(handle, 3);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  fieldsize = handle->buf[0];
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  stsz->sampleCount = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  switch (fieldsize)
+  {
+  case 4: /* Two entries in each byte */
+
+    {
+      mp4_u32 i;
+
+      stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
+      if (stsz->entrySize == NULL)
+        return -1;
+
+      for (i = 0; i < (stsz->sampleCount + 1) / 2; i++)
+      {
+        bytesread = readData(handle, handle->buf, 1);
+        if (bytesread < 0)
+          return -1;
+
+        totalbytesread += bytesread;
+
+        stsz->entrySize[i * 2] = (mp4_u32)(handle->buf[0] >> 4);
+
+        if (stsz->sampleCount % 2 == 0) /* Even number of samples */
+        {
+          stsz->entrySize[i * 2 + 1] = (mp4_u32)(handle->buf[0] & 0x0f);
+          continue;
+        }
+
+        /* This condition is needed to avoid writing after the table */
+
+        if (i == (stsz->sampleCount + 1) / 2 - 1) /* Last sample */
+        {
+        }
+        else
+          stsz->entrySize[i * 2 + 1] = (mp4_u32)(handle->buf[0] & 0x0f);
+      }
+    }
+
+    break;
+
+  case 8: /* One entry for each byte */
+
+    {
+      mp4_u32 i;
+
+      stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
+      if (stsz->entrySize == NULL)
+        return -1;
+
+      for (i = 0; i < stsz->sampleCount; i++)
+      {
+        bytesread = readData(handle, handle->buf, 1);
+        if (bytesread < 0)
+          return -1;
+
+        stsz->entrySize[i] = (mp4_u32)handle->buf[0];
+
+        totalbytesread += bytesread;
+      }
+    }
+
+    break;
+
+  case 16: /* Each entry in 2 bytes */
+
+    {
+      mp4_u32 i;
+
+      stsz->entrySize = (mp4_u32 *)mp4malloc(stsz->sampleCount * sizeof(mp4_u32));
+      if (stsz->entrySize == NULL)
+        return -1;
+
+      for (i = 0; i < stsz->sampleCount; i++)
+      {
+        bytesread = readData(handle, handle->buf, 2);
+        if (bytesread < 0)
+          return -1;
+
+        stsz->entrySize[i] = (mp4_u32)u16endian(*((mp4_u16 *)handle->buf));
+
+        totalbytesread += bytesread;
+      }
+    }
+
+    break;
+
+  default: /* Illegal fieldsize */
+
+    return -1;
+  }
+
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSTSC(MP4HandleImp handle,
+ *                    sampleToChunkAtom *stsc)
+ *
+ * Description:
+ *
+ *   This function parses one STSC atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   stsc               STSC pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTSC(MP4HandleImp handle, sampleToChunkAtom *stsc)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+  mp4_u32 i;
+
+
+  if ((stsc->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, stsc->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (stsc->atomhdr->type != ATOMTYPE_STSC)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  stsc->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  if (stsc->entryCount)
+  {
+	  stsc->firstChunk = (mp4_u32 *)mp4malloc(stsc->entryCount * sizeof(mp4_u32));
+	  if (stsc->firstChunk == NULL)
+	    return -1;
+	  stsc->samplesPerChunk = (mp4_u32 *)mp4malloc(stsc->entryCount * sizeof(mp4_u32));
+	  if (stsc->samplesPerChunk == NULL)
+	    return -1;
+	  stsc->sampleDescriptionIndex = (mp4_u32 *)mp4malloc(stsc->entryCount * sizeof(mp4_u32));
+	  if (stsc->sampleDescriptionIndex == NULL)
+	  {
+		return -1;	  	
+	  }
+
+	  for (i = 0; i < stsc->entryCount; i++)
+	  {
+	    bytesread = readData(handle, handle->buf, 12);
+	    if (bytesread < 0)
+	      return -1;
+
+	    stsc->firstChunk[i] = u32endian(*((mp4_u32 *)handle->buf));
+	    stsc->samplesPerChunk[i] = u32endian(*((mp4_u32 *)(handle->buf+4)));
+	    stsc->sampleDescriptionIndex[i] = u32endian(*((mp4_u32 *)(handle->buf+8)));
+	    if ( stsc->sampleDescriptionIndex[i] > stsc->entryCount)
+	    {
+	    	return -1;
+	    }
+
+	    totalbytesread += bytesread;
+	  }
+  }
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSTCO(MP4HandleImp handle,
+ *                    chunkOffsetAtom *stco)
+ *
+ * Description:
+ *
+ *   This function parses one STCO atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   stco               STCO pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSTCO(MP4HandleImp handle, chunkOffsetAtom *stco)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+  mp4_u32  i;
+
+
+  if ((stco->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, stco->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (stco->atomhdr->type != ATOMTYPE_STCO)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  stco->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  if (stco->entryCount)
+  {
+	  // validate stco->entryCount before allocating chunkOffsetTable
+	  if ( handle->moov->mvhd )
+	    {
+	    if ( handle->moov->mvhd->timeScale > 0 )
+	        {
+	        TUint magicNumberMaxSamplesInSec = MAXSAMPLESPERSECOND;
+	        TUint maxSampleCount;
+
+	        if ( handle->moov->mvhd->atomhdr->version == 1 ) // 64bit duration
+	            {
+	            maxSampleCount = I64INT(handle->moov->mvhd->duration64 / TUint(handle->moov->mvhd->timeScale) + 1) * magicNumberMaxSamplesInSec;
+	            }
+	        else    // 32bit duration
+	            {
+	            maxSampleCount = TUint((TUint( handle->moov->mvhd->duration  ) / TUint(handle->moov->mvhd->timeScale) + 1)) * magicNumberMaxSamplesInSec;
+	            }
+
+	        if ( maxSampleCount < stco->entryCount )
+	            {
+	            // corrupted 
+	            return -1;
+	            }
+	        }
+	    }
+
+	  stco->chunkOffset = (mp4_u32 *)mp4malloc(stco->entryCount * sizeof(mp4_u32));
+	  if (stco->chunkOffset == NULL)
+	    return -1;
+
+	  for (i = 0; i < stco->entryCount; i++)
+	  {
+	    bytesread = readData(handle, handle->buf, 4);
+	    if (bytesread < 0)
+	      return -1;
+
+	    stco->chunkOffset[i] = u32endian(*((mp4_u32 *)handle->buf));
+
+	    totalbytesread += bytesread;
+	  }
+  }
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readCO64(MP4HandleImp handle,
+ *                    chunkOffset64Atom *stco64)
+ *
+ * Description:
+ *
+ *   This function parses one CO64 atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   stco64               CO64 pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readCO64(MP4HandleImp handle, chunkOffset64Atom *stco64)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+  mp4_u32 i;
+
+
+  if ((stco64->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, stco64->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (stco64->atomhdr->type != ATOMTYPE_CO64)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  stco64->entryCount = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  if ( stco64->entryCount )
+  {
+	  stco64->chunkOffset = (mp4_u64 *)mp4malloc(stco64->entryCount * sizeof(mp4_u64));
+	  if (stco64->chunkOffset == NULL)
+	    return -1;
+
+	  for (i = 0; i < stco64->entryCount; i++)
+	  {
+	    bytesread = readData(handle, handle->buf, 8);
+	    if (bytesread < 0)
+	      return -1;
+	    
+	    stco64->chunkOffset[i] = u64endian(*((mp4_u64 *)(handle->buf)));
+
+	    totalbytesread += bytesread;
+	  }
+  }
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readMP4V(MP4HandleImp handle,
+ *                    visualSampleEntry *mp4v)
+ *
+ * Description:
+ *
+ *   This function parses one MP4V atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   mp4v               MP4V pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMP4V(MP4HandleImp handle, visualSampleEntry *mp4v)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((mp4v->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, mp4v->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (mp4v->atomhdr->type != ATOMTYPE_MP4V)
+    return -1;
+
+
+  bytesread = discardData(handle, 6);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  mp4v->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 16);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  mp4v->width = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  mp4v->height = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 50);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if ((mp4v->esd = (ESDAtom *)mp4malloc(sizeof(ESDAtom))) == NULL)
+    return -100;
+
+  bytesread = readESD(handle, mp4v->esd);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+  
+  if ( totalbytesread < mp4v->atomhdr->size )
+  	{
+    bytesread = discardData(handle, mp4v->atomhdr->size - totalbytesread );
+  	if (bytesread < 0)
+  		{
+    	return -1;	  		
+  		}
+  	totalbytesread += bytesread;
+  	}  
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readMP4A(MP4HandleImp handle,
+ *                    audioSampleEntry *mp4a)
+ *
+ * Description:
+ *
+ *   This function parses one MP4A atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   mp4a               MP4A pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMP4A(MP4HandleImp handle, audioSampleEntry *mp4a)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((mp4a->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, mp4a->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (mp4a->atomhdr->type != ATOMTYPE_MP4A)
+    return -1;
+
+
+  bytesread = discardData(handle, 6);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  mp4a->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 16);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  mp4a->timeScale = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 2);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if ((mp4a->esd = (ESDAtom *)mp4malloc(sizeof(ESDAtom))) == NULL)
+    return -100;
+
+  bytesread = readESD(handle, mp4a->esd);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+  
+  if ( totalbytesread < mp4a->atomhdr->size )
+  	{
+    bytesread = discardData(handle, mp4a->atomhdr->size - totalbytesread );
+  	if (bytesread < 0)
+  		{
+    	return -1;	  		
+  		}
+  	totalbytesread += bytesread;
+  	}
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readMP4S(MP4HandleImp handle,
+ *                    mpegSampleEntry *mp4s)
+ *
+ * Description:
+ *
+ *   This function parses one MP4S atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   mp4s               MP4S pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readMP4S(MP4HandleImp handle, mpegSampleEntry *mp4s)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((mp4s->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, mp4s->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (mp4s->atomhdr->type != ATOMTYPE_MP4S)
+    return -1;
+
+
+  bytesread = discardData(handle, 6);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  mp4s->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  if ((mp4s->esd = (ESDAtom *)mp4malloc(sizeof(ESDAtom))) == NULL)
+    return -100;
+
+  bytesread = readESD(handle, mp4s->esd);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+  
+  if ( totalbytesread < mp4s->atomhdr->size )
+  	{
+    bytesread = discardData(handle, mp4s->atomhdr->size - totalbytesread );
+  	if (bytesread < 0)
+  		{
+    	return -1;	  		
+  		}
+  	totalbytesread += bytesread;
+  	}    
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readS263(MP4HandleImp handle,
+ *                    h263SampleEntry *s263)
+ *
+ * Description:
+ *
+ *   This function parses one S263 atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   s263               S263 pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readS263(MP4HandleImp handle, h263SampleEntry *s263)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((s263->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, s263->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (s263->atomhdr->type != ATOMTYPE_S263)
+    return -1;
+
+
+  bytesread = discardData(handle, 6);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  s263->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 16);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  s263->width = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  s263->height = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 50);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if ((s263->d263 = (h263SpecificAtom *)mp4malloc(sizeof(h263SpecificAtom))) == NULL)
+    return -100;
+
+  bytesread = readD263(handle, s263->d263);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+  
+  if ( totalbytesread < s263->atomhdr->size )
+  	{
+    bytesread = discardData(handle, s263->atomhdr->size - totalbytesread );
+  	if (bytesread < 0)
+  		{
+    	return -1;	  		
+  		}
+  	totalbytesread += bytesread;
+  	}      
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSAMR(MP4HandleImp handle,
+ *                    amrSampleEntry *samr)
+ *
+ * Description:
+ *
+ *   This function parses one SAMR atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   samr               SAMR pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSAMR(MP4HandleImp handle, amrSampleEntry *samr)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((samr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, samr->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (samr->atomhdr->type != ATOMTYPE_SAMR)
+    return -1;
+
+
+  bytesread = discardData(handle, 6);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  samr->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 16);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  samr->timeScale = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 2);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if ((samr->damr = (amrDecSpecStruc *)mp4malloc(sizeof(amrDecSpecStruc))) == NULL)
+    return -100;
+
+  bytesread = readDAMR(handle, samr->damr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+  
+  if ( totalbytesread < samr->atomhdr->size )
+  	{
+    bytesread = discardData(handle, samr->atomhdr->size - totalbytesread );
+  	if (bytesread < 0)
+  		{
+    	return -1;	  		
+  		}
+  	totalbytesread += bytesread;
+  	}      
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSAWB(MP4HandleImp handle,
+ *                    amrSampleEntry *sawb)
+ *
+ * Description:
+ *
+ *   This function parses one SAWB atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   sawb               SAWB pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSAWB(MP4HandleImp handle, amrSampleEntry *sawb)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((sawb->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, sawb->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (sawb->atomhdr->type != ATOMTYPE_SAWB)
+    return -1;
+
+
+  bytesread = discardData(handle, 6);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  sawb->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 16);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  sawb->timeScale = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 2);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if ((sawb->damr = (amrDecSpecStruc *)mp4malloc(sizeof(amrDecSpecStruc))) == NULL)
+    return -100;
+
+  bytesread = readDAMR(handle, sawb->damr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+  
+  if ( totalbytesread < sawb->atomhdr->size )
+  	{
+    bytesread = discardData(handle, sawb->atomhdr->size - totalbytesread );
+  	if (bytesread < 0)
+  		{
+    	return -1;	  		
+  		}
+  	totalbytesread += bytesread;
+  	}      
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readESD(MP4HandleImp handle,
+ *                   ESDAtom *esd)
+ *
+ * Description:
+ *
+ *   This function parses one ESD atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   esd                ESD pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readESD(MP4HandleImp handle, ESDAtom *esd)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+  mp4_i32 decConfDescrBytesRead = 0;
+
+
+  if ((esd->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readFullAtomHeader(handle, esd->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (esd->atomhdr->type != ATOMTYPE_ESD)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  esd->esDescrTag = handle->buf[0];
+  totalbytesread += bytesread;
+  if (esd->esDescrTag != 3) /* ES_DescrTag == 3 */
+    return -1;
+
+  esd->size = 0;
+  do
+  {
+    mp4_u8 c;
+
+    bytesread = readData(handle, handle->buf, 1);
+    if (bytesread < 0)
+      return -1;
+    c = (mp4_u8)(handle->buf[0] & 0x7f);
+    esd->size = (esd->size << 7) | c;
+    totalbytesread += bytesread;
+  }
+  while (handle->buf[0] & 0x80);
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  esd->ESID = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  esd->flags = handle->buf[0];
+  totalbytesread += bytesread;
+
+  if (esd->flags & 0x80) /* Stream Dependence flag has been set */
+  {
+    bytesread = readData(handle, handle->buf, 2);
+    if (bytesread < 0)
+      return -1;
+    esd->dependsOnESID = u16endian(*((mp4_u16 *)handle->buf));
+    totalbytesread += bytesread;
+  }
+
+  if (esd->flags & 0x40) /* URL flag has been set */
+  {
+    bytesread = readData(handle, handle->buf, 1);
+    if (bytesread < 0)
+      return -1;
+    esd->URLLength = handle->buf[0];
+    totalbytesread += bytesread;
+
+    bytesread = discardData(handle, esd->URLLength);
+    if (bytesread < 0)
+      return -1;
+    totalbytesread += bytesread;
+  }
+
+  if (esd->flags & 0x20) /* OCR stream flag has been set */
+  {
+    bytesread = readData(handle, handle->buf, 2);
+    if (bytesread < 0)
+      return -1;
+    esd->OCRESID = u16endian(*((mp4_u16 *)handle->buf));
+    totalbytesread += bytesread;
+  }
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  esd->decConfDescrTag = handle->buf[0];
+  totalbytesread += bytesread;
+  if (esd->decConfDescrTag != 4) /* DecoderConfigDescrTag == 4 */
+    return -1;
+
+  esd->decConfDescrSize = 0;
+  do
+  {
+    mp4_u8 c;
+
+    bytesread = readData(handle, handle->buf, 1);
+    if (bytesread < 0)
+      return -1;
+    c = (mp4_u8)(handle->buf[0] & 0x7f);
+    esd->decConfDescrSize = (esd->decConfDescrSize << 7) | c;
+    totalbytesread += bytesread;
+  }
+  while (handle->buf[0] & 0x80);
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  esd->objectTypeIndication = handle->buf[0];
+  totalbytesread += bytesread;
+  decConfDescrBytesRead += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  esd->stream = handle->buf[0];
+  totalbytesread += bytesread;
+  decConfDescrBytesRead += bytesread;
+
+  bytesread = readData(handle, handle->buf, 3);
+  if (bytesread < 0)
+    return -1;
+  esd->bufferSizeDB = ((mp4_u32)handle->buf[0]) << 16 |
+                      ((mp4_u32)handle->buf[1]) << 8 |
+                      ((mp4_u32)handle->buf[2]);
+  totalbytesread += bytesread;
+  decConfDescrBytesRead += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  esd->maxBitrate = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+  decConfDescrBytesRead += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  esd->avgBitrate = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+  decConfDescrBytesRead += bytesread;
+
+  if ((mp4_u32)decConfDescrBytesRead < esd->decConfDescrSize)
+  {
+    bytesread = readData(handle, handle->buf, 1);
+    if (bytesread < 0)
+      return -1;
+    esd->decSpecificInfoTag = handle->buf[0];
+    totalbytesread += bytesread;
+    decConfDescrBytesRead += bytesread;
+    if (esd->decSpecificInfoTag != 5) /* DecSpecificInfoTag == 5 */
+    {
+      bytesread = discardData(handle, esd->decConfDescrSize - decConfDescrBytesRead);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+    }
+    else
+    {
+      esd->decSpecificInfoSize = 0;
+      do
+      {
+        mp4_u8 c;
+
+        bytesread = readData(handle, handle->buf, 1);
+        if (bytesread < 0)
+          return -1;
+        c = (mp4_u8)(handle->buf[0] & 0x7f);
+        esd->decSpecificInfoSize = (esd->decSpecificInfoSize << 7) | c;
+        totalbytesread += bytesread;
+      }
+      while (handle->buf[0] & 0x80);
+
+      if(esd->decSpecificInfoSize)
+      {
+        if ((esd->decSpecificInfo = (mp4_u8 *)mp4malloc(esd->decSpecificInfoSize)) == NULL)
+          return -100;
+
+        bytesread = readData(handle, esd->decSpecificInfo, esd->decSpecificInfoSize);
+        if (bytesread < 0)
+          return -1;
+        totalbytesread += bytesread;
+      }
+    }
+  }
+
+  bytesread = discardData(handle, esd->atomhdr->size - totalbytesread);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readD263(MP4HandleImp handle,
+ *                    h263SpecificAtom *d263)
+ *
+ * Description:
+ *
+ *   This function parses one D263 atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   d263               D263 pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readD263(MP4HandleImp handle, h263SpecificAtom *d263)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((d263->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, d263->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (d263->atomhdr->type != ATOMTYPE_D263)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  d263->vendor = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  d263->decoderVersion = handle->buf[0];
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  d263->h263Level = handle->buf[0];
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  d263->h263Profile = handle->buf[0];
+  totalbytesread += bytesread;
+
+  /* Check for the bitrate atom */
+
+  while ((mp4_u32)totalbytesread < d263->atomhdr->size)
+  {
+    mp4_u32 type;
+
+
+    if (peekData(handle, handle->buf, 8) < 0)
+      return -1;
+
+    type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+    switch (type)
+    {
+    case ATOMTYPE_BITR:
+
+      if (d263->bitr) /* BITR has already been read, more than one is not allowed */
+        return -1;
+
+      if ((d263->bitr = (bitrateAtom *)mp4malloc(sizeof(bitrateAtom))) == NULL)
+        return -100;
+
+      bytesread = readBITR(handle, d263->bitr);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+
+    default: /* Other atoms are not needed */
+
+      bytesread = readUnknown(handle);
+      if (bytesread < 0)
+        return -1;
+      totalbytesread += bytesread;
+
+      break;
+    }
+  }
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readBITR(MP4HandleImp handle,
+ *                    bitrateAtom *d263)
+ *
+ * Description:
+ *
+ *   This function parses one BITR atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   bitr               BITR pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readBITR(MP4HandleImp handle, bitrateAtom *bitr)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((bitr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, bitr->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (bitr->atomhdr->type != ATOMTYPE_BITR)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  bitr->avgBitrate = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  bitr->maxBitrate = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readDAMR(MP4HandleImp handle,
+ *                    amrDecSpecStruc *damr)
+ *
+ * Description:
+ *
+ *   This function parses one DAMR atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   damr               DAMR pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readDAMR(MP4HandleImp handle, amrDecSpecStruc *damr)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((damr->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, damr->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (damr->atomhdr->type != ATOMTYPE_DAMR)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  damr->vendor = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  damr->decoderVersion = handle->buf[0];
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  damr->modeSet = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  damr->modeChangePeriod = handle->buf[0];
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  damr->framesPerSample = handle->buf[0];
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeFTYP(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ *   This function frees memory for FTYP atom.
+ *
+ * Parameters:
+ *
+ *   ftyp       FTYP atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeFTYP(fileTypeAtom *ftyp)
+{
+  if (ftyp)
+  {
+    if (freeAtomHeader(ftyp->atomhdr) < 0)
+      return -1;
+    if (ftyp->compatibleBrands)
+      mp4free(ftyp->compatibleBrands);
+
+    mp4free(ftyp);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeMOOV(movieAtom *moov)
+ *
+ * Description:
+ *
+ *   This function frees memory for MOOV atom.
+ *
+ * Parameters:
+ *
+ *   moov       MOOV atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeMOOV(movieAtom *moov)
+{
+  if (moov)
+  {
+    if (freeAtomHeader(moov->atomhdr) < 0)
+      return -1;
+    if (freeMVHD(moov->mvhd) < 0)
+      return -1;
+    if (freeTRAK(moov->trakAudio) < 0)
+      return -1;
+    if (freeTRAK(moov->trakVideo) < 0)
+      return -1;
+    if (freeIODS(moov->iods) < 0)
+      return -1;
+    if (freeUDTA(moov->udta) < 0)
+      return -1;
+
+    mp4free(moov);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeAtomHeader(atomHeader *atomhdr)
+ *
+ * Description:
+ *
+ *   This function frees memory for atom header.
+ *
+ * Parameters:
+ *
+ *   atomhdr    atom header pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeAtomHeader(atomHeader *atomhdr)
+{
+  if (atomhdr)
+    mp4free(atomhdr);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeMVHD(movieHeaderAtom *mvhd)
+ *
+ * Description:
+ *
+ *   This function frees memory for MVHD atom.
+ *
+ * Parameters:
+ *
+ *   mvhd       MVHD atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeMVHD(movieHeaderAtom *mvhd)
+{
+  if (mvhd)
+  {
+    if (freeAtomHeader(mvhd->atomhdr) < 0)
+      return -1;
+
+    mp4free(mvhd);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeTRAK(trackAtom *trak)
+ *
+ * Description:
+ *
+ *   This function frees memory for TRAK atom.
+ *
+ * Parameters:
+ *
+ *   trak       TRAK atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeTRAK(trackAtom *trak)
+{
+  if (trak)
+  {
+    if (freeAtomHeader(trak->atomhdr) < 0)
+      return -1;
+    if (freeTKHD(trak->tkhd) < 0)
+      return -1;
+    if (freeTREF(trak->tref) < 0)
+      return -1;
+    if (freeEDTS(trak->edts) < 0)
+      return -1;
+    if (freeMDIA(trak->mdia) < 0)
+      return -1;
+    if (freeUDTA(trak->udta) < 0)
+      return -1;
+
+    mp4free(trak);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeTKHD(trackHeaderAtom *tkhd)
+ *
+ * Description:
+ *
+ *   This function frees memory for TKHD atom.
+ *
+ * Parameters:
+ *
+ *   tkhd       TKHD atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeTKHD(trackHeaderAtom *tkhd)
+{
+  if (tkhd)
+  {
+    if (freeAtomHeader(tkhd->atomhdr) < 0)
+      return -1;
+
+    mp4free(tkhd);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeTREF(trackReferenceAtom *tref)
+ *
+ * Description:
+ *
+ *   This function frees memory for TREF atom.
+ *
+ * Parameters:
+ *
+ *   tref       TREF atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeTREF(trackReferenceAtom *tref)
+{
+  if (tref)
+  {
+    if (freeAtomHeader(tref->atomhdr) < 0)
+      return -1;
+
+    mp4free(tref);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeEDTS(editListContainerAtom *edts)
+ *
+ * Description:
+ *
+ *   This function frees memory for EDTS atom.
+ *
+ * Parameters:
+ *
+ *   edts       EDTS atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeEDTS(editListContainerAtom *edts)
+{
+  if (edts)
+  {
+    if (freeAtomHeader(edts->atomhdr) < 0)
+      return -1;
+
+    mp4free(edts);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeMDIA(mediaAtom *mdia)
+ *
+ * Description:
+ *
+ *   This function frees memory for MDIA atom.
+ *
+ * Parameters:
+ *
+ *   mdia       MDIA atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeMDIA(mediaAtom *mdia)
+{
+  if (mdia)
+  {
+    if (freeAtomHeader(mdia->atomhdr) < 0)
+      return -1;
+    if (freeMDHD(mdia->mdhd) < 0)
+      return -1;
+    if (freeHDLR(mdia->hdlr) < 0)
+      return -1;
+    if (freeMINF(mdia->minf) < 0)
+      return -1;
+
+    mp4free(mdia);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeMDHD(mediaHeaderAtom *mdhd)
+ *
+ * Description:
+ *
+ *   This function frees memory for MDHD atom.
+ *
+ * Parameters:
+ *
+ *   mdhd       MDHD atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeMDHD(mediaHeaderAtom *mdhd)
+{
+  if (mdhd)
+  {
+    if (freeAtomHeader(mdhd->atomhdr) < 0)
+      return -1;
+
+    mp4free(mdhd);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeHDLR(handlerAtom *hdlr)
+ *
+ * Description:
+ *
+ *   This function frees memory for HDLR atom.
+ *
+ * Parameters:
+ *
+ *   hdlr       HDLR atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeHDLR(handlerAtom *hdlr)
+{
+  if (hdlr)
+  {
+    if (freeAtomHeader(hdlr->atomhdr) < 0)
+      return -1;
+    if (hdlr->name)
+      mp4free(hdlr->name);
+
+    mp4free(hdlr);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeMINF(mediaInformationAtom *minf)
+ *
+ * Description:
+ *
+ *   This function frees memory for MINF atom.
+ *
+ * Parameters:
+ *
+ *   minf       MINF atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeMINF(mediaInformationAtom *minf)
+{
+  if (minf)
+  {
+    if (freeAtomHeader(minf->atomhdr) < 0)
+      return -1;
+    if (freeVMHD(minf->vmhd) < 0)
+      return -1;
+    if (freeSMHD(minf->smhd) < 0)
+      return -1;
+    if (freeDINF(minf->dinf) < 0)
+      return -1;
+    if (freeSTBL(minf->stbl) < 0)
+      return -1;
+
+    mp4free(minf);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeVMHD(videoMediaHeaderAtom *vmhd)
+ *
+ * Description:
+ *
+ *   This function frees memory for VMHD atom.
+ *
+ * Parameters:
+ *
+ *   vmhd       VMHD atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeVMHD(videoMediaHeaderAtom *vmhd)
+{
+  if (vmhd)
+  {
+    if (freeAtomHeader(vmhd->atomhdr) < 0)
+      return -1;
+
+    mp4free(vmhd);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSMHD(soundMediaHeaderAtom *smhd)
+ *
+ * Description:
+ *
+ *   This function frees memory for SMHD atom.
+ *
+ * Parameters:
+ *
+ *   smhd       SMHD atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSMHD(soundMediaHeaderAtom *smhd)
+{
+  if (smhd)
+  {
+    if (freeAtomHeader(smhd->atomhdr) < 0)
+      return -1;
+
+    mp4free(smhd);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeDINF(dataInformationAtom *dinf)
+ *
+ * Description:
+ *
+ *   This function frees memory for DINF atom.
+ *
+ * Parameters:
+ *
+ *   dinf       DINF atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeDINF(dataInformationAtom *dinf)
+{
+  if (dinf)
+  {
+    if (freeAtomHeader(dinf->atomhdr) < 0)
+      return -1;
+    if (freeDREF(dinf->dref) < 0)
+      return -1;
+
+    mp4free(dinf);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeDREF(dataReferenceAtom *dref)
+ *
+ * Description:
+ *
+ *   This function frees memory for DREF atom.
+ *
+ * Parameters:
+ *
+ *   dref       DREF atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeDREF(dataReferenceAtom *dref)
+{
+  if (dref)
+  {
+    if (freeAtomHeader(dref->atomhdr) < 0)
+      return -1;
+    if (freeURL(dref->url) < 0)
+      return -1;
+    if (freeURN(dref->urn) < 0)
+      return -1;
+
+    mp4free(dref);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeURL(dataEntryURLAtom *url)
+ *
+ * Description:
+ *
+ *   This function frees memory for URL atom.
+ *
+ * Parameters:
+ *
+ *   url        URL atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeURL(dataEntryURLAtom *url)
+{
+  if (url)
+  {
+    if (freeAtomHeader(url->atomhdr) < 0)
+      return -1;
+
+    mp4free(url);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeURN(dataEntryURNAtom *urn)
+ *
+ * Description:
+ *
+ *   This function frees memory for URN atom.
+ *
+ * Parameters:
+ *
+ *   urn        URN atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeURN(dataEntryURNAtom *urn)
+{
+  if (urn)
+  {
+    if (freeAtomHeader(urn->atomhdr) < 0)
+      return -1;
+
+    mp4free(urn);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSTBL(sampleTableAtom *stbl)
+ *
+ * Description:
+ *
+ *   This function frees memory for STBL atom.
+ *
+ * Parameters:
+ *
+ *   stbl       STBL atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSTBL(sampleTableAtom *stbl)
+{
+  if (stbl)
+  {
+    if (freeAtomHeader(stbl->atomhdr) < 0)
+      return -1;
+    if (freeSTTS(stbl->stts) < 0)
+      return -1;
+    if (freeCTTS(stbl->ctts) < 0)
+      return -1;
+    if (freeSTSD(stbl->stsd) < 0)
+      return -1;
+    if (freeSTSZ(stbl->stsz) < 0)
+      return -1;
+    if (freeSTSC(stbl->stsc) < 0)
+      return -1;
+    if (stbl->is32BitOffsets)
+    {
+    
+      if (freeSTCO(stbl->stco) < 0)
+        return -1;
+    }
+    else
+    {
+    
+      if (freeSTCO64(stbl->stco64) < 0)
+        return -1;
+    }
+    if (freeSTSS(stbl->stss) < 0)
+      return -1;
+    if (freeSTSH(stbl->stsh) < 0)
+      return -1;
+    if (freeSDTP(stbl->sdtp) < 0)
+      return -1;
+
+    mp4free(stbl);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSTTS(timeToSampleAtom *stts)
+ *
+ * Description:
+ *
+ *   This function frees memory for STTS atom.
+ *
+ * Parameters:
+ *
+ *   stts       STTS atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSTTS(timeToSampleAtom *stts)
+{
+  if (stts)
+  {
+    if (freeAtomHeader(stts->atomhdr) < 0)
+      return -1;
+    if (stts->sampleCount)
+      mp4free(stts->sampleCount);
+    if (stts->sampleDelta)
+      mp4free(stts->sampleDelta);
+
+    mp4free(stts);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeCTTS(compositionTimeToSampleAtom *ctts)
+ *
+ * Description:
+ *
+ *   This function frees memory for CTTS atom.
+ *
+ * Parameters:
+ *
+ *   ctts       CTTS atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeCTTS(compositionTimeToSampleAtom *ctts)
+{
+  if (ctts)
+  {
+    if (freeAtomHeader(ctts->atomhdr) < 0)
+      return -1;
+    if (ctts->sampleCount)
+      mp4free(ctts->sampleCount);
+    if (ctts->sampleOffset)
+      mp4free(ctts->sampleOffset);
+
+    mp4free(ctts);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSTSD(sampleDescriptionAtom *stsd)
+ *
+ * Description:
+ *
+ *   This function frees memory for STSD atom.
+ *
+ * Parameters:
+ *
+ *   stsd       STSD atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSTSD(sampleDescriptionAtom *stsd)
+{
+  mp4_u32 sampleentrycount = 0;
+  mp4_u32 entryindex;
+  
+  if (stsd)
+  {
+	sampleentrycount = stsd->entryCount;
+
+    if (freeAtomHeader(stsd->atomhdr) < 0)
+      return -1;
+	for (entryindex = 0; entryindex < sampleentrycount; entryindex++)
+	{
+		if (freeMP4V(stsd->mp4v[entryindex]) < 0)
+		  return -1;
+		if (freeMP4A(stsd->mp4a[entryindex]) < 0)
+		  return -1;
+		if (freeMP4S(stsd->mp4s[entryindex]) < 0)
+		  return -1;
+		if (freeS263(stsd->s263[entryindex]) < 0)
+		  return -1;
+		if (freeSAMR(stsd->samr[entryindex]) < 0)
+		  return -1;
+		if (freeSAWB(stsd->sawb[entryindex]) < 0)
+		  return -1;
+		if (freeAVC1(stsd->avc1[entryindex]) < 0)
+			return -1;
+        if (freeSQCP(stsd->sqcp[entryindex]) < 0)
+          return -1;
+	}
+    mp4free(stsd);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeMP4V(visualSampleEntry *mp4v)
+ *
+ * Description:
+ *
+ *   This function frees memory for MP4V atom.
+ *
+ * Parameters:
+ *
+ *   mp4v       MP4V atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeMP4V(visualSampleEntry *mp4v)
+{
+  if (mp4v)
+  {
+    if (freeAtomHeader(mp4v->atomhdr) < 0)
+      return -1;
+    if (freeESD(mp4v->esd) < 0)
+      return -1;
+
+    mp4free(mp4v);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeESD(ESDAtom *esd)
+ *
+ * Description:
+ *
+ *   This function frees memory for ESD atom.
+ *
+ * Parameters:
+ *
+ *   esd        ESD atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeESD(ESDAtom *esd)
+{
+  if (esd)
+  {
+    if (freeAtomHeader(esd->atomhdr) < 0)
+      return -1;
+    if (esd->URLString)
+      mp4free(esd->URLString);
+    if (esd->decSpecificInfo)
+      mp4free(esd->decSpecificInfo);
+
+    mp4free(esd);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeMP4A(audioSampleEntry *mp4a)
+ *
+ * Description:
+ *
+ *   This function frees memory for MP4A atom.
+ *
+ * Parameters:
+ *
+ *   mp4a       MP4A atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeMP4A(audioSampleEntry *mp4a)
+{
+  if (mp4a)
+  {
+    if (freeAtomHeader(mp4a->atomhdr) < 0)
+      return -1;
+    if (freeESD(mp4a->esd) < 0)
+      return -1;
+
+    mp4free(mp4a);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeMP4S(mpegSampleEntry *mp4s)
+ *
+ * Description:
+ *
+ *   This function frees memory for MP4S atom.
+ *
+ * Parameters:
+ *
+ *   mp4s       MP4S atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeMP4S(mpegSampleEntry *mp4s)
+{
+  if (mp4s)
+  {
+    if (freeAtomHeader(mp4s->atomhdr) < 0)
+      return -1;
+    if (freeESD(mp4s->esd) < 0)
+      return -1;
+
+    mp4free(mp4s);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeS263(h263SampleEntry *s263)
+ *
+ * Description:
+ *
+ *   This function frees memory for S263 atom.
+ *
+ * Parameters:
+ *
+ *   s263       S263 atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeS263(h263SampleEntry *s263)
+{
+  if (s263)
+  {
+    if (freeAtomHeader(s263->atomhdr) < 0)
+      return -1;
+    if (freeD263(s263->d263) < 0)
+      return -1;
+
+    mp4free(s263);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeD263(h263SpecificAtom *d263)
+ *
+ * Description:
+ *
+ *   This function frees memory for D263 atom.
+ *
+ * Parameters:
+ *
+ *   d263       D263 atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeD263(h263SpecificAtom *d263)
+{
+  if (d263)
+  {
+    if (freeAtomHeader(d263->atomhdr) < 0)
+      return -1;
+    if (freeBITR(d263->bitr) < 0)
+      return -1;
+
+    mp4free(d263);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeBITR(BitrateAtom *bitr)
+ *
+ * Description:
+ *
+ *   This function frees memory for BITR atom.
+ *
+ * Parameters:
+ *
+ *   bitr       BITR atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeBITR(bitrateAtom *bitr)
+{
+  if (bitr)
+  {
+    if (freeAtomHeader(bitr->atomhdr) < 0)
+      return -1;
+
+    mp4free(bitr);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSAMR(amrSampleEntry *samr)
+ *
+ * Description:
+ *
+ *   This function frees memory for SAMR atom.
+ *
+ * Parameters:
+ *
+ *   samr       SAMR atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSAMR(amrSampleEntry *samr)
+{
+  if (samr)
+  {
+    if (freeAtomHeader(samr->atomhdr) < 0)
+      return -1;
+    if (freeDAMR(samr->damr) < 0)
+      return -1;
+
+    mp4free(samr);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSAWB(amrSampleEntry *sawb)
+ *
+ * Description:
+ *
+ *   This function frees memory for SAWB atom.
+ *
+ * Parameters:
+ *
+ *   sawb       SAWB atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSAWB(amrSampleEntry *sawb)
+{
+  if (sawb)
+  {
+    if (freeAtomHeader(sawb->atomhdr) < 0)
+      return -1;
+    if (freeDAMR(sawb->damr) < 0)
+      return -1;
+
+    mp4free(sawb);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeDAMR(amrDecSpecStruc *damr)
+ *
+ * Description:
+ *
+ *   This function frees memory for DAMR atom.
+ *
+ * Parameters:
+ *
+ *   damr       DAMR atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeDAMR(amrDecSpecStruc *damr)
+{
+  if (damr)
+  {
+    if (freeAtomHeader(damr->atomhdr) < 0)
+      return -1;
+
+    mp4free(damr);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSTSZ(sampleSizeAtom *stsz)
+ *
+ * Description:
+ *
+ *   This function frees memory for STSZ atom.
+ *
+ * Parameters:
+ *
+ *   stsz       STSZ atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSTSZ(sampleSizeAtom *stsz)
+{
+  if (stsz)
+  {
+    if (freeAtomHeader(stsz->atomhdr) < 0)
+      return -1;
+    if (stsz->entrySize)
+      mp4free(stsz->entrySize);
+
+    mp4free(stsz);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSTSC(sampleToChunkAtom *stsc)
+ *
+ * Description:
+ *
+ *   This function frees memory for STSC atom.
+ *
+ * Parameters:
+ *
+ *   stsc       STSC atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSTSC(sampleToChunkAtom *stsc)
+{
+  if (stsc)
+  {
+    if (freeAtomHeader(stsc->atomhdr) < 0)
+      return -1;
+    if (stsc->firstChunk)
+      mp4free(stsc->firstChunk);
+    if (stsc->samplesPerChunk)
+      mp4free(stsc->samplesPerChunk);
+    if (stsc->sampleDescriptionIndex)
+      mp4free(stsc->sampleDescriptionIndex);
+
+    mp4free(stsc);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSTCO(chunkOffsetAtom *stco)
+ *
+ * Description:
+ *
+ *   This function frees memory for STCO atom.
+ *
+ * Parameters:
+ *
+ *   stco       STCO atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSTCO(chunkOffsetAtom *stco)
+{
+  if (stco)
+  {
+    if (freeAtomHeader(stco->atomhdr) < 0)
+      return -1;
+    if (stco->chunkOffset)
+      mp4free(stco->chunkOffset);
+
+    mp4free(stco);
+  }
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSTCO64(chunkOffset64Atom *stco64)
+ *
+ * Description:
+ *
+ *   This function frees memory for STCO64 atom.
+ *
+ * Parameters:
+ *
+ *   stco64       STCO64 atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSTCO64(chunkOffset64Atom *stco64)
+{
+  if (stco64)
+  {
+    if (freeAtomHeader(stco64->atomhdr) < 0)
+      return -1;
+    if (stco64->chunkOffset)
+      mp4free(stco64->chunkOffset);
+
+    mp4free(stco64);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSTSS(syncSampleAtom *stss)
+ *
+ * Description:
+ *
+ *   This function frees memory for STSS atom.
+ *
+ * Parameters:
+ *
+ *   stss       STSS atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSTSS(syncSampleAtom *stss)
+{
+  if (stss)
+  {
+    if (freeAtomHeader(stss->atomhdr) < 0)
+      return -1;
+    if (stss->sampleNumber)
+      mp4free(stss->sampleNumber);
+
+    mp4free(stss);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSTSH(shadowSyncSampleAtom *stsh)
+ *
+ * Description:
+ *
+ *   This function frees memory for STSH atom.
+ *
+ * Parameters:
+ *
+ *   stsh       STSH atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSTSH(shadowSyncSampleAtom *stsh)
+{
+  if (stsh)
+  {
+    if (freeAtomHeader(stsh->atomhdr) < 0)
+      return -1;
+
+    mp4free(stsh);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSDTP(sampleDependencyAtom *sdtp)
+ *
+ * Description:
+ *
+ *   This function frees memory for SDTP atom.
+ *
+ * Parameters:
+ *
+ *   sdtp       SDTP atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSDTP(sampleDependencyAtom *sdtp)
+	{
+	if (sdtp)
+		{
+		if (freeAtomHeader(sdtp->atomhdr) < 0)
+			{
+			return -1;
+			}
+
+		if (sdtp->dep)
+			{
+			mp4free(sdtp->dep);
+			}		
+    
+		mp4free(sdtp);
+		}
+
+  	return 0;
+	}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeIODS(objectDescriptorAtom *iods)
+ *
+ * Description:
+ *
+ *   This function frees memory for IODS atom.
+ *
+ * Parameters:
+ *
+ *   iods       IODS atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeIODS(objectDescriptorAtom *iods)
+{
+  if (iods)
+  {
+    if (freeAtomHeader(iods->atomhdr) < 0)
+      return -1;
+
+    mp4free(iods);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readUDTA(MP4HandleImp handle,
+ *                    userDataAtom *udta)
+ *
+ * Description:
+ *
+ *   This function parses one UDTA atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   udta               UDTA pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readUDTA(MP4HandleImp handle, userDataAtom *udta)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+  if ((udta->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, udta->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (udta->atomhdr->type != ATOMTYPE_UDTA)
+    return -1;
+
+  if ( handle->file )
+      {
+      udta->atomcontentloc = handle->diskReadBufStart + handle->diskReadBufPos;
+      }
+  else
+      {
+      udta->atomcontentloc = handle->absPosition;
+      }
+
+  if ( udta->atomhdr->size == 1 )
+      {
+      udta->atomcontentsize = I64INT(udta->atomhdr->largeSize) - (TInt)totalbytesread;
+      }
+  else
+      {
+      udta->atomcontentsize = (TInt)(udta->atomhdr->size - totalbytesread);
+      }
+
+  if ( handle->file )
+  {
+  	if ( seekFile(handle, udta->atomhdr->size - totalbytesread) < 0 )
+  	{
+  	   return -1;	
+  	}
+  	else
+  	{
+  	   return udta->atomhdr->size;	
+  	}
+  }
+  else
+  {
+	  bytesread = discardData(handle, udta->atomhdr->size - totalbytesread);
+	  if (bytesread < 0)
+	    return -1;
+	  totalbytesread += bytesread;
+  }
+  return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeUDTA(userDataAtom *udta)
+ *
+ * Description:
+ *
+ *   This function frees memory for UDTA atom.
+ *
+ * Parameters:
+ *
+ *   udta       UDTA atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeUDTA(userDataAtom *udta)
+{
+  if (udta)
+  {
+    if (freeAtomHeader(udta->atomhdr) < 0)
+      return -1;
+    mp4free(udta);
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineVideoLength(MP4HandleImp handle,
+ *                                mp4_u32 *videolength)
+ *
+ * Description:
+ *
+ *   This function determines the length of video in milliseconds.
+ *
+ * Parameters:
+ *
+ *   handle       MP4 library handle
+ *   videolength  Video length is returned here
+ *
+ * Return value:
+ *
+ *   0            Success
+ *   Negative     Error
+ *
+ */
+mp4_i32 determineVideoLength(MP4HandleImp handle, mp4_u32 *videolength)
+{
+  if (!handle->moov)
+    return -1;
+
+  if (!handle->moov->mvhd)
+    return -1;
+
+  if (!handle->moov->trakVideo)
+    return -1;
+
+  if (!handle->moov->trakVideo->tkhd)
+    return -1;
+
+  /* Is timescale set? */
+  if (handle->moov->mvhd->timeScale == 0)
+    return -1;
+
+  *videolength = (mp4_u32)(((mp4_double)handle->moov->trakVideo->tkhd->duration / (mp4_double)handle->moov->mvhd->timeScale) * (mp4_double)1000);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineFrameRate(MP4HandleImp handle,
+ *                              mp4_double *framerate)
+ *
+ * Description:
+ *
+ *   This function determines the frame rate of video.
+ *
+ *   Frame rate is calculated as the average frame rate of the entire video.
+ *
+ * Parameters:
+ *
+ *   handle     MP4 library handle
+ *   framerate  Frame rate is returned here
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 determineFrameRate(MP4HandleImp handle, mp4_double *framerate)
+{
+  mp4_double numberofframes;
+  mp4_double length;
+
+
+  if (!handle)
+    return -1;
+  if (!handle->moov)
+    return -1;
+  if (!handle->moov->trakVideo)
+    return -1;
+  if (!handle->moov->trakVideo->mdia)
+    return -1;
+  if (!handle->moov->trakVideo->mdia->minf)
+    return -1;
+  if (!handle->moov->trakVideo->mdia->minf->stbl)
+    return -1;
+  if (!handle->moov->trakVideo->mdia->minf->stbl->stsz)
+    return -1;
+  if (!handle->moov->trakVideo->mdia->mdhd)
+    return -1;
+
+
+  	if (handle->moov->trakVideo->mdia->mdhd->timeScale == 0)
+    	return -1;
+  	
+  	if (handle->moov->trakVideo->mdia->mdhd->duration == 0)
+  		{
+  		*framerate = 0;
+  		}
+	else
+		{
+  		numberofframes = (mp4_double)handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount;
+  		length = (mp4_double)handle->moov->trakVideo->mdia->mdhd->duration /
+           		 (mp4_double)handle->moov->trakVideo->mdia->mdhd->timeScale;
+
+  		*framerate = numberofframes / length;			
+		}    
+
+  	return 0;
+	}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineVideoType(MP4HandleImp handle,
+ *                              mp4_u32 *videotype)
+ *
+ * Description:
+ *
+ *   This function determines the video type of the MP4.
+ *
+ * Parameters:
+ *
+ *   handle     MP4 library handle
+ *   videotype  Video type is returned here
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   -1			Error
+ *	 -2			Unknown video type
+ *
+ */
+mp4_i32 determineVideoType(MP4HandleImp handle, mp4_u32 *videotype)
+{
+  *videotype = MP4_TYPE_NONE;
+
+  if (!handle->moov)
+    return -1;
+
+  if (!handle->moov->trakVideo)
+    return -1;
+
+  if (!handle->moov->trakVideo->mdia)
+    return -1;
+
+  if (!handle->moov->trakVideo->mdia->minf)
+    return -1;
+
+  if (!handle->moov->trakVideo->mdia->minf->stbl)
+    return -1;
+
+  if (!handle->moov->trakVideo->mdia->minf->stbl->stsd)
+    return -1;
+  
+  if (handle->moov->trakVideo->mdia->minf->stbl->stsd->entryCount == 0)
+    return -1;  
+
+/* 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->mp4v[0])
+  {
+    if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->esd)
+      return -1;
+
+    if ((handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->esd->objectTypeIndication == 0x20) &&
+        ((handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->esd->stream >> 2) == 0x04))
+      *videotype = MP4_TYPE_MPEG4_VIDEO;
+  }
+  else
+  if (handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0])
+  {
+    if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263)
+      return -1;
+
+    switch (handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->d263->h263Profile)
+    {
+    case 0:
+      *videotype = MP4_TYPE_H263_PROFILE_0;
+      break;
+    case 3:
+      *videotype = MP4_TYPE_H263_PROFILE_3;
+      break;
+    default:
+      break;
+    }
+  }
+  else
+   if (handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0])
+   {
+	   if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc)
+		   return -1;
+
+	   if (handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfigSize == 0)
+		   return -1;
+
+	   /* AVC profile is in the second byte of the avcconfigrecord */
+	   switch((mp4_u8)handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfig[1]) 
+	   {
+	   case 66:
+		   *videotype = MP4_TYPE_AVC_PROFILE_BASELINE;
+		   break;
+	   case 77:
+		   *videotype = MP4_TYPE_AVC_PROFILE_MAIN;
+		   break;
+	   case 88:
+		   *videotype = MP4_TYPE_AVC_PROFILE_EXTENDED;
+		   break;
+       case 100:
+          *videotype = MP4_TYPE_AVC_PROFILE_HIGH;
+           break;
+	   default:
+		   {
+		   mp4_u8 constraintByte = (mp4_u8)handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfig[2];
+		   if ( (constraintByte & 0x80) || (constraintByte & 0x10) )
+			   {
+			   *videotype = MP4_TYPE_AVC_PROFILE_BASELINE;	
+			   }
+		   else if (constraintByte & 0x40)
+			   {
+			   *videotype = MP4_TYPE_AVC_PROFILE_MAIN;	
+			   }
+		   else if (constraintByte & 0x20)
+			   {
+			   *videotype = MP4_TYPE_AVC_PROFILE_EXTENDED;
+			   }
+		   // NOTE: Cannot reliably determine higher profiles from
+		   // the constraint flags.
+		   break;	   	
+		   }
+	   }
+	}
+   else
+       {}
+   /* Note: Read the AVC level and recreate the actual AVC profile and level in the future! */
+  if (*videotype == MP4_TYPE_NONE)
+    return -2;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineVideoResolution(MP4HandleImp handle,
+ *                                    mp4_u32 *videowidth,
+ *                                    mp4_u32 *videoheight)
+ *
+ * Description:
+ *
+ *   This function finds out the video width and height from the atom
+ *   structure.
+ *
+ * Parameters:
+ *
+ *   handle       MP4 library handle
+ *   videowidth   Video width is returned here
+ *   videoheight  Video height is returned here
+ *
+ * Return value:
+ *
+ *   0            Success
+ *   Negative     Error
+ *
+ */
+mp4_i32 determineVideoResolution(MP4HandleImp handle, mp4_u32 *videowidth, mp4_u32 *videoheight)
+{
+  mp4_u32 videotype = MP4_TYPE_NONE;
+
+
+  if (determineVideoType(handle, &videotype) < 0)
+    return -1;
+
+  if (videotype == MP4_TYPE_NONE)
+    return -1;
+
+  if (!handle->moov)
+    return -1;
+
+  if (!handle->moov->trakVideo)
+    return -1;
+
+  if (!handle->moov->trakVideo->mdia)
+    return -1;
+
+  if (!handle->moov->trakVideo->mdia->minf)
+    return -1;
+
+  if (!handle->moov->trakVideo->mdia->minf->stbl)
+    return -1;
+
+  if (!handle->moov->trakVideo->mdia->minf->stbl->stsd)
+    return -1;
+
+  if (handle->moov->trakVideo->mdia->minf->stbl->stsd->entryCount == 0)
+    return -1;  
+  
+/* Assume that the video characteristics for all the video sample entries are the same. Just get them from the first one */
+
+  if (videotype == MP4_TYPE_H263_PROFILE_0 ||
+      videotype == MP4_TYPE_H263_PROFILE_3)
+  {
+    if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0])
+      return -1;
+
+    *videowidth  = handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->width;
+    *videoheight = handle->moov->trakVideo->mdia->minf->stbl->stsd->s263[0]->height;
+  }
+  else if (videotype == MP4_TYPE_MPEG4_VIDEO)
+  {
+    if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0])
+      return -1;
+
+    *videowidth  = handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->width;
+    *videoheight = handle->moov->trakVideo->mdia->minf->stbl->stsd->mp4v[0]->height;
+  }
+  else if ( isAvcVideo(videotype) )
+  {
+    if (!handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0])
+      return -1;
+
+    *videowidth  = handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->width;
+    *videoheight = handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->height;
+  }
+  else
+  {
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineVideoTimeScale(MP4HandleImp handle,
+ *                                   mp4_u32 *timescale)
+ *
+ * Description:
+ *
+ *   This function determines the timescale of video track.
+ *
+ * Parameters:
+ *
+ *   handle     MP4 library handle
+ *   timescale  Timescale of video track is returned here
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 determineVideoTimeScale(MP4HandleImp handle, mp4_u32 *timescale)
+{
+  if (timescale == NULL)
+    return 0;
+
+  if (!handle)
+    return -1;
+  if (!handle->moov)
+    return -1;
+  if (!handle->moov->trakVideo)
+    return -1;
+  if (!handle->moov->trakVideo->mdia)
+    return -1;
+  if (!handle->moov->trakVideo->mdia->mdhd)
+    return -1;
+  if (handle->moov->trakVideo->mdia->mdhd->timeScale == 0)
+    return -1;
+
+  *timescale = handle->moov->trakVideo->mdia->mdhd->timeScale;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineAudioLength(MP4HandleImp handle,
+ *                                mp4_u32 *audiolength)
+ *
+ * Description:
+ *
+ *   This function determines the length of audio in milliseconds.
+ *
+ * Parameters:
+ *
+ *   handle       MP4 library handle
+ *   audiolength  Audio length is returned here
+ *
+ * Return value:
+ *
+ *   0            Success
+ *   Negative     Error
+ *
+ */
+mp4_i32 determineAudioLength(MP4HandleImp handle, mp4_u32 *audiolength)
+{
+  if (!handle->moov)
+    return -1;
+
+  if (!handle->moov->mvhd)
+    return -1;
+
+  if (!handle->moov->trakAudio)
+    return -1;
+
+  if (!handle->moov->trakAudio->tkhd)
+    return -1;
+
+  /* Is timescale set? */
+  if (handle->moov->mvhd->timeScale == 0)
+    return -1;
+
+  *audiolength = (mp4_u32)(((mp4_double)handle->moov->trakAudio->tkhd->duration / (mp4_double)handle->moov->mvhd->timeScale) * (mp4_double)1000);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineAudioType(MP4HandleImp handle,
+ *                              mp4_u32 *audiotype)
+ *
+ * Description:
+ *
+ *   This function determines the audio type of the MP4.
+ *
+ * Parameters:
+ *
+ *   handle     MP4 library handle
+ *   audiotype  Audio type is returned here
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   -1   		Error
+ *   -2			Unknown audiotrack
+ *
+ */
+mp4_i32 determineAudioType(MP4HandleImp handle, mp4_u32 *audiotype)
+{
+  *audiotype = MP4_TYPE_NONE;
+
+
+  if (!handle->moov)
+    return -1;
+
+  if (!handle->moov->trakAudio)
+    return -1;
+
+  if (!handle->moov->trakAudio->mdia)
+    return -1;
+
+  if (!handle->moov->trakAudio->mdia->minf)
+    return -1;
+
+  if (!handle->moov->trakAudio->mdia->minf->stbl)
+    return -1;
+
+  if (!handle->moov->trakAudio->mdia->minf->stbl->stsd)
+    return -1;
+  
+  if (handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount == 0)
+    return -1;  
+
+/* Assume that the audio type is the same for all sample entries. Just get the audio type from the first one */
+  if (handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0])
+  {
+    if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd)
+      return -1;
+
+    if ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->objectTypeIndication == 0x40) &&
+        ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->stream >> 2) == 0x05))
+      *audiotype = MP4_TYPE_MPEG4_AUDIO;
+
+   if ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->objectTypeIndication == 0xE1) &&
+     ((handle->moov->trakAudio->mdia->minf->stbl->stsd->mp4a[0]->esd->stream >> 2) == 0x05))  
+   {
+      *audiotype = MP4_TYPE_QCELP_13K;
+      handle->qcelpStoredAsMPEGAudio = MP4TRUE;
+   }
+  }
+  else if (handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[0])
+    *audiotype = MP4_TYPE_AMR_NB;
+  else if (handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[0])
+    *audiotype = MP4_TYPE_AMR_WB;
+  else if (handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[0])
+  {
+    *audiotype = MP4_TYPE_QCELP_13K;
+    handle->qcelpStoredAsMPEGAudio = MP4FALSE;
+  }
+  else
+  {
+  }
+
+  if (*audiotype == MP4_TYPE_NONE)
+    return -2;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineAudioFramesPerSample(MP4HandleImp handle,
+ *                                         mp4_u8 *framespersample)
+ *
+ * Description:
+ *
+ *   This function determines the number of audio frames in each sample.
+ *   The function works with AMR audio type only.
+ *
+ * Parameters:
+ *
+ *   handle           MP4 library handle
+ *   framespersample  Number of frames in each sample
+ *
+ * Return value:
+ *
+ *   0                Success
+ *   Negative         Error
+ *
+ */
+mp4_i32 determineAudioFramesPerSample(MP4HandleImp handle, mp4_u8 *framespersample)
+{
+  mp4_i8 sampleentryindex;
+  
+  *framespersample = 0;
+
+
+  if (!((handle->type & MP4_TYPE_AMR_NB) ||
+        (handle->type & MP4_TYPE_AMR_WB) ||
+        ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))))
+  {
+    *framespersample = 1;
+
+    return 0;
+  }
+
+
+  if (!handle->moov)
+    return -1;
+
+  if (!handle->moov->trakAudio)
+    return -1;
+
+  if (!handle->moov->trakAudio->mdia)
+    return -1;
+
+  if (!handle->moov->trakAudio->mdia->minf)
+    return -1;
+
+  if (!handle->moov->trakAudio->mdia->minf->stbl)
+    return -1;
+
+  if (!handle->moov->trakAudio->mdia->minf->stbl->stsd)
+    return -1;
+
+  if (handle->type & MP4_TYPE_AMR_NB)
+  {
+/* Now, framespersample returns the maximum frames_per_sample listed in the AMR sample entries*/
+	for (sampleentryindex = 0; (mp4_u8) sampleentryindex < handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount; sampleentryindex++)
+	{
+		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex])
+		  return -1;
+
+		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex]->damr)
+		  return -1;
+
+		if (*framespersample < handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex]->damr->framesPerSample)
+			*framespersample = handle->moov->trakAudio->mdia->minf->stbl->stsd->samr[sampleentryindex]->damr->framesPerSample;
+	}
+  }
+  else if (handle->type & MP4_TYPE_AMR_WB)
+  {
+/* Now, framespersample returns the maximum frames_per_sample listed in the AMR sample entries*/
+	for (sampleentryindex = 0; (mp4_u8)sampleentryindex < handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount; sampleentryindex++)
+	{
+		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex])
+		  return -1;
+
+		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex]->damr)
+		  return -1;
+
+		if (*framespersample < handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex]->damr->framesPerSample)
+ 		  *framespersample = handle->moov->trakAudio->mdia->minf->stbl->stsd->sawb[sampleentryindex]->damr->framesPerSample;
+	}
+  }
+  else if ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))
+  {
+/* Now, framespersample returns the maximum frames_per_sample listed in the QCELP-13K sample entries*/
+	for (sampleentryindex = 0; (mp4_u8)sampleentryindex < handle->moov->trakAudio->mdia->minf->stbl->stsd->entryCount; sampleentryindex++)
+	{
+		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex])
+		  return -1;
+
+		if (!handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex]->dqcp)
+		  return -1;
+
+		if (*framespersample < handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex]->dqcp->framesPerSample)
+		  *framespersample = handle->moov->trakAudio->mdia->minf->stbl->stsd->sqcp[sampleentryindex]->dqcp->framesPerSample;
+	}
+  }
+  else
+  {
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineAudioTimeScale(MP4HandleImp handle,
+ *                                   mp4_u32 *timescale)
+ *
+ * Description:
+ *
+ *   This function determines the timescale of audio track.
+ *
+ * Parameters:
+ *
+ *   handle     MP4 library handle
+ *   timescale  Timescale of audio track is returned here
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 determineAudioTimeScale(MP4HandleImp handle, mp4_u32 *timescale)
+{
+  if (timescale == NULL)
+    return 0;
+
+  if (!handle)
+    return -1;
+  if (!handle->moov)
+    return -1;
+  if (!handle->moov->trakAudio)
+    return -1;
+  if (!handle->moov->trakAudio->mdia)
+    return -1;
+  if (!handle->moov->trakAudio->mdia->mdhd)
+    return -1;
+
+
+  if (handle->moov->trakAudio->mdia->mdhd->timeScale == 0)
+    return -1;
+
+  *timescale = handle->moov->trakAudio->mdia->mdhd->timeScale;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineAudioAverageBitRate(MP4HandleImp handle,
+ *                                        mp4_u32 *averagebitrate)
+ *
+ * Description:
+ *
+ *   This function determines the average bitrate of the audio in bits per
+ *   second.
+ *
+ *   The average is calculated so that the audio data length is divided by
+ *   the length of the  audio track.
+ *
+ * Parameters:
+ *
+ *   handle                MP4 library handle
+ *   averagebitrate        Result is returned here
+ *
+ * Return value:
+ *
+ *   0           Success
+ *   Negative    Error
+ *
+ */
+mp4_i32 determineAudioAverageBitRate(MP4HandleImp handle, mp4_u32 *averagebitrate)
+	{
+	mp4_u32 audiosize = 0;
+
+  	if (!handle->moov)
+  		{
+  		return -1;	
+  		}
+    	
+  	if (handle->moov->trakAudio)
+  		{
+		if (!handle->moov->trakAudio->mdia)
+			{
+			return -1;		
+			}
+					
+		if (!handle->moov->trakAudio->mdia->minf)
+			{
+			return -1;	
+			}
+		
+		if (!handle->moov->trakAudio->mdia->minf->stbl)
+			{
+			return -1;				
+			}
+
+		if (!handle->moov->trakAudio->mdia->minf->stbl->stsz)
+			{
+			return -1;				
+			}
+
+		if (handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize != 0)
+			{
+			audiosize += (handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount *
+	                   	 handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize);			
+			}
+	    else
+	    	{
+	      	mp4_u32 i;
+	      	for (i = 0; i < handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount; i++)
+	      		{
+	        	audiosize += handle->moov->trakAudio->mdia->minf->stbl->stsz->entrySize[i];      			
+	      		}
+	    	}
+	  	}
+	else
+		{
+		return -1;  		
+		}
+
+  	if (!handle->moov->trakAudio->mdia->mdhd)
+  		{
+    	return -1;  			
+  		}
+  	
+  	if (!handle->moov->trakAudio->mdia->mdhd->timeScale)
+  		{
+		return -1;  			
+  		}
+
+  	if (handle->moov->trakAudio->mdia->mdhd->duration == 0)
+  		{
+  		*averagebitrate = 0;
+  		}
+	else
+		{
+		*averagebitrate = (mp4_u32)((mp4_double)8 *
+		                  (mp4_double)audiosize /
+		                  ((mp4_double)handle->moov->trakAudio->mdia->mdhd->duration /
+		                  (mp4_double)handle->moov->trakAudio->mdia->mdhd->timeScale));
+		}  	
+
+  	return 0;
+	}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineStreamSize(MP4HandleImp handle,
+ *                              mp4_u32 *streamsize)
+ *
+ * Description:
+ *
+ *   This function determines the size of media data in MP4 file/stream.
+ *
+ * Parameters:
+ *
+ *   handle      MP4 library handle
+ *   streamsize  Size of data
+ *
+ * Return value:
+ *
+ *   0           Success
+ *   Negative    Error
+ *
+ */
+mp4_i32 determineStreamSize(MP4HandleImp handle, mp4_u32 *streamsize)
+{
+  *streamsize = 0;
+
+  if (!handle->moov)
+    return -1;
+
+  if ((!handle->moov->trakAudio) && (!handle->moov->trakVideo))
+    return -1;
+
+  if (handle->moov->trakAudio)
+  {
+    if (!handle->moov->trakAudio->mdia)
+      return -1;
+
+    if (!handle->moov->trakAudio->mdia->minf)
+      return -1;
+
+    if (!handle->moov->trakAudio->mdia->minf->stbl)
+      return -1;
+
+    if (!handle->moov->trakAudio->mdia->minf->stbl->stsz)
+      return -1;
+
+    if (handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize != 0)
+      *streamsize += handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount *
+                     handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleSize;
+    else
+    {
+      mp4_u32 i;
+
+      for (i = 0; i < handle->moov->trakAudio->mdia->minf->stbl->stsz->sampleCount; i++)
+        *streamsize += handle->moov->trakAudio->mdia->minf->stbl->stsz->entrySize[i];
+    }
+  }
+
+  if (handle->moov->trakVideo)
+  {
+    if (!handle->moov->trakVideo->mdia)
+      return -1;
+
+    if (!handle->moov->trakVideo->mdia->minf)
+      return -1;
+
+    if (!handle->moov->trakVideo->mdia->minf->stbl)
+      return -1;
+
+    if (!handle->moov->trakVideo->mdia->minf->stbl->stsz)
+      return -1;
+
+    if (handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleSize != 0)
+      *streamsize += handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount *
+                     handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleSize;
+    else
+    {
+      mp4_u32 i;
+
+      for (i = 0; i < handle->moov->trakVideo->mdia->minf->stbl->stsz->sampleCount; i++)
+        *streamsize += handle->moov->trakVideo->mdia->minf->stbl->stsz->entrySize[i];
+    }
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineStreamAverageBitRate(MP4HandleImp handle,
+ *                                         mp4_u32 *streamaveragebitrate,
+ *                                         mp4_u32 streamsize)
+ *
+ * Description:
+ *
+ *   This function determines the average bitrate of the stream in bits per
+ *   second.
+ *
+ *   The average is calculated so that the media data length is divided by
+ *   the length of the presentation.
+ *
+ * Parameters:
+ *
+ *   handle                MP4 library handle
+ *   streamaveragebitrate  Result is returned here
+ *   streamsize            Size of media data in bytes
+ *
+ * Return value:
+ *
+ *   0           Success
+ *   Negative    Error
+ *
+ */
+mp4_i32 determineStreamAverageBitRate(MP4HandleImp handle, mp4_u32 *streamaveragebitrate, mp4_u32 streamsize)
+{
+  if (!handle->moov)
+    return -1;
+
+  if (!handle->moov->mvhd)
+    return -1;
+
+  if (!handle->moov->mvhd->timeScale)
+    return -1;
+
+  if (handle->moov->mvhd->atomhdr->version == 1) /* 64 bit */
+      {
+      if (!handle->moov->mvhd->duration64)
+        return -1;
+     
+      *streamaveragebitrate = (mp4_u32)((mp4_double)8 * (mp4_double)streamsize /
+                                        ((mp4_double)handle->moov->mvhd->duration64 / handle->moov->mvhd->timeScale));      
+      }
+  else /* 32 bit */
+      {
+      if (!handle->moov->mvhd->duration)
+        return -1;
+
+      *streamaveragebitrate = (mp4_u32)((mp4_double)8 * (mp4_double)streamsize /
+                                        ((mp4_double)handle->moov->mvhd->duration / handle->moov->mvhd->timeScale));      
+      }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 advanceVideoFrame(MP4HandleImp handle,
+ *                             trackAtom *trak)
+ *
+ * Description:
+ *
+ *   This function Advances one video frame and finds the frame offset
+ *   and size.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   trak      TRAK atom pointer
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   Negative  Error
+ *
+ */
+mp4_i32 advanceVideoFrame(MP4HandleImp handle, trackAtom *trak)
+{
+  if (!trak->mdia)
+    return -1;
+  if (!trak->mdia->minf)
+    return -1;
+  if (!trak->mdia->minf->stbl)
+    return -1;
+  if (!trak->mdia->minf->stbl->stsz)
+    return -1;
+
+  /* Are there frames (samples) left? */
+
+  if (trak->mdia->minf->stbl->stsz->sampleCount > handle->videoSampleNum)
+    handle->videoSampleNum++;
+  else
+    return -2;
+
+  /* Find the size of the frame (sample) */
+
+  if (resolveVideoSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
+    return -1;
+
+  /* Find the offset of the frame (sample) */
+
+  if (resolveVideoSampleOffset(handle, trak->mdia->minf->stbl) < 0)
+    return -1;
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 resolveVideoSampleOffset(MP4HandleImp handle,
+ *                                    sampleTableAtom *stbl)
+ *
+ * Description:
+ *
+ *   This function finds the offset of the current video sample.
+ *   The result is stored in handle->videoFrameOffset.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   stbl      STBL atom pointer
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   Negative  Error
+ *
+ */
+mp4_i32 resolveVideoSampleOffset(MP4HandleImp handle, sampleTableAtom *stbl)
+	{
+	mp4_u32  chunk;            /* Current chunk number */
+	mp4_u32  sample;           /* Number of samples before this run of chunks */
+	mp4_u32  entry;            /* Current entry in sample to chunk */
+	mp4_u32  chunksInThisRun;  /* Number of chunks in this run */
+	mp4_u32  sampleNrInChunk = 0;	/* Sample number in the chunk */
+
+	if (!stbl->stsc || stbl->stsc->entryCount == 0)
+		{
+		return -1;
+		}
+	
+	if (!stbl->stco || stbl->stco->entryCount == 0)
+		{
+		return -1;
+		}
+
+	chunk = 0;
+	sample = 0;
+	entry = 0;
+
+  for (;;)
+		{
+		/* Find how many chunks there are in this run */
+		
+		if (stbl->stsc->entryCount > entry + 1) /* Not last chunk run */
+			{
+			chunksInThisRun = stbl->stsc->firstChunk[entry + 1] - stbl->stsc->firstChunk[entry];
+			}
+		else
+			{
+			chunksInThisRun = stbl->stco->entryCount - chunk + 1;
+			}
+
+		if (handle->videoSampleNum <= chunksInThisRun * stbl->stsc->samplesPerChunk[entry] + sample)
+			{
+			chunk += (handle->videoSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) / stbl->stsc->samplesPerChunk[entry];
+			sampleNrInChunk = (handle->videoSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) % stbl->stsc->samplesPerChunk[entry];
+	  
+			/* The following functions are needed for multiple sample entry support */
+			handle->videoSampleEntryIndex = stbl->stsc->sampleDescriptionIndex[entry];
+
+			break; /* We know the chunk number and sample number in chunk AND the sample entry index of the current sample*/
+			}
+		else
+			{
+			chunk += chunksInThisRun;
+			sample += chunksInThisRun * stbl->stsc->samplesPerChunk[entry];
+			}
+
+	    entry++;
+		}
+
+	if (chunk > stbl->stco->entryCount)
+		{
+		return -1;
+		}
+
+	handle->videoFrameOffset = getChunkOffset(stbl, chunk - 1);
+
+	if (sampleNrInChunk)
+		{
+		if (stbl->stsz->sampleSize)
+			{
+			handle->videoFrameOffset += stbl->stsz->sampleSize * sampleNrInChunk;
+			}
+		else
+			{
+			if (stbl->stsz->sampleCount == 0)
+				{
+				return -1;
+				}
+			while (sampleNrInChunk)
+				{
+				handle->videoFrameOffset += stbl->stsz->entrySize[handle->videoSampleNum - sampleNrInChunk - 1];
+				sampleNrInChunk--;
+				}
+			}
+		}
+		
+		
+	//PRINT((_L("videoFrameOffset %Lu"), handle->videoFrameOffset));
+	return 0;
+	}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 resolveVideoSampleSize(MP4HandleImp handle,
+ *                                  sampleSizeAtom *stsz)
+ *
+ * Description:
+ *
+ *   This function finds the size of the current video sample.
+ *   The result is stored in handle->videoFrameSize.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   stsz      STSZ atom pointer
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   Negative  Error
+ *
+ */
+mp4_i32 resolveVideoSampleSize(MP4HandleImp handle, sampleSizeAtom *stsz)
+	{
+	if (stsz->sampleSize)
+		{
+		handle->videoFrameSize = stsz->sampleSize;
+		return 0;
+		}
+
+	if (stsz->sampleCount == 0)
+		{
+		return -1;
+		}
+	handle->videoFrameSize = stsz->entrySize[handle->videoSampleNum - 1];
+
+	return 0;
+	}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 fetchVideoFrame(MP4HandleImp handle,
+ *                           trackAtom *trak,
+ *                           mp4_u8 *buffer,
+ *                           mp4_u32 buffersize,
+ *                           mp4_u32 *framesize,
+ *                           mp4_u32 *timestamp,
+ *                           mp4_bool *keyframe,
+ *                           mp4_u32 *timestamp2)
+ *
+ * Description:
+ *
+ *   This function fetches one video frame from a file.
+ *
+ * Parameters:
+ *
+ *   handle       MP4 library handle
+ *   trak         TRAK atom pointer
+ *   buffer       Video frame is retuned here
+ *   buffersize   Size of buffer
+ *   framesize    Size of returned frame in bytes
+ *   timestamp    Frame time in milliseconds (from the beginning of the
+ *                presentation)
+ *   keyframe     True if intra frame, false otherwise
+ *   timestamp2   Frame time in timescale (from the beginning of the
+ *                presentation)
+ *
+ * Return value:
+ *
+ *   0            Success
+ *   Negative     Error
+ *
+ */
+mp4_i32 fetchVideoFrame(MP4HandleImp handle,
+                        trackAtom *trak,
+                        mp4_u8 *buffer,
+                        mp4_u32 buffersize,
+                        mp4_u32 *framesize,
+                        mp4_u32 *timestamp,
+                        mp4_bool *keyframe,
+                        mp4_u32 *timestamp2)
+{
+  mp4_i32 bytesread;
+
+
+  if (!trak->mdia)
+    return -1;
+
+  if (handle->file) /* Input is in a file */
+  {
+    if (seekFileAbs(handle, handle->videoFrameOffset) != 0)
+      return -4;
+  }
+  else /* Input is a stream */
+  {
+      if (handle->videoFrameOffset + handle->videoFrameSize <= getCumulativeBufferedBytes(handle))
+      {
+          handle->absPosition = handle->videoFrameOffset;
+      }
+      else
+        return -3;
+  }
+
+  if (handle->videoFrameSize > buffersize)
+  {
+    *framesize = handle->videoFrameSize;
+    return -2;
+  }
+
+  bytesread = readData(handle, buffer, handle->videoFrameSize);
+  switch (bytesread)
+  {
+    case -1:
+      return -1;
+    case -2:
+      return -4;
+    case -10:
+      return -3;
+    default:
+      break;
+  }
+
+  if (handle->file)
+    if (handle->videoFrameOffset + handle->videoFrameSize - 1 > handle->lastAccessedPosInFile)
+      handle->lastAccessedPosInFile = handle->videoFrameOffset + handle->videoFrameSize - 1;
+
+  *framesize = handle->videoFrameSize;
+
+  if (convertVideoSampleToTime(handle, trak->mdia, timestamp, timestamp2) < 0)
+    return -1;
+
+  if (isVideoFrameKeyFrame(handle, trak, keyframe) < 0)
+    return -1;
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 fetchVideoFrameAsync(MP4HandleImp handle,
+ *                           	  trackAtom *trak,
+ *                           	  mp4_u8 *buffer,
+ *                           	  mp4_u32 buffersize,
+ *
+ * Description:
+ *
+ *   This function fetches one video frame from a file asyncronously.
+ *
+ * Parameters:
+ *
+ *   handle       MP4 library handle
+ *   trak         TRAK atom pointer
+ *   buffer       Video frame is retuned here
+ *   buffersize   Size of buffer
+ *
+ * Return value:
+ *
+ *   0            Success
+ *   Negative     Error
+ *
+ */
+mp4_i32 fetchVideoFrameAsync(MP4HandleImp handle,
+                        trackAtom *trak,
+                        mp4_u8 *buffer,
+                        mp4_u32 *buffersize)
+{
+  if (trak)
+	{
+	if (!trak->mdia)
+		return -1;
+	}
+  else
+    {
+	return -1;
+    }
+  
+  if (handle->videoFrameSize > *buffersize)
+  {
+    *buffersize = handle->videoFrameSize;
+    return -2;
+  }
+  
+  if ( handle->asyncReader == NULL )
+  	{
+	TRAPD(error, handle->asyncReader = CFileAsyncParser::NewL( handle, (RFile64&)handle->rfile ));
+	if ( error != KErrNone )
+		{
+		if (error == KErrNoMemory )
+			{
+			return MP4_OUT_OF_MEMORY;    		
+			}
+		else
+			{
+			return -1;
+			}
+		}  	
+  	}
+  
+  return handle->asyncReader->ReadVideoFrame( buffer, handle->videoFrameOffset, handle->videoFrameSize);
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 isVideoFrameKeyFrame(MP4HandleImp handle,
+ *                                trackAtom *trak,
+ *                                mp4_bool *keyframe)
+ *
+ * Description:
+ *
+ *   This function determines if the current frame is a keyframe (intra)
+ *   or not.
+ *
+ * Parameters:
+ *
+ *   handle       MP4 library handle
+ *   trak         TRAK atom pointer
+ *   keyframe     Has a value of MP4TRUE if current frame is a keyframe
+ *                (intra) or MP4FALSE otherwise
+ *
+ * Return value:
+ *
+ *   0            Success
+ *   Negative     Error
+ *
+ */
+mp4_i32 isVideoFrameKeyFrame(MP4HandleImp handle, trackAtom *trak, mp4_bool *keyframe)
+{
+  mp4_u32  i;
+
+
+  *keyframe = MP4FALSE;
+
+  if (!trak->mdia)
+    return -1;
+
+  if (!trak->mdia->minf)
+    return -1;
+
+  if (!trak->mdia->minf->stbl)
+    return -1;
+
+  if (!trak->mdia->minf->stbl->stss)
+  {
+    *keyframe = MP4TRUE;
+
+    return 0;
+  }
+
+  for (i = 0; i < trak->mdia->minf->stbl->stss->entryCount; i++)
+  {
+    if (trak->mdia->minf->stbl->stss->sampleNumber[i] == handle->videoSampleNum)
+    {
+      *keyframe = MP4TRUE;
+      break;
+    }
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 convertVideoSampleToTime(MP4HandleImp handle,
+ *                                    mediaAtom *mdia,
+ *                                    mp4_u32 *timestamp,
+ *                                    mp4_u32 *timestamp2)
+ *
+ * Description:
+ *
+ *   This function converts a video sample to corresponding time.
+ *
+ * Parameters:
+ *
+ *   handle       MP4 library handle
+ *   mdia         MDIA atom pointer
+ *   timestamp    Time in milliseconds is returned here
+ *   timestamp2   Time in timescale is returned here
+ *
+ * Return value:
+ *
+ *   0            Success
+ *   Negative     Error
+ *
+ */
+mp4_i32 convertVideoSampleToTime(MP4HandleImp handle,
+                                 mediaAtom *mdia,
+                                 mp4_u32 *timestamp,
+                                 mp4_u32 *timestamp2)
+	{
+	mp4_u32      tmptime;
+	mp4_double   tmptime2;
+	mp4_u32      sample;
+	mp4_u32      entry;
+
+	if (!mdia->mdhd)
+		{
+		return -1;
+		}
+	if (!mdia->minf)
+		{
+		return -1;
+		}
+	if (!mdia->minf->stbl)
+		{
+		return -1;
+		}
+	if (!mdia->minf->stbl->stts)
+		{
+		return -1;
+		}
+	if (mdia->minf->stbl->stts->entryCount == 0)
+		{
+		return -1;
+		}
+
+	tmptime = 0;
+	sample = 0;
+	entry = 0;
+
+	for (;;)
+		{
+		if (sample + mdia->minf->stbl->stts->sampleCount[entry] < handle->videoSampleNum)
+			{
+			sample += mdia->minf->stbl->stts->sampleCount[entry];
+			tmptime += (mdia->minf->stbl->stts->sampleCount[entry] * mdia->minf->stbl->stts->sampleDelta[entry]);
+			entry++;
+			if (entry == mdia->minf->stbl->stts->entryCount)
+				{
+				return -1;
+				}
+			}
+		else
+			{
+			tmptime += ((handle->videoSampleNum - sample - 1) * mdia->minf->stbl->stts->sampleDelta[entry]);
+			break;
+			}
+		}
+	
+  	if (mdia->mdhd->timeScale == 0)
+  		{
+  		return -1;
+  		}
+
+  	if (timestamp2)
+  		{
+  		*timestamp2 = tmptime;
+  		}
+
+  	tmptime2 = (mp4_double)tmptime * (mp4_double)1000 / (mp4_double)mdia->mdhd->timeScale + (mp4_double)0.5;
+
+  	*timestamp = (mp4_u32)tmptime2;
+
+  	return 0;
+	}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 advanceAudioSample(MP4HandleImp handle,
+ *                              trackAtom *trak)
+ *
+ * Description:
+ *
+ *   This function advances one audio sample and finds the sample
+ *   offset and sample size.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   trak      TRAK atom pointer
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   Negative  Error
+ *
+ */
+mp4_i32 advanceAudioSample(MP4HandleImp handle,
+                           trackAtom *trak)
+{
+  if (!trak->mdia)
+    return -1;
+  if (!trak->mdia->minf)
+    return -1;
+  if (!trak->mdia->minf->stbl)
+    return -1;
+  if (!trak->mdia->minf->stbl->stsz)
+    return -1;
+
+
+  /* Are there samples left? */
+
+  if (trak->mdia->minf->stbl->stsz->sampleCount > handle->audioSampleNum)
+    handle->audioSampleNum++;
+  else
+    return -2;
+
+  /* Find the size of the sample */
+
+  if (resolveAudioSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
+    return -1;
+
+  /* Find the offset of the sample */
+
+  if (resolveAudioSampleOffset(handle, trak->mdia->minf->stbl) < 0)
+    return -1;
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 resolveAudioSampleOffset(MP4HandleImp handle,
+ *                                    sampleTableAtom *stbl)
+ *
+ * Description:
+ *
+ *   This function finds the offset of the current audio sample.
+ *   The result is stored in handle->audioSampleOffset.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   stbl      STBL atom pointer
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   Negative  Error
+ *
+ */
+mp4_i32 resolveAudioSampleOffset(MP4HandleImp handle, sampleTableAtom *stbl)
+{
+  mp4_u32  chunk;            /* Current chunk number */
+  mp4_u32  sample;            /* Number of samples before this run of chunks */
+  mp4_u32  entry;            /* Current entry in sample to chunk */
+  mp4_u32 chunksInThisRun;  /* Number of chunks in this run */
+  mp4_u32  sampleNrInChunk;  /* Sample number in the chunk */
+
+
+  if (!stbl->stsc || stbl->stsc->entryCount == 0)
+    return -1;
+  if (!stbl->stco || stbl->stco->entryCount == 0)
+    return -1;
+
+  chunk = 0;
+  sample = 0;
+  entry = 0;
+
+  for (;;)
+  {
+    /* Find how many chunks there are in this run */
+
+    if (stbl->stsc->entryCount > entry + 1) /* Not last chunk run */
+    {
+      chunksInThisRun = stbl->stsc->firstChunk[entry + 1] -
+                        stbl->stsc->firstChunk[entry];
+    }
+    else
+      chunksInThisRun = stbl->stco->entryCount - chunk + 1;
+
+
+    if (handle->audioSampleNum <= chunksInThisRun * stbl->stsc->samplesPerChunk[entry] + sample)
+    {
+      chunk += (handle->audioSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) / stbl->stsc->samplesPerChunk[entry];
+      sampleNrInChunk = (handle->audioSampleNum - sample + stbl->stsc->samplesPerChunk[entry] - 1) % stbl->stsc->samplesPerChunk[entry];
+
+	  /* The following functions are needed for multiple sample entry support */
+	  handle->audioSampleEntryIndex = stbl->stsc->sampleDescriptionIndex[entry];
+
+      break; /* We know the chunk number and sample number in chunk AND the sample entry index of the current sample*/
+    }
+    else
+    {
+      chunk += chunksInThisRun;
+      sample += chunksInThisRun * stbl->stsc->samplesPerChunk[entry];
+    }
+
+    entry++;
+  }
+
+  if (chunk > stbl->stco->entryCount)
+    return -1;
+
+  handle->audioSampleOffset = getChunkOffset(stbl, chunk - 1);
+
+  	if (sampleNrInChunk)
+  		{
+  		if (stbl->stsz->sampleSize)
+  			{
+  			handle->audioSampleOffset += stbl->stsz->sampleSize * sampleNrInChunk;
+  			}
+  		else
+  			{
+  			if (stbl->stsz->sampleCount == 0)
+  				{
+  				// ensure there are entries in the entrySize array
+  				return -1;
+  				}
+    
+  			while (sampleNrInChunk)
+  				{
+  				handle->audioSampleOffset += stbl->stsz->entrySize[handle->audioSampleNum - sampleNrInChunk - 1];
+  				sampleNrInChunk--;
+  				}
+  			}
+  		}
+  		
+  //PRINT((_L("audioSampleOffset %Lu"), handle->audioSampleOffset));
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 resolveAudioSampleSize(MP4HandleImp handle,
+ *                                  sampleSizeAtom *stsz)
+ *
+ * Description:
+ *
+ *   This function finds the size of the current audio sample.
+ *   The result is stored in handle->audioSampleSize.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   stsz      STSZ atom pointer
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   Negative  Error
+ *
+ */
+mp4_i32 resolveAudioSampleSize(MP4HandleImp handle, sampleSizeAtom *stsz)
+	{
+	if (stsz->sampleSize)
+		{
+		handle->audioSampleSize = stsz->sampleSize;
+		return 0;
+		}
+
+	if (stsz->sampleCount == 0)
+		{
+		return -1;
+		}
+	handle->audioSampleSize = stsz->entrySize[handle->audioSampleNum - 1];
+
+	return 0;
+	}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 fetchAudioSample(MP4HandleImp handle,
+ *                            trackAtom *trak,
+ *                            mp4_u8 *buffer,
+ *                            mp4_u32 buffersize,
+ *                            mp4_u32 *framesize,
+ *                            mp4_u32 *timestamp,
+ *                            mp4_u32 *returnedframes,
+ *                            mp4_u32 *timestamp2)
+ *
+ * Description:
+ *
+ *   This function fetches one audio sample from a file.
+ *
+ *   Note: returnedframes may differ from the correct value when accessing
+ *         the last audio sample.
+ *
+ * Parameters:
+ *
+ *   handle           MP4 library handle
+ *   trak             TRAK atom pointer
+ *   buffer           Audio frame is retuned here
+ *   buffersize       Size of buffer
+ *   framesize        Size of returned frame in bytes
+ *   timestamp        Frame time in milliseconds (from the beginning of the
+ *                    presentation)
+ *   returnedframes   Number of frames returned, of 0 if not known
+ *   timestamp2       Frame time in timescale (from the beginning of the
+ *                    presentation)
+ *
+ * Return value:
+ *
+ *   0                Success
+ *   Negative         Error
+ *
+ */
+mp4_i32 fetchAudioSample(MP4HandleImp handle,
+                         trackAtom *trak,
+                         mp4_u8 *buffer,
+                         mp4_u32 buffersize,
+                         mp4_u32 *framesize,
+                         mp4_u32 *timestamp,
+                         mp4_u32 *returnedframes,
+                         mp4_u32 *timestamp2)
+{
+  mp4_i32 bytesread;
+  mp4_i32 frameLength;
+  mp4_u32 numOfFrames;
+  mp4_u8 *framepointer;
+  mp4_u32 rawAmrFrameLength[16] = {13,14,16,18,20,21,27,32,6,0,0,0,0,0,0,1};
+
+  if (!trak->mdia)
+    return -1;
+
+  if (handle->file) /* Input is in a file */
+  {
+    if (seekFileAbs(handle, handle->audioSampleOffset) != 0)
+      return -4;
+  }
+  else /* Input is a stream */
+  {
+      if (handle->audioSampleOffset + handle->audioSampleSize <= getCumulativeBufferedBytes(handle))
+      {
+          handle->absPosition = handle->audioSampleOffset;
+      }
+      else
+        return -3;
+  }
+
+  if (handle->audioSampleSize > buffersize)
+  {
+    *framesize = handle->audioSampleSize;
+    return -2;
+  }
+
+  bytesread = readData(handle, buffer, handle->audioSampleSize);
+  switch (bytesread)
+  {
+    case -1:
+      return -1;
+    case -2:
+      return -4;
+    case -10:
+      return -3;
+    default:
+      break;
+  }
+
+  if (handle->file)
+    if (handle->audioSampleOffset + handle->audioSampleSize - 1 > handle->lastAccessedPosInFile)
+      handle->lastAccessedPosInFile = handle->audioSampleOffset + handle->audioSampleSize - 1;
+
+  *framesize = handle->audioSampleSize;
+  if (convertAudioSampleToTime(handle, trak->mdia, timestamp, timestamp2) < 0)
+    return -1;
+
+  *returnedframes = 0;
+
+  /* AMR */
+  if (trak->mdia->minf)
+    if (trak->mdia->minf->stbl)
+      if (trak->mdia->minf->stbl->stsd)
+        if (handle->type & MP4_TYPE_AMR_NB)
+        {
+            framepointer = buffer;
+            numOfFrames = 0;
+            while ( bytesread > 0 )
+            {
+                frameLength = rawAmrFrameLength[(TInt)(((*framepointer) & 0x78) >> 3)];
+                if ( frameLength == 0)
+                {
+                    return -4;
+                }
+                bytesread -= frameLength;
+                framepointer += frameLength;
+                numOfFrames++;
+            }
+            *returnedframes = numOfFrames;
+
+		  /* Return the number of sample entries listed for this particular sample entry index 
+          if (trak->mdia->minf->stbl->stsd->samr[handle->audioSampleEntryIndex - 1])
+            if (trak->mdia->minf->stbl->stsd->samr[handle->audioSampleEntryIndex - 1]->damr)
+              *returnedframes = trak->mdia->minf->stbl->stsd->samr[handle->audioSampleEntryIndex - 1]->damr->framesPerSample;*/
+        }
+        else if (handle->type & MP4_TYPE_AMR_WB)
+        {
+		  /* Return the number of sample entries listed for this particular sample entry index */
+          if (trak->mdia->minf->stbl->stsd->sawb[handle->audioSampleEntryIndex - 1])
+            if (trak->mdia->minf->stbl->stsd->sawb[handle->audioSampleEntryIndex - 1]->damr)
+              *returnedframes = trak->mdia->minf->stbl->stsd->sawb[handle->audioSampleEntryIndex - 1]->damr->framesPerSample;
+        }
+        else
+        {
+        }
+
+  /* MPEG-4 audio */
+  if (trak->mdia->minf)
+    if (trak->mdia->minf->stbl)
+      if (trak->mdia->minf->stbl->stsd)
+        if (trak->mdia->minf->stbl->stsd->mp4a[handle->audioSampleEntryIndex - 1])
+          *returnedframes = 1;
+
+  /* QCELP 13K as QCELPSampleEntry*/
+  if (trak->mdia->minf)
+    if (trak->mdia->minf->stbl)
+      if (trak->mdia->minf->stbl->stsd)
+        if ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))
+        {
+		  /* Return the number of sample entries listed for this particular sample entry index */
+          if (trak->mdia->minf->stbl->stsd->sqcp[handle->audioSampleEntryIndex - 1])
+            if (trak->mdia->minf->stbl->stsd->sqcp[handle->audioSampleEntryIndex - 1]->dqcp)
+              *returnedframes = trak->mdia->minf->stbl->stsd->sqcp[handle->audioSampleEntryIndex - 1]->dqcp->framesPerSample;
+        }
+
+  /* QCELP 13K as MPEG-4 audio */
+  if (trak->mdia->minf)
+    if (trak->mdia->minf->stbl)
+      if (trak->mdia->minf->stbl->stsd)
+        if (trak->mdia->minf->stbl->stsd->mp4a[handle->audioSampleEntryIndex - 1])
+          *returnedframes = 1;
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 fetchAudioSampleAsync(MP4HandleImp handle,
+ *                            trackAtom *trak,
+ *                            mp4_u8 *buffer,
+ *                            mp4_u32 buffersize,
+ *
+ * Description:
+ *
+ *   This function fetches one audio sample from a file asyncronously.
+ *
+ * Parameters:
+ *
+ *   handle           MP4 library handle
+ *   trak             TRAK atom pointer
+ *   buffer           Audio frame is retuned here
+ *   buffersize       Size of buffer
+ *
+ * Return value:
+ *
+ *   0                Success
+ *   Negative         Error
+ *
+ */
+mp4_i32 fetchAudioSampleAsync(MP4HandleImp handle,
+                         	  trackAtom *trak,
+                         	  mp4_u8 *buffer,
+                         	  mp4_u32 *buffersize)
+{
+  if (trak)
+	{
+	if (!trak->mdia)
+		return -1;
+	}
+  else
+    {
+	return -1;
+    }
+  
+  if (handle->audioSampleSize > *buffersize)
+		{
+		*buffersize = handle->audioSampleSize;
+		return -2;
+		}
+  
+  if (!handle->file) // Other input than file is not supported
+	  {
+	  return -1;
+	  }
+  
+  if ( handle->asyncReader == NULL )
+  	{
+	TRAPD(error, handle->asyncReader = CFileAsyncParser::NewL( handle, (RFile64&)handle->rfile ));
+	if ( error != KErrNone )
+		{
+		if (error == KErrNoMemory )
+			{
+			return MP4_OUT_OF_MEMORY;    		
+			}
+		else
+			{
+			return -1;
+			}
+		}  	
+  	}
+    
+  return handle->asyncReader->ReadAudioFrames( buffer, handle->audioSampleOffset, handle->audioSampleSize);
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 convertAudioSampleToTime(MP4HandleImp handle,
+ *                                    mediaAtom *mdia,
+ *                                    mp4_u32 *timestamp,
+ *                                    mp4_u32 *timestamp2)
+ *
+ * Description:
+ *
+ *   This function converts an audio sample to corresponding time.
+ *
+ * Parameters:
+ *
+ *   handle       MP4 library handle
+ *   mdia         MDIA atom pointer
+ *   timestamp    Time in milliseconds is returned here
+ *   timestamp2   Time in timescale is returned here
+ *
+ * Return value:
+ *
+ *   0            Success
+ *   Negative     Error
+ *
+ */
+mp4_i32 convertAudioSampleToTime(MP4HandleImp handle,
+                                 mediaAtom *mdia,
+                                 mp4_u32 *timestamp,
+                                 mp4_u32 *timestamp2)
+	{
+	mp4_u32      tmptime;
+	mp4_double  tmptime2;
+	mp4_u32      sample;
+	mp4_u32      entry;
+
+  	if (!mdia->mdhd)
+  		{
+  		return -1;
+  		}
+  	if (!mdia->minf)
+  		{
+  		return -1;
+  		}
+  	if (!mdia->minf->stbl)
+  		{
+  		return -1;
+  		}
+  	if (!mdia->minf->stbl->stts)
+  		{
+  		return -1;
+  		}
+  	if (mdia->minf->stbl->stts->entryCount == 0)
+  		{
+  		return -1;
+  		}
+
+  	tmptime = 0;
+  	sample = 0;
+  	entry = 0;
+
+  	for (;;)
+  		{
+  		if (sample + mdia->minf->stbl->stts->sampleCount[entry] < handle->audioSampleNum)
+  			{
+  			sample += mdia->minf->stbl->stts->sampleCount[entry];
+  			tmptime += mdia->minf->stbl->stts->sampleCount[entry] *
+                 	mdia->minf->stbl->stts->sampleDelta[entry];
+  			entry++;
+  			
+  			if (entry == mdia->minf->stbl->stts->entryCount)
+  				return -1;
+  			}
+  		else
+  			{
+  			tmptime += (handle->audioSampleNum - sample - 1) * mdia->minf->stbl->stts->sampleDelta[entry];
+  			break;
+  			}
+  		}
+
+  	if (mdia->mdhd->timeScale == 0)
+  		{
+  		return -1;
+  		}
+
+  	if (timestamp2)
+  		{
+  		*timestamp2 = tmptime;
+  		}
+
+  	tmptime2 = (mp4_double)tmptime * (mp4_double)1000 / (mp4_double)mdia->mdhd->timeScale + (mp4_double)0.5;
+
+  	*timestamp = (mp4_u32)tmptime2;
+
+  	return 0;
+	}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 convertTimeToSample(MP4HandleImp handle,
+ *                               trackAtom *trak,
+ *                               mp4_u32 position,
+ *                               mp4_u32 *sample)
+ *
+ * Description:
+ *
+ *   This function converts time to corresponding sample number.
+ *
+ * Parameters:
+ *
+ *   handle       MP4 library handle
+ *   trak         trackAtom pointer
+ *   position     Time in milliseconds
+ *   sample       Sample number is returned here
+ *
+ * Return value:
+ *
+ *   0            Success
+ *   Negative     Error
+ *
+ */
+mp4_i32 convertTimeToSample(MP4HandleImp handle,
+                            trackAtom *trak,
+                            mp4_u32 position,
+                            mp4_u32 *sample)
+{
+  mp4_u32 pos;      /* Target position in media timescale */
+  mp4_u32 tmppos;   /* Temporary position counter */
+  mp4_u32 i;
+
+
+  if (!handle)
+    return -1;
+  if (!trak)
+    return -1;
+  if (!trak->mdia)
+    return -1;
+  if (!trak->mdia->mdhd)
+    return -1;
+  if (!trak->mdia->minf)
+    return -1;
+  if (!trak->mdia->minf->stbl)
+    return -1;
+  if (!trak->mdia->minf->stbl->stts)
+    return -1;
+  if (trak->mdia->minf->stbl->stts->entryCount == 0)
+    return -1;
+
+  *sample = 1;
+  tmppos = 0;
+
+  pos = (mp4_u32)((mp4_double)position / (mp4_double)1000 * (mp4_double)trak->mdia->mdhd->timeScale + (mp4_double)0.5);
+
+  for (i = 0; i < trak->mdia->minf->stbl->stts->entryCount; i++)
+  {
+    if (pos >= (tmppos + trak->mdia->minf->stbl->stts->sampleCount[i] *
+                         trak->mdia->minf->stbl->stts->sampleDelta[i]))
+    {
+      *sample += trak->mdia->minf->stbl->stts->sampleCount[i];
+      tmppos += (trak->mdia->minf->stbl->stts->sampleCount[i] *
+                 trak->mdia->minf->stbl->stts->sampleDelta[i]);
+
+      if (i == trak->mdia->minf->stbl->stts->entryCount - 1) /* Last entry */
+        *sample = *sample - 1;
+    }
+    else
+    {
+      if (trak->mdia->minf->stbl->stts->sampleDelta[i] == 0)
+        return -1;
+
+      *sample += ((pos - tmppos) / trak->mdia->minf->stbl->stts->sampleDelta[i]);
+
+      break;
+    }
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 goToVideoSample(MP4HandleImp handle,
+ *                           trackAtom *trak,
+ *                           mp4_u32 sample)
+ *
+ * Description:
+ *
+ *   This function moves to video sample indicated by sample and finds the
+ *   sample offset and sample size.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   trak      TRAK atom pointer
+ *   sample    Sample to go to
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   Negative  Error
+ *
+ */
+mp4_i32 goToVideoSample(MP4HandleImp handle,
+                        trackAtom *trak,
+                        mp4_u32 sample)
+{
+  if (!trak->mdia)
+    return -1;
+  if (!trak->mdia->minf)
+    return -1;
+  if (!trak->mdia->minf->stbl)
+    return -1;
+  if (!trak->mdia->minf->stbl->stsz)
+    return -1;
+
+
+  /* Is the sample valid? */
+
+  if (sample <= trak->mdia->minf->stbl->stsz->sampleCount)
+    handle->videoSampleNum = sample;
+  else
+    return -1;
+
+  /* Find the size of the sample */
+
+  if (resolveVideoSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
+    return -1;
+
+  /* Find the offset of the sample */
+
+  if (resolveVideoSampleOffset(handle, trak->mdia->minf->stbl) < 0)
+    return -1;
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 goToAudioSample(MP4HandleImp handle,
+ *                           trackAtom *trak,
+ *                           mp4_u32 sample)
+ *
+ * Description:
+ *
+ *   This function moves to audio sample indicated by sample and finds the
+ *   sample offset and sample size.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   trak      TRAK atom pointer
+ *   sample    Sample to go to
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   Negative  Error
+ *
+ */
+mp4_i32 goToAudioSample(MP4HandleImp handle,
+                        trackAtom *trak,
+                        mp4_u32 sample)
+{
+  if (!trak->mdia)
+    return -1;
+  if (!trak->mdia->minf)
+    return -1;
+  if (!trak->mdia->minf->stbl)
+    return -1;
+  if (!trak->mdia->minf->stbl->stsz)
+    return -1;
+
+
+  /* Is the sample valid? */
+
+  if (sample <= trak->mdia->minf->stbl->stsz->sampleCount)
+    handle->audioSampleNum = sample;
+  else
+    return -1;
+
+  /* Find the size of the sample */
+
+  if (resolveAudioSampleSize(handle, trak->mdia->minf->stbl->stsz) < 0)
+    return -1;
+
+  /* Find the offset of the sample */
+
+  if (resolveAudioSampleOffset(handle, trak->mdia->minf->stbl) < 0)
+    return -1;
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 findVideoKeyFrame(MP4HandleImp handle,
+ *                             trackAtom *trak,
+ *                             mp4_u32 sample,
+ *                             mp4_u32 *newsample)
+ *
+ * Description:
+ *
+ *   This function finds the video keyframe that is identical to or precedes
+ *   the sample indicated by sample.
+ *
+ * Parameters:
+ *
+ *   handle       MP4 library handle
+ *   trak         TRAK atom pointer
+ *   sample       Sample number
+ *   newsample    Sample number of found keyframe
+ *
+ * Return value:
+ *
+ *   0            Success
+ *   Negative     Error
+ *
+ */
+mp4_i32 findVideoKeyFrame(MP4HandleImp handle,
+                          trackAtom *trak,
+                          mp4_u32 sample,
+                          mp4_u32 *newsample)
+{
+  mp4_i32  i;
+
+
+  if (!handle)
+    return -1;
+  if (!trak->mdia)
+    return -1;
+  if (!trak->mdia->minf)
+    return -1;
+  if (!trak->mdia->minf->stbl)
+    return -1;
+
+  if (!trak->mdia->minf->stbl->stss) /* No sync sample atom => all samples are
+                                        random access points */
+  {
+    *newsample = sample;
+
+    return 0;
+  }
+  *newsample = 0;
+
+  for (i = trak->mdia->minf->stbl->stss->entryCount - 1; i >= 0; i--)
+  {
+    if (sample >= trak->mdia->minf->stbl->stss->sampleNumber[i])
+    {
+      *newsample = trak->mdia->minf->stbl->stss->sampleNumber[i];
+      break;
+    }
+  }
+
+  if (*newsample == 0)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readAVCC(MP4HandleImp handle,
+ *                    avcConfigurationAtom *avcc)
+ *
+ * Description:
+ *
+ *   This function parses one avcc atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   avcc               avcC pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readAVCC(MP4HandleImp handle, avcConfigurationAtom *avcc)
+{
+	mp4_i32 bytesread;
+	mp4_i32 totalbytesread = 0;
+
+	avcc->avcConfigSize = 0;
+
+	if ((avcc->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+		return -100;
+
+	bytesread = readAtomHeader(handle, avcc->atomhdr);
+	if (bytesread < 0)
+		return -1;
+	totalbytesread +=bytesread;
+
+	if (avcc->atomhdr->type != ATOMTYPE_AVCC)
+		return -1;
+
+    /* read the avcDecoderConfigurationRecord */
+    if  (avcc->atomhdr->size != 1)
+    	avcc->avcConfigSize = avcc->atomhdr->size - 8;
+    else
+    	avcc->avcConfigSize = (mp4_u32)(I64INT(avcc->atomhdr->largeSize) - 16);
+
+   	avcc->avcConfig = (mp4_u8 *)mp4malloc(avcc->avcConfigSize);
+	if (avcc->avcConfig == 0)
+		return -100;
+	
+	bytesread = readData(handle, avcc->avcConfig, avcc->avcConfigSize );
+    
+	if (bytesread < 0)
+		return -1;
+	totalbytesread +=bytesread;
+	return totalbytesread;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readBTRT(MP4HandleImp handle,
+ *                    mpeg4BitrateAtom *btrt)
+ *
+ * Description:
+ *
+ *   This function parses one btrt atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   btrt					btrt pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readBTRT(MP4HandleImp handle, mpeg4BitrateAtom *btrt)
+{
+	mp4_i32 bytesread;
+	mp4_i32 totalbytesread = 0;
+
+
+	if ((btrt->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+		return -100;
+
+	bytesread = readAtomHeader(handle, btrt->atomhdr);
+	if (bytesread < 0)
+		return -1;
+	totalbytesread +=bytesread;
+
+	if (btrt->atomhdr->type != ATOMTYPE_BTRT)
+		return -1;
+
+    /* read the mpeg4BitrateAtom */
+   bytesread = readData(handle, handle->buf, 4);
+   if (bytesread < 0)
+	   return -1;
+   btrt->bufferSizeDB = u32endian(*((mp4_u32 *)handle->buf));
+   totalbytesread +=bytesread;
+
+   bytesread = readData(handle, handle->buf, 4);
+   if (bytesread < 0)
+	   return -1;
+   btrt->maxBitRate = u32endian(*((mp4_u32 *)handle->buf));
+   totalbytesread +=bytesread;
+
+   bytesread = readData(handle, handle->buf, 4);
+   if (bytesread < 0)
+	   return -1;
+   btrt->avgBitrate = u32endian(*((mp4_u32 *)handle->buf));
+   totalbytesread +=bytesread;
+
+	return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readM4DS(MP4HandleImp handle,
+ *                    mpeg4ExtensionDescriptorsAtom *m4ds)
+ *
+ * Description:
+ *
+ *   This function parses one m4ds atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   m4ds               m4ds pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readM4DS(MP4HandleImp handle, mpeg4ExtensionDescriptorsAtom *m4ds)
+{
+	mp4_i32 bytesread;
+	mp4_i32 totalbytesread = 0;
+	mp4_u32 i;
+
+	m4ds->descrSize = 0;
+
+	if ((m4ds->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+		return -100;
+
+	bytesread = readAtomHeader(handle, m4ds->atomhdr);
+	if (bytesread < 0)
+		return -1;
+	totalbytesread +=bytesread;
+
+	if (m4ds->atomhdr->type != ATOMTYPE_M4DS)
+		return -1;
+
+    /* read the avcDecoderConfigurationRecord */
+	if  (m4ds->atomhdr->size != 1)
+		bytesread = readData(handle, handle->buf, m4ds->atomhdr->size - 8);
+	else
+        bytesread = readData(handle, handle->buf, (mp4_u32)(I64INT(m4ds->atomhdr->largeSize) - 16) );
+
+	if (bytesread < 0)
+		return -1;
+	m4ds->descrSize = bytesread;
+	m4ds->descr = (mp4_u8 *)mp4malloc(m4ds->descrSize * sizeof(mp4_u8));
+	
+	/* copy the mpeg4ExtensionDescriptors from the temp. buffer */
+	for(i = 0; i <  m4ds->descrSize; i++)
+		m4ds->descr[i] = handle->buf[i];
+	
+	totalbytesread +=bytesread;
+
+	return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readAVC1(MP4HandleImp handle,
+ *                    avcSampleEntry *avc1)
+ *
+ * Description:
+ *
+ *   This function parses one avc1 atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   avc1               avc1 pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readAVC1(MP4HandleImp handle, avcSampleEntry *avc1)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+  if ((avc1->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, avc1->atomhdr);
+
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (avc1->atomhdr->type != ATOMTYPE_AVC1)
+    return -1;
+
+  bytesread = discardData(handle, 6);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  avc1->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 16);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  avc1->width = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  avc1->height = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 50);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  /* Check for the present atoms */
+  while ((mp4_u32)totalbytesread < avc1->atomhdr->size)
+  {
+    mp4_u32 type;
+
+    if (peekData(handle, handle->buf, 8) < 0)
+      return -1;
+
+    type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+    switch (type)
+    {
+    case ATOMTYPE_AVCC:
+
+		if (avc1->avcc) /* avcC has already been read, more than one is not allowed. */
+			return -1;
+
+		if ((avc1->avcc = (avcConfigurationAtom *)mp4malloc(sizeof(avcConfigurationAtom))) == NULL)
+			return -100;
+
+		bytesread = readAVCC(handle, avc1->avcc);  
+		if(bytesread < 0)
+			return -1;
+		totalbytesread +=bytesread;
+  	    break;
+
+    case ATOMTYPE_BTRT:
+
+		if (avc1->btrt) /* btrt has already been read, more than one is not allowed. */
+			return -1;
+
+		if ((avc1->btrt = (mpeg4BitrateAtom *)mp4malloc(sizeof(mpeg4BitrateAtom))) == NULL)
+			return -100;
+
+		bytesread = readBTRT(handle, avc1->btrt);  
+		if(bytesread < 0)
+			return -1;
+		totalbytesread +=bytesread;
+	    break;
+
+    case ATOMTYPE_M4DS:
+
+		if (avc1->m4ds) /* m4ds has already been read, more than one is not allowed. */
+			return -1;
+
+		if ((avc1->m4ds = (mpeg4ExtensionDescriptorsAtom *)mp4malloc(sizeof(mpeg4ExtensionDescriptorsAtom))) == NULL)
+			return -100;
+
+		bytesread = readM4DS(handle, avc1->m4ds);  
+		if(bytesread < 0)
+			return -1;
+		totalbytesread +=bytesread;
+	    break;
+	 
+	 default:
+
+        bytesread = readUnknown(handle);
+        if (bytesread < 0)
+            return -1;
+        totalbytesread += bytesread;
+
+        break;
+
+	}
+  }
+
+  return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeAVCC(avcConfigurationAtom *avcc)
+ *
+ * Description:
+ *
+ *   This function frees memory for avcc atom.
+ *
+ * Parameters:
+ *
+ *   avcc       avcc atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeAVCC(avcConfigurationAtom *avcc)
+{
+  if (avcc)
+  {
+    if (freeAtomHeader(avcc->atomhdr) < 0)
+      return -1;
+	if(avcc->avcConfig)
+		mp4free(avcc->avcConfig);
+
+    mp4free(avcc);
+  }
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeBTRT(mpeg4BitrateAtom *btrt)
+ *
+ * Description:
+ *
+ *   This function frees memory for btrt atom.
+ *
+ * Parameters:
+ *
+ *   btrt       btrt atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeBTRT(mpeg4BitrateAtom *btrt)
+{
+  if (btrt)
+  {
+    if (freeAtomHeader(btrt->atomhdr) < 0)
+      return -1;
+
+    mp4free(btrt);
+  }
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeM4DS(mpeg4ExtensionDescriptorsAtom *m4ds)
+ *
+ * Description:
+ *
+ *   This function frees memory for m4ds atom.
+ *
+ * Parameters:
+ *
+ *   m4ds       m4ds atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeM4DS(mpeg4ExtensionDescriptorsAtom *m4ds)
+{
+  if (m4ds)
+  {
+    if (freeAtomHeader(m4ds->atomhdr) < 0)
+      return -1;
+	if(m4ds->descr)
+		mp4free(m4ds->descr);
+
+    mp4free(m4ds);
+  }
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeAVC1(avcSampleEntry *avc1)
+ *
+ * Description:
+ *
+ *   This function frees memory for avc1 atom.
+ *
+ * Parameters:
+ *
+ *   avc1       avc1 atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeAVC1(avcSampleEntry *avc1)
+{
+  if (avc1)
+  {
+    if (freeAtomHeader(avc1->atomhdr) < 0)
+      return -1;
+    if (freeAVCC(avc1->avcc) < 0)
+      return -1;
+	if (freeBTRT(avc1->btrt) < 0)
+		return -1;
+	if (freeM4DS(avc1->m4ds) < 0)
+		return -1;
+
+    mp4free(avc1);
+  }
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSQCP(MP4HandleImp handle,
+ *                    qcelpSampleEntry *sqcp)
+ *
+ * Description:
+ *
+ *   This function parses one SQCP atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   sqcp               SQCP pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readSQCP(MP4HandleImp handle, qcelpSampleEntry *sqcp)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((sqcp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, sqcp->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (sqcp->atomhdr->type != ATOMTYPE_SQCP)
+    return -1;
+
+
+  bytesread = discardData(handle, 6);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  sqcp->dataReferenceIndex = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 16);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 2);
+  if (bytesread < 0)
+    return -1;
+  sqcp->timeScale = u16endian(*((mp4_u16 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = discardData(handle, 2);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if ((sqcp->dqcp = (qcelpDecSpecStruc *)mp4malloc(sizeof(qcelpDecSpecStruc))) == NULL)
+    return -100;
+
+  bytesread = readDQCP(handle, sqcp->dqcp);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+  
+  if ( totalbytesread < sqcp->atomhdr->size )
+  	{
+    bytesread = discardData(handle, sqcp->atomhdr->size - totalbytesread );
+  	if (bytesread < 0)
+  		{
+    	return -1;	  		
+  		}
+  	totalbytesread += bytesread;
+  	}  
+
+  return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeSQCP(qcelpSampleEntry *sqcp)
+ *
+ * Description:
+ *
+ *   This function frees memory for SQCP atom.
+ *
+ * Parameters:
+ *
+ *   sqcp       SQCP atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeSQCP(qcelpSampleEntry *sqcp)
+{
+  if (sqcp)
+  {
+    if (freeAtomHeader(sqcp->atomhdr) < 0)
+      return -1;
+    if (freeDQCP(sqcp->dqcp) < 0)
+      return -1;
+
+    mp4free(sqcp);
+  }
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readDQCP(MP4HandleImp handle,
+ *                    qcelpDecSpecStruc *dqcp)
+ *
+ * Description:
+ *
+ *   This function parses one DQCP atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   dqcp               DQCP pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+mp4_i32 readDQCP(MP4HandleImp handle, qcelpDecSpecStruc *dqcp)
+{
+  mp4_i32 bytesread;
+  mp4_i32 totalbytesread = 0;
+
+
+  if ((dqcp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, dqcp->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (dqcp->atomhdr->type != ATOMTYPE_DQCP)
+    return -1;
+
+
+  bytesread = readData(handle, handle->buf, 4);
+  if (bytesread < 0)
+    return -1;
+  dqcp->vendor = u32endian(*((mp4_u32 *)handle->buf));
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  dqcp->decoderVersion = handle->buf[0];
+  totalbytesread += bytesread;
+
+  bytesread = readData(handle, handle->buf, 1);
+  if (bytesread < 0)
+    return -1;
+  dqcp->framesPerSample = handle->buf[0];
+  totalbytesread += bytesread;
+
+  return totalbytesread;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 freeDQCP(qcelpDecSpecStruc *dqcp)
+ *
+ * Description:
+ *
+ *   This function frees memory for DQCP atom.
+ *
+ * Parameters:
+ *
+ *   damr       DQCP atom pointer
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   Negative   Error
+ *
+ */
+mp4_i32 freeDQCP(qcelpDecSpecStruc *dqcp)
+{
+  if (dqcp)
+  {
+    if (freeAtomHeader(dqcp->atomhdr) < 0)
+      return -1;
+
+    mp4free(dqcp);
+  }
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readSDTP(MP4HandleImp handle, sampleDependencyAtom *sdtp, 
+ * 				      mp4_i32 sample_count)
+ *
+ * Description:
+ *
+ *   This function parses one SDTP atom.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   sdtp               SDTP atom pointer
+ *
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   >= 0               Success. Value tells how many bytes were read.
+ *
+ */
+
+mp4_i32 readSDTP(MP4HandleImp handle, 
+				 sampleDependencyAtom *sdtp, 
+				 mp4_i32 sample_count)
+{
+  mp4_i32 bytesread = 0;
+  mp4_i32 totalbytesread = 0;
+  mp4_u32 i = 0;
+
+  if ((sdtp->atomhdr = (atomHeader *)mp4malloc(sizeof(atomHeader))) == NULL)
+    return -100;
+
+  bytesread = readAtomHeader(handle, sdtp->atomhdr);
+  if (bytesread < 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  if (sdtp->atomhdr->type != ATOMTYPE_SDTP)
+    return -1;
+  
+  bytesread = readData(handle, handle->buf, 1); //Version must be 0
+  if (bytesread < 0 || handle->buf[0] != 0)
+    return -1;
+  totalbytesread += bytesread;
+  bytesread = readData(handle, handle->buf, 3); // Flags must be 0
+  if (bytesread < 0 || handle->buf[0] != 0 || handle->buf[1] != 0 || handle->buf[2] != 0)
+    return -1;
+  totalbytesread += bytesread;
+
+  // sample_count == (size_of_atom - 12) ???  12 = size + 'sdtp' + ver + flags = 4 + 4 + 1 + 3 ???
+  //
+  // sample_count is taken from the sample_count in the Sample Size Box ('stsz') or
+  // Compact Sample Size Box (‘stz2’).
+  if (sample_count != sdtp->atomhdr->size-12 || sample_count < 0)
+	  {
+	  // as each byte consititue one entry in the table, the number of remaining bytes in this
+	  // atom should match the sample count.  If not, the file is corrupted.
+	  return -1;
+	  }
+  
+  if ((sdtp->dep = (sampleDependency *)mp4malloc(sample_count * sizeof(sampleDependency))) == NULL)
+    return -100;
+  
+  for(i=0;i<sample_count;i++)
+  {
+    bytesread = readData(handle, handle->buf, 1);
+    if (bytesread < 0)
+      return -1;
+    
+    sdtp->dep[i].sDependsOn = (handle->buf[0] >> 4) & 0x03; // value from 0 to 3
+    sdtp->dep[i].sIsDependentOn = (handle->buf[0] >> 2) & 0x03; // value from 0 to 3
+    sdtp->dep[i].sHasRedundancy = handle->buf[0] & 0x03; // value from 0 to 3
+    totalbytesread += bytesread;
+  }
+
+  sdtp->sampleCount = sample_count;
+  return totalbytesread;	
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 readBoxHeader(MP4HandleImp handle, mp4_i64* size, mp4_u32* type)
+ * 				      
+ *
+ * Description:
+ *
+ *   This function parses the size and type information for a box. 
+ *   Taking into account largesize if needed.
+ *
+ * Parameters:
+ *
+ *   handle             MP4 library handle
+ *   size               Size of box is returned here
+ *   type               Type of the box is returned here
+ * Return value:
+ *
+ *   Negative integer   Error
+ *   0               Success.
+ *
+ */
+mp4_i32 readBoxHeader(MP4HandleImp handle, mp4_i64* size, mp4_u32* type)
+{
+  if (peekData(handle, handle->buf, 8) < 0)
+    return -1;
+
+  *size = u32endian(*((mp4_u32 *)handle->buf));
+  *type = u32endian(*((mp4_u32 *)(handle->buf+4)));
+
+  if (*size == 1)
+  {
+    if (peekData(handle, handle->buf, 16) < 0)
+      return -1;
+    
+    *size = u64endian(*((mp4_u64 *)(handle->buf+8)));
+  }
+
+  return 0;
+}
+
+/*
+ */
+
+mp4_i64 getChunkOffset(sampleTableAtom *stbl, mp4_u32 index)
+{
+  if (stbl->is32BitOffsets)
+  	return (mp4_i64)stbl->stco->chunkOffset[index];
+  else
+    return stbl->stco64->chunkOffset[index];
+}
+
+// End of File