mmplugins/lib3gp/impl/src/compose.cpp
changeset 0 40261b775718
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/lib3gp/impl/src/compose.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,7464 @@
+// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <3gplibrary/mp4config.h>
+#include <3gplibrary/mp4lib.h>
+#include "mp4atom.h"
+#include "mp4memwrap.h"
+#include "mp4file.h"
+#include "mp4endian.h"
+#include "mp4compose.h"
+#include "mp4currenttime.h"
+#include "mp4utils.h"
+
+#define MP4_INT_MAX		KMaxTInt32	
+#define MDAT_HEADER_SIZE 16
+
+// MACROS
+// Debug print macro
+#ifdef _DEBUG
+#include <e32svr.h>
+#define PRINT(x)
+#else
+#define PRINT(x)
+#endif
+
+
+inline void updateChunkOffset(sampleTable *st, mp4_i32 index, mp4_i64 value) 
+{
+  if (value > MP4_INT_MAX) 
+    st->stcoNeed64Bits = ETrue; 
+  
+  st->stcoChunkOffset[index] = value;
+}
+
+/* must be called after determineAudioTrakMetaDataSize and determineVideoTrakMetaDataSize */
+size_t mvhdAtomSize(MP4HandleImp handle)
+{
+  if (handle->videoDuration > MP4_INT_MAX || handle->audioDuration > MP4_INT_MAX)
+  {
+    return 120;
+  }
+  else
+  {
+    return 108;
+  }
+}
+
+
+
+/* helper functions */
+mp4_i32 formatMdatHeader(mp4_u8 *buffer, mp4_i64 size);
+
+/*
+ * Function:
+ *
+ *   mp4_i32 updateVideoMetaData(MP4HandleImp handle,
+ *                               mp4_u32 size,
+ *                               mp4_u32 duration)
+ *
+ * Description:
+ *
+ *   This function updates sample table atom data.
+ *
+ *   One call of this function will generate one chunk in the MP4 file.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   size      Size of video frame to insert
+ *   duration  Duration of the video frame (in media timescale)
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   -1        Error
+ *
+ */
+mp4_i32 updateVideoMetaData(MP4HandleImp handle, mp4_u32 size, mp4_u32 duration, mp4_bool keyframe)
+{
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (handle->metaDataBlocks == BLOCK_LIMIT)
+    {
+      /* Write metadata to temporary files */
+
+      if (writeMetaDataTmp(handle) < 0)
+        return -1;
+    }
+
+    handle->metaDataBlocks++;
+  }
+
+  handle->videoSampleTable->currentChunk++;
+
+  if (updateDecodingTimeToSample(handle, handle->videoSampleTable, duration) < 0)
+    return -1;
+
+  if (updateSampleSize(handle, handle->videoSampleTable, size) < 0)
+    return -1;
+
+  if (updateSampleToChunk(handle->videoSampleTable) < 0)
+    return -1;
+
+  if (updateChunkOffset(handle, handle->videoSampleTable) < 0)
+    return -1;
+
+  if (keyframe)
+    if (updateSyncSample(handle, handle->videoSampleTable) < 0)
+      return -1;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 updateAudioMetaData(MP4HandleImp handle,
+ *                               mp4_u32 size,
+ *                               mp4_u32 numberofframes)
+ *
+ * Description:
+ *
+ *   This function updates sample table atom data.
+ *
+ *   One call of this function will generate one chunk in the MP4 file.
+ *
+ * Parameters:
+ *
+ *   handle          MP4 library handle
+ *   size            Size of video frame to insert
+ *   duration        Duration of audio frames (in timescale,
+ *                   see MP4ComposeAddAudioDescription)
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   -1        Error
+ *
+ */
+mp4_i32 updateAudioMetaData(MP4HandleImp handle, mp4_u32 size, mp4_u32 duration)
+{
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (handle->metaDataBlocks == BLOCK_LIMIT)
+    {
+      /* Write metadata to temporary files */
+
+      if (writeMetaDataTmp(handle) < 0)
+        return -1;
+    }
+
+    handle->metaDataBlocks++;
+  }
+
+  handle->audioSampleTable->currentChunk++;
+
+  if (updateDecodingTimeToSample(handle, handle->audioSampleTable, duration) < 0)
+    return -1;
+
+  if (updateSampleSize(handle, handle->audioSampleTable, size) < 0)
+    return -1;
+
+  if (updateSampleToChunk(handle->audioSampleTable) < 0)
+    return -1;
+
+  if (updateChunkOffset(handle, handle->audioSampleTable) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeFTYPAndMDATToFile(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ *   This function writes FTYP box to a file. In addition, it writes MDAT box
+ *   size and type to a file. The function is used when meta data is put to
+ *   the end of file.
+ *
+ * Parameters:
+ *
+ *   handle     MP4 library handle
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   -1         Error
+ *
+ */
+mp4_i32 writeFTYPAndMDATToFile(MP4HandleImp handle)
+{
+  mp4_u8  buf[32];
+  mp4_u32 i = 0;
+
+
+  if (writeFTYP(handle) < 0)
+    return -1;
+
+  handle->ftypWritten = MP4TRUE;
+
+
+  i = formatMdatHeader(buf, (mp4_u32)0);
+  if (writeFile(handle, buf, i) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeDataToFile(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ *   This function writes meta and media data to a file.
+ *
+ * Parameters:
+ *
+ *   handle     MP4 library handle
+ *
+ * Return value:
+ *
+ *   0          Success
+ *   -1         Error
+ *
+ */
+mp4_i32 writeDataToFile(MP4HandleImp handle)
+{
+  PRINT((_L("e_writedatatofile 1")));
+  mp4_u32   metaDataSize = 0;
+  trakSize  *audioTrackSize;
+  trakSize  *videoTrackSize;
+  mp4_bool  haveAudio = MP4FALSE;
+  mp4_bool  haveVideo = MP4FALSE;
+  mp4_u8 ftypdelta = 0;
+
+
+  if ((handle->type & MP4_TYPE_AMR_NB) ||
+      (handle->type & MP4_TYPE_AMR_WB) ||
+       (handle->type & MP4_TYPE_QCELP_13K) ||     
+      (handle->type & MP4_TYPE_MPEG4_AUDIO))
+    haveAudio = MP4TRUE;
+
+  if ((handle->type & MP4_TYPE_H263_PROFILE_0) ||
+      (handle->type & MP4_TYPE_H263_PROFILE_3) ||
+      (handle->type & MP4_TYPE_MPEG4_VIDEO) ||
+	  containsAvcVideo( handle->type ) )
+    haveVideo = MP4TRUE;
+
+  if ((handle->generate3G2 && !(handle->type &  MP4_TYPE_QCELP_13K)) ||
+       (!handle->generate3G2 && !(handle->type &  MP4_TYPE_AMR_WB)))
+     ftypdelta = 4; /* one more additional compatible brand */
+  else
+     ftypdelta = 0;
+  
+  if( containsAvcVideo( handle->type ) )
+  {
+    ftypdelta += 4;
+  }  
+
+  PRINT((_L("e_writedatatofile_alloc_audiotrk 1")));
+  audioTrackSize = (trakSize *)mp4malloc(sizeof(trakSize));
+  if (audioTrackSize == NULL)
+    return -1;
+  PRINT((_L("e_writedatatofile_alloc_audiotrk 0")));    
+	
+  PRINT((_L("e_writedatatofile_alloc_videotrk 1")));  
+  videoTrackSize = (trakSize *)mp4malloc(sizeof(trakSize));
+  if (videoTrackSize == NULL)
+  {
+    mp4free(audioTrackSize);
+
+    return -1;
+  }
+  PRINT((_L("e_writedatatofile_alloc_videotrk 0")));  
+
+  if (haveAudio)
+  {
+	PRINT((_L("e_writedatatofile_deter_audiotrk_metadatasize 1")));  
+    if (determineAudioTrakMetaDataSize(handle, handle->audioSampleTable, audioTrackSize) < 0)
+        {
+        mp4free(audioTrackSize);
+        mp4free(videoTrackSize);
+        return -1;
+        }
+	PRINT((_L("e_writedatatofile_deter_audiotrk_metadatasize 0")));          
+  }
+
+  if (haveVideo)
+  {
+	PRINT((_L("e_writedatatofile_deter_videotrk_metadatasize 1")));
+    if (determineVideoTrakMetaDataSize(handle, handle->videoSampleTable, videoTrackSize) < 0)
+        {
+        mp4free(audioTrackSize);
+        mp4free(videoTrackSize);
+        return -1;
+        }
+PRINT((_L("e_writedatatofile_deter_videotrk_metadatasize 0")));        
+  }
+
+  if (handle->flags & MP4_FLAG_METADATALAST)
+  {
+    metaDataSize += (FTYP_SIZE + ftypdelta);             /* ftyp */
+    handle->metaDataSize = metaDataSize;
+  }
+  else
+  {
+    metaDataSize += (FTYP_SIZE + ftypdelta);             /* ftyp */
+    metaDataSize += 8;                     /* moov atomheader */
+    metaDataSize += mvhdAtomSize(handle);                   /* mvhd */
+    if (handle->moovUDTA)
+        {
+        metaDataSize += 8 + (mp4_u32)handle->moovUDTA->atomcontentsize;
+        }
+    metaDataSize += audioTrackSize->trak;  /* Audio trak */
+    metaDataSize += videoTrackSize->trak;  /* Video trak */
+
+    handle->metaDataSize = metaDataSize;
+  }
+
+
+  if (!(handle->flags & MP4_FLAG_LONGCLIP))
+  {
+    /* Update metadata pointers only if metadata is in memory */
+
+    if (haveAudio)
+    {
+	PRINT((_L("e_writedatatofile_reupdata_audiometadata 1")));     
+      if (reUpdateAudioMetaData(handle->audioSampleTable, metaDataSize) < 0)
+      {
+        mp4free(audioTrackSize);
+        mp4free(videoTrackSize);
+
+        return -1;
+      }
+	PRINT((_L("e_writedatatofile_reupdata_audiometadata 0")));           
+    }
+
+    if (haveVideo)
+    {
+	PRINT((_L("e_writedatatofile_reupdata_videometadata 1")));               
+      if (reUpdateVideoMetaData(handle->videoSampleTable, metaDataSize) < 0)
+      {
+        mp4free(audioTrackSize);
+        mp4free(videoTrackSize);
+
+        return -1;
+      }
+	PRINT((_L("e_writedatatofile_reupdata_videometadata 0")));      
+    }
+  }
+  else
+  {
+    /* Write the rest of metadata to temporary files */
+	PRINT((_L("e_writedatatofile_write_metadatablocks 1")));
+    if (handle->metaDataBlocks)
+      if (writeMetaDataTmp(handle) < 0)
+          {
+          mp4free(audioTrackSize);
+          mp4free(videoTrackSize);
+          return -1;
+          }
+	PRINT((_L("e_writedatatofile_write_metadatablocks 0")));          
+  }
+
+
+  if (handle->flags & MP4_FLAG_METADATALAST)
+  {
+    mp4_u8  buf[16];
+    mp4_u32 moovSize = 0;
+
+    moovSize += 8;                     /* moov atomheader */
+    moovSize += mvhdAtomSize(handle);                   /* mvhd */
+    moovSize += audioTrackSize->trak;  /* Audio trak */
+    moovSize += videoTrackSize->trak;  /* Video trak */
+    if (handle->moovUDTA)
+        {
+        moovSize += 8 + handle->moovUDTA->atomcontentsize;
+        }    
+        
+	PRINT((_L("e_writedatatofile_write_moov 1")));
+    if (writeMOOV(handle, moovSize, haveAudio, haveVideo, audioTrackSize, videoTrackSize) < 0)
+    {
+      mp4free(audioTrackSize);
+      mp4free(videoTrackSize);
+
+      return -1;
+    }
+    PRINT((_L("e_writedatatofile_write_moov 0")));
+
+    /* Overwrite media data size */
+	PRINT((_L("e_writedatatofile_update_moov_media_size 1")));
+	if(!handle->bufferWrite)
+	{
+		if (seekFileAbsWrite(handle, (FTYP_SIZE + ftypdelta)) != 0)
+			{
+			mp4free(audioTrackSize);
+			mp4free(videoTrackSize);
+			return -1;
+			}
+	}
+	
+	//make sure the buf is large enough to hold the mdat header
+	TInt i;
+	i = formatMdatHeader(buf, handle->mediaDataBytes);
+    if (writeFileUnbuffered(handle, buf, i) < 0)
+        {
+        mp4free(audioTrackSize);
+        mp4free(videoTrackSize);
+        return -1;
+        }
+	PRINT((_L("e_writedatatofile_update_moov_media_size 0")));        
+  }
+  else
+  {
+	PRINT((_L("e_writedatatofile_write_ftyp 1")));  
+    if (writeFTYP(handle) < 0)
+    {
+      mp4free(audioTrackSize);
+      mp4free(videoTrackSize);
+
+      return -1;
+    }
+    PRINT((_L("e_writedatatofile_write_ftyp 0")));  
+
+	PRINT((_L("e_writedatatofile_write_new_moov 1")));  
+    if (writeMOOV(handle, metaDataSize - (FTYP_SIZE + ftypdelta), haveAudio, haveVideo, audioTrackSize, videoTrackSize) < 0)
+    {
+      mp4free(audioTrackSize);
+      mp4free(videoTrackSize);
+
+      return -1;
+    }
+    PRINT((_L("e_writedatatofile_write_new_moov 0")));
+
+	PRINT((_L("e_writedatatofile_write_new_mdia 1")));
+    if (writeMediaData(handle) < 0)
+    {
+      mp4free(audioTrackSize);
+      mp4free(videoTrackSize);
+
+      return -1;
+    }
+    PRINT((_L("e_writedatatofile_write_new_mdia 0")));
+  }
+
+PRINT((_L("e_writedatatofile_free_audioandvideotrks 1")));
+  mp4free(audioTrackSize);
+  mp4free(videoTrackSize);
+PRINT((_L("e_writedatatofile_free_audioandvideotrks 0")));
+PRINT((_L("e_writedatatofile 0")));
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 updateDecodingTimeToSample(MP4HandleImp handle,
+ *                                      sampleTable *st,
+ *                                      mp4_u32 duration)
+ *
+ * Description:
+ *
+ *   This function updates stts atom data.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   st        sampleTable
+ *   duration  Duration of sample to insert (in media timescale)
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   -1        Error
+ *
+ */
+mp4_i32 updateDecodingTimeToSample(MP4HandleImp handle, sampleTable *st, mp4_u32 duration)
+{
+  if (!handle)
+    return -1;
+
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (st->sttsCurrentEntryCount == 0)
+    {
+      st->sttsSampleCount[st->sttsCurrentEntryCount] = 1;
+      st->sttsSampleDelta[st->sttsCurrentEntryCount] = duration;
+
+      st->sttsCurrentEntryCount++;
+      st->sttsEntryCount++;
+
+      return 0;
+    }
+
+    if (st->sttsCurrentEntryCount == st->sttsMaxEntryCount)
+    {
+      void *p;
+
+      p = mp4realloc(st->sttsSampleCount,
+                     2 * sizeof(mp4_u32) * st->sttsMaxEntryCount,
+                     sizeof(mp4_u32) * st->sttsMaxEntryCount);
+      if (p == NULL)
+        return -1;
+
+      st->sttsSampleCount = (mp4_u32 *)p;
+
+      p = mp4realloc(st->sttsSampleDelta,
+                     2 * sizeof(mp4_u32) * st->sttsMaxEntryCount,
+                     sizeof(mp4_u32) * st->sttsMaxEntryCount);
+      if (p == NULL)
+        return -1;
+
+      st->sttsSampleDelta = (mp4_u32 *)p;
+
+      st->sttsMaxEntryCount *= 2;
+    }
+
+    if (st->sttsSampleDelta[st->sttsCurrentEntryCount - 1] == duration)
+    {
+      st->sttsSampleCount[st->sttsCurrentEntryCount - 1]++;
+    }
+    else
+    {
+      st->sttsSampleCount[st->sttsCurrentEntryCount] = 1;
+      st->sttsSampleDelta[st->sttsCurrentEntryCount] = duration;
+
+      st->sttsCurrentEntryCount++;
+      st->sttsEntryCount++;
+    }
+  }
+  else
+  {
+    if (st->sttsEntryCount == 0)
+    {
+      st->sttsSampleCount[st->sttsEntryCount]++;
+      st->sttsSampleDelta[st->sttsEntryCount] = duration;
+
+      st->sttsEntryCount++;
+
+      return 0;
+    }
+
+    if (st->sttsEntryCount == st->sttsMaxEntryCount)
+    {
+      void *p;
+
+      p = mp4realloc(st->sttsSampleCount,
+                     2 * sizeof(mp4_u32) * st->sttsMaxEntryCount,
+                     sizeof(mp4_u32) * st->sttsMaxEntryCount);
+      if (p == NULL)
+        return -1;
+
+      st->sttsSampleCount = (mp4_u32 *)p;
+
+      p = mp4realloc(st->sttsSampleDelta,
+                     2 * sizeof(mp4_u32) * st->sttsMaxEntryCount,
+                     sizeof(mp4_u32) * st->sttsMaxEntryCount);
+      if (p == NULL)
+        return -1;
+
+      st->sttsSampleDelta = (mp4_u32 *)p;
+
+      st->sttsMaxEntryCount *= 2;
+    }
+
+    if (st->sttsSampleDelta[st->sttsEntryCount - 1] == duration)
+    {
+      st->sttsSampleCount[st->sttsEntryCount - 1]++;
+    }
+    else
+    {
+      st->sttsSampleCount[st->sttsEntryCount] = 1;
+      st->sttsSampleDelta[st->sttsEntryCount] = duration;
+
+      st->sttsEntryCount++;
+    }
+  }
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 updateSampleSize(MP4HandleImp handle,
+ *                            sampleTable *st,
+ *                            mp4_u32 size)
+ *
+ * Description:
+ *
+ *   This function updates stsz atom data.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   st        sampleTable
+ *   size      Size of sample in bytes
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   -1        Error
+ *
+ */
+mp4_i32 updateSampleSize(MP4HandleImp handle, sampleTable *st, mp4_u32 size)
+{
+  if (!handle)
+    return -1;
+
+  if (size == 0)
+    return -1;
+
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (st->stszCurrentSampleCount == st->stszMaxSampleCount)
+    {
+      void *p;
+
+      p = mp4realloc(st->stszEntrySize,
+                     2 * sizeof(mp4_u32) * st->stszMaxSampleCount,
+                     sizeof(mp4_u32) * st->stszMaxSampleCount);
+      if (p == NULL)
+        return -1;
+
+      st->stszEntrySize = (mp4_u32 *)p;
+
+      st->stszMaxSampleCount *= 2;
+    }
+
+    st->stszEntrySize[st->stszCurrentSampleCount] = size;
+
+    st->stszCurrentSampleCount++;
+    st->stszSampleCount++;
+  }
+  else
+  {
+    if (st->stszSampleCount == st->stszMaxSampleCount)
+    {
+      void *p;
+
+      p = mp4realloc(st->stszEntrySize,
+                     2 * sizeof(mp4_u32) * st->stszMaxSampleCount,
+                     sizeof(mp4_u32) * st->stszMaxSampleCount);
+      if (p == NULL)
+        return -1;
+
+      st->stszEntrySize = (mp4_u32 *)p;
+
+      st->stszMaxSampleCount *= 2;
+    }
+
+    st->stszEntrySize[st->stszSampleCount] = size;
+
+    st->stszSampleCount++;
+  }
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 updateSampleToChunk(sampleTable *st)
+ *
+ * Description:
+ *
+ *   This function updates stsc atom data.
+ *
+ * Parameters:
+ *
+ *   st        sampleTable
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   -1        Error
+ *
+ */
+mp4_i32 updateSampleToChunk(sampleTable *st)
+{
+  if (st->stscEntryCount != 0)
+    return 0;
+
+
+  st->stscFirstChunk[st->stscEntryCount] = st->currentChunk;
+  st->stscSamplesPerChunk[st->stscEntryCount] = 1;
+  st->stscSampleDescriptionIndex[st->stscEntryCount] = 1;  /* Note: Need to update here for multiple sample entry support */
+  st->stscEntryCount++;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 updateChunkOffset(MP4HandleImp handle,
+ *                             sampleTable *st)
+ *
+ * Description:
+ *
+ *   This function updates stco atom data.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   st        sampleTable
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   -1        Error
+ *
+ */
+mp4_i32 updateChunkOffset(MP4HandleImp handle, sampleTable *st)
+{
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (st->stcoCurrentEntryCount == st->stcoMaxEntryCount)
+    {
+      void *p;
+
+      p = mp4realloc(st->stcoChunkOffset,
+                     2 * sizeof(mp4_u64) * st->stcoMaxEntryCount,
+                     sizeof(mp4_u64) * st->stcoMaxEntryCount);
+      if (p == NULL)
+        return -1;
+
+      st->stcoChunkOffset = (mp4_u64*)p;
+
+      st->stcoMaxEntryCount *= 2;
+    }
+    
+    if (handle->flags & MP4_FLAG_METADATALAST)
+      updateChunkOffset(st, st->stcoCurrentEntryCount, handle->mediaDataBytes);
+    else
+      updateChunkOffset(st, st->stcoCurrentEntryCount, handle->bytesInTmpFile);
+
+    st->stcoCurrentEntryCount++;
+    st->stcoEntryCount++;
+  }
+  else
+  {
+    if (st->stcoEntryCount == st->stcoMaxEntryCount)
+    {
+      void *p;
+
+      p = mp4realloc(st->stcoChunkOffset,
+                     2 * sizeof(mp4_u64) * st->stcoMaxEntryCount,
+                     sizeof(mp4_u64) * st->stcoMaxEntryCount);
+      if (p == NULL)
+        return -1;
+
+      st->stcoChunkOffset = (mp4_u64 *)p;
+
+      st->stcoMaxEntryCount *= 2;
+    }
+
+    if (handle->flags & MP4_FLAG_METADATALAST)
+      updateChunkOffset(st, st->stcoEntryCount, handle->mediaDataBytes);
+    else
+      updateChunkOffset(st, st->stcoEntryCount, handle->bytesInTmpFile);
+
+    st->stcoEntryCount++;
+  }
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 updateSyncSample(MP4HandleImp handle,
+ *                            sampleTable *st)
+ *
+ * Description:
+ *
+ *   This function updates stss atom data.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *   st        sampleTable
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   -1        Error
+ *
+ */
+mp4_i32 updateSyncSample(MP4HandleImp handle, sampleTable *st)
+{
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (st->stssCurrentEntryCount == st->stssMaxEntryCount)
+    {
+      void *p;
+
+      p = mp4realloc(st->stssSampleNumber,
+                     2 * sizeof(mp4_u32) * st->stssMaxEntryCount,
+                     sizeof(mp4_u32) * st->stssMaxEntryCount);
+      if (p == NULL)
+        return -1;
+
+      st->stssSampleNumber = (mp4_u32 *)p;
+
+      st->stssMaxEntryCount *= 2;
+    }
+
+    st->stssSampleNumber[st->stssCurrentEntryCount] = handle->videoSampleNum;
+    st->stssCurrentEntryCount++;
+    st->stssEntryCount++;
+  }
+  else
+  {
+    if (st->stssEntryCount == st->stssMaxEntryCount)
+    {
+      void *p;
+
+      p = mp4realloc(st->stssSampleNumber,
+                     2 * sizeof(mp4_u32) * st->stssMaxEntryCount,
+                     sizeof(mp4_u32) * st->stssMaxEntryCount);
+      if (p == NULL)
+        return -1;
+
+      st->stssSampleNumber = (mp4_u32 *)p;
+
+      st->stssMaxEntryCount *= 2;
+    }
+
+    st->stssSampleNumber[st->stssEntryCount] = handle->videoSampleNum;
+    st->stssEntryCount++;
+  }
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineAudioTrakMetaDataSize(MP4HandleImp handle,
+ *                                          sampleTable *st,
+ *                                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   This function calculates the audio track meta data size.
+ *
+ * Parameters:
+ *
+ *   handle      MP4 library handle
+ *   st          Sample table data
+ *   ts          Atom sizes are returned here
+ *
+ * Return value:
+ *
+ *   0           Success
+ *
+ */
+mp4_i32 determineAudioTrakMetaDataSize(MP4HandleImp handle, sampleTable *st, trakSize *ts)
+{
+  if (handle->type & MP4_TYPE_AMR_NB) /* AMR-NB */
+  {
+    ts->damr = 17;
+    ts->samr = 36 + ts->damr;
+    ts->stsd = 16 + ts->samr;
+  }
+  else if (handle->type & MP4_TYPE_AMR_WB) /* AMR-WB */
+  {
+    ts->damr = 17;
+    ts->sawb = 36 + ts->damr;
+    ts->stsd = 16 + ts->sawb;
+  }
+  else if ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio)) /* QCELP 13K stored in QCELPSampleEntry */
+  {
+    ts->dqcp = 14;
+    ts->sqcp = 36 + ts->dqcp;
+    ts->stsd = 16 + ts->sqcp;
+  } 
+  else if ((handle->type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio)) /* QCELP 13K stored in MP4AudioDescription */
+  {
+    calculateES_DescriptorSize(handle, MP4_TYPE_QCELP_13K);
+    ts->esds = 12 + handle->ES_DescriptorSize; /*37 + handle->audioDecSpecificInfoSize;*/
+    ts->mp4a = 36 + ts->esds;
+    ts->stsd = 16 + ts->mp4a;
+  }
+  else /* MPEG audio */
+  {
+    calculateES_DescriptorSize(handle, MP4_TYPE_MPEG4_AUDIO);
+    ts->esds = 12 + handle->ES_DescriptorSize; /*37 + handle->audioDecSpecificInfoSize;*/
+    ts->mp4a = 36 + ts->esds;
+    ts->stsd = 16 + ts->mp4a;
+  }
+  ts->stts = 16 + st->sttsEntryCount * 8;
+  ts->stsc = 16 + st->stscEntryCount * 12;
+  if (st->stszSampleSize != 0)
+    ts->stsz = 20;
+  else
+    ts->stsz = 20 + st->stszSampleCount * 4;
+  ts->stco = 16 + st->stcoEntryCount * (st->stcoNeed64Bits ? 8 : 4);
+  ts->stbl = 8 + ts->stsd + ts->stts + ts->stsc + ts->stsz + ts->stco;
+  ts->dref = 28;
+  ts->dinf = 8 + ts->dref;
+  ts->smhd = 16;
+  ts->minf = 8 + ts->smhd + ts->dinf + ts->stbl;
+  ts->hdlr = 33;
+
+  if (handle->audioDuration > MP4_INT_MAX)
+  {
+    ts->mdhd = 44;
+    ts->tkhd = 104;
+  }
+  else
+  {
+    ts->mdhd = 32;
+    ts->tkhd = 92;
+  }
+
+  ts->mdia = 8 + ts->mdhd + ts->hdlr + ts->minf;
+  if ( handle->audioUDTA )
+      {
+      ts->udta = 8 + handle->audioUDTA->atomcontentsize;
+      }
+  ts->trak = 8 + ts->tkhd + ts->mdia + ts->udta;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 determineVideoTrakMetaDataSize(MP4HandleImp handle,
+ *                                          sampleTable *st,
+ *                                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   This function calculates the video track meta data size.
+ *
+ * Parameters:
+ *
+ *   handle      MP4 library handle
+ *   st          Sample table data
+ *   ts          Atom sizes are returned here
+ *
+ * Return value:
+ *
+ *   0           Success
+ *
+ */
+mp4_i32 determineVideoTrakMetaDataSize(MP4HandleImp handle, sampleTable *st, trakSize *ts)
+{
+  /* Note: This functions assumes single sample entry per media track. 
+	   If necessary, modify to support multiple sample entries in the future. */
+  if ((handle->type & MP4_TYPE_H263_PROFILE_0) || (handle->type & MP4_TYPE_H263_PROFILE_3))
+  {
+    ts->d263 = 15;
+    ts->s263 = 86 + ts->d263;
+    ts->stsd = 16 + ts->s263;
+  }
+  else /* MPEG-4 */
+   if ((handle->type & MP4_TYPE_MPEG4_VIDEO))		
+  {
+    ts->esds = 37 + handle->videoDecSpecificInfoSize;
+    ts->mp4v = 86 + ts->esds;
+    ts->stsd = 16 + ts->mp4v;
+  }
+  else  /* AVC */
+  if ( containsAvcVideo( handle->type ) )
+  {
+    /* Note: If necessary, add btrt and m4ds boxes here in the future. */
+   ts->avcc = 8 + handle->videoDecSpecificInfoSize; /*handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfigSize;*/
+   ts->avc1 = 86 + ts->avcc;
+   ts->stsd = 16 + ts->avc1;
+  }
+  else
+  {
+  }
+
+  ts->stts = 16 + st->sttsEntryCount * 8;
+  ts->stsc = 16 + st->stscEntryCount * 12;
+  if (st->stszSampleSize != 0)
+    ts->stsz = 20;
+  else
+    ts->stsz = 20 + st->stszSampleCount * 4;
+  ts->stco = 16 + st->stcoEntryCount * (st->stcoNeed64Bits ? 8 : 4);
+  ts->stss = 16 + st->stssEntryCount * 4;
+  if( handle->videoSampleTable->sdtpEntryCount )
+  	ts->sdtp = 4 + 4 + 1 + 3 + handle->videoSampleTable->sdtpEntryCount; //size + 'SDTP' + ver + flags + dependencies
+  else
+    ts->sdtp = 0;
+
+  ts->stbl = 8 + ts->stsd + ts->stts + ts->stsc + ts->stsz + ts->stco + ts->stss + ts->sdtp;
+  ts->dref = 28;
+  ts->dinf = 8 + ts->dref;
+  ts->vmhd = 20;
+  ts->minf = 8 + ts->vmhd + ts->dinf + ts->stbl;
+  ts->hdlr = 33;
+  
+  if (handle->videoDuration > MP4_INT_MAX)
+  {
+    ts->mdhd = 44;
+    ts->tkhd = 104;
+  }
+  else
+  {
+    ts->mdhd = 32;
+    ts->tkhd = 92;
+  }
+
+  ts->mdia = 8 + ts->mdhd + ts->hdlr + ts->minf;
+  if ( handle->videoUDTA )
+    {
+    ts->udta = 8 + handle->videoUDTA->atomcontentsize;  
+    }
+  ts->trak = 8 + ts->tkhd + ts->mdia + ts->udta;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 reUpdateAudioMetaData(sampleTable *st,
+ *                                 mp4_u32 metaDataSize)
+ *
+ * Description:
+ *
+ *   This function updates the chunk offsets in the meta data to point to
+ *   correct places.
+ *
+ * Parameters:
+ *
+ *   st            Sample table data
+ *   metaDataSize  Meta data size
+ *
+ * Return value:
+ *
+ *   0             Success
+ *
+ */
+mp4_i32 reUpdateAudioMetaData(sampleTable *st, mp4_u32 metaDataSize)
+{
+  mp4_u32 i;
+
+
+  for (i = 0; i < st->stcoEntryCount; i++)
+    updateChunkOffset(st, i, st->stcoChunkOffset[i] + metaDataSize + MDAT_HEADER_SIZE);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 reUpdateVideoMetaData(sampleTable *st,
+ *                                 mp4_u32 metaDataSize)
+ *
+ * Description:
+ *
+ *   This function updates the chunk offsets in the meta data to point to
+ *   correct places.
+ *
+ * Parameters:
+ *
+ *   st            Sample table data
+ *   metaDataSize  Meta data size
+ *
+ * Return value:
+ *
+ *   0             Success
+ *
+ */
+mp4_i32 reUpdateVideoMetaData(sampleTable *st, mp4_u32 metaDataSize)
+{
+  mp4_u32 i;
+
+
+  for (i = 0; i < st->stcoEntryCount; i++)
+    updateChunkOffset(st, i, st->stcoChunkOffset[i] + metaDataSize + MDAT_HEADER_SIZE);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeFTYP(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ *   Write FTYP atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeFTYP(MP4HandleImp handle)
+{
+  mp4_u8  *buf;
+  mp4_u32 i = 0;
+  mp4_u8 ftypdelta = 0;
+
+   if ((handle->generate3G2 && !(handle->type &  MP4_TYPE_QCELP_13K)) ||
+       (!handle->generate3G2 && !(handle->type &  MP4_TYPE_AMR_WB)))
+     ftypdelta = 4; /* one more additional compatible brand */
+   else
+     ftypdelta = 0;
+
+   if( containsAvcVideo( handle->type ) )
+   {
+     ftypdelta += 4;
+   }
+   if(handle->bufferWrite)
+		handle->ftypdelta=ftypdelta;
+
+  buf = (mp4_u8 *)mp4malloc(FTYP_SIZE + ftypdelta);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)(FTYP_SIZE + ftypdelta));
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_FTYP);
+  i += 4;
+
+  if ( containsAvcVideo( handle->type ) )
+  {
+      if(handle->generateMP4)
+      {
+	      /* MPEG-4 Major brand */
+	      buf[i++] = 'm';
+	      buf[i++] = 'p';
+	      buf[i++] = '4';
+	      buf[i++] = '2';
+      }
+
+	  else
+	  {
+	    /* AVC is included for 3GPP Release 6 and beyond */
+	    /* Major brand */
+	    buf[i++] = '3';
+	    buf[i++] = 'g';
+	    buf[i++] = 'p';
+	    buf[i++] = '6';
+	  }
+  }
+  else
+  {
+    if(handle->generateMP4)
+    {
+	    /* MPEG-4 Major brand */
+	    buf[i++] = 'm';
+	    buf[i++] = 'p';
+	    buf[i++] = '4';
+	    buf[i++] = '2';
+    }
+    else if(handle->generate3G2)
+    {
+	    /* 3GPP2 Major brand */
+	    buf[i++] = '3';
+	    buf[i++] = 'g';
+	    buf[i++] = '2';
+	    buf[i++] = 'a';
+    }
+    else
+    {
+	    /* 3GPP Major brand */
+	    buf[i++] = '3';
+	    buf[i++] = 'g';
+	    buf[i++] = 'p';
+	    buf[i++] = '4';
+    }
+  }
+
+  /* Minor version */
+  if(handle->generateMP4)
+  {  /* MPEG-4 Minor Version */
+      insertu32(buf+i, (mp4_u32)(0)); /* 0 */
+      i += 4;
+  }
+  else if(handle->generate3G2)
+  {  /* 3GPP2 Minor Version */
+      if( containsAvcVideo( handle->type ) )
+      {
+      	insertu32(buf+i, (mp4_u32)(2*256*256)); /* VB.0.0 */
+      	i += 4;
+      }
+      else
+      {
+      	insertu32(buf+i, (mp4_u32)(1*256*256)); /* VA.0.0 */
+      	i += 4;
+      }
+  }
+  else  
+  { /* 3GPP Minor Version */
+      if( containsAvcVideo( handle->type ) )
+      {
+      	  insertu32(buf+i, (mp4_u32)2*256); /* V6.3.0 */
+      	  i += 4;
+      }
+      else
+      {
+      	  insertu32(buf+i, (mp4_u32)4*256); /* V4.4.0 */
+          i += 4;
+      }
+  }
+
+  /* Compatible brands */
+  if(handle->generateMP4)
+  {/* MPEG-4 Compatible Brands */
+	  buf[i++] = 'm';
+	  buf[i++] = 'p';
+	  buf[i++] = '4';
+	  buf[i++] = '2';
+
+      buf[i++] = '3';
+      buf[i++] = 'g';
+      buf[i++] = 'p';
+      buf[i++] = '4';
+
+      buf[i++] = 'i';
+      buf[i++] = 's';
+      buf[i++] = 'o';
+      buf[i++] = 'm';
+	  if ( containsAvcVideo( handle->type ) )
+	  {
+		  /* AVC is included for 3GPP Release 6 and beyond */
+		  buf[i++] = 'a';
+		  buf[i++] = 'v';
+		  buf[i++] = 'c';
+		  buf[i++] = '1';
+	  }
+  }
+  else if(handle->generate3G2)
+  {/* 3GPP2 Compatible Brands */
+      if( containsAvcVideo( handle->type ) )
+      {
+      	  buf[i++] = '3';
+	      buf[i++] = 'g';
+	      buf[i++] = '2';
+	      buf[i++] = 'b';
+	      if (!(handle->type &  MP4_TYPE_QCELP_13K))
+          { // If 3GPP codecs are used, then put 3GP6 in compatible brands 
+              buf[i++] = '3';
+              buf[i++] = 'g';
+              buf[i++] = 'p';
+              buf[i++] = '6';
+          }
+      }
+      else
+      {
+      	  buf[i++] = '3';
+      	  buf[i++] = 'g';
+      	  buf[i++] = '2';
+      	  buf[i++] = 'a';
+          if (!(handle->type &  MP4_TYPE_QCELP_13K))
+          { // If 3GPP codecs are used, then put 3GP4 in compatible brands 
+              buf[i++] = '3';
+              buf[i++] = 'g';
+              buf[i++] = 'p';
+              buf[i++] = '4';
+          }
+      }
+	  if ( containsAvcVideo( handle->type ) )
+	  {
+		  /* AVC is included for 3GPP Release 6 and beyond */
+		  buf[i++] = 'a';
+		  buf[i++] = 'v';
+		  buf[i++] = 'c';
+		  buf[i++] = '1';
+	  }
+
+      buf[i++] = 'i';
+      buf[i++] = 's';
+      buf[i++] = 'o';
+      buf[i++] = 'm';
+  }
+  else
+  {/* 3GPP Compatible Brands */
+      if ( containsAvcVideo( handle->type ) )
+	  {
+	      buf[i++] = '3';
+	      buf[i++] = 'g';
+	      buf[i++] = 'p';
+	      buf[i++] = '6';
+	  }
+	  else
+	  {
+	      buf[i++] = '3';
+	      buf[i++] = 'g';
+	      buf[i++] = 'p';
+	      buf[i++] = '4';
+	  }
+	  
+      if (!(handle->type &  MP4_TYPE_AMR_WB))
+      { // If 3GPP2 codecs are used, then put 3G2A in compatible brands 
+          buf[i++] = '3';
+          buf[i++] = 'g';
+          buf[i++] = '2';
+          buf[i++] = 'a';
+      }
+
+      buf[i++] = 'i';
+      buf[i++] = 's';
+      buf[i++] = 'o';
+      buf[i++] = 'm';
+
+	  if ( containsAvcVideo( handle->type ) )
+	  {
+		  /* AVC is included for 3GPP Release 6 and beyond */
+		  buf[i++] = 'a';
+		  buf[i++] = 'v';
+		  buf[i++] = 'c';
+		  buf[i++] = '1';
+	  }
+      
+  }
+  if (writeFile(handle, buf, (FTYP_SIZE + ftypdelta)) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeMOOV(MP4HandleImp handle,
+ *                     mp4_u32 moovSize,
+ *                     mp4_bool haveAudio,
+ *                     mp4_bool haveVideo,
+ *                     trakSize *audioTrackSize,
+ *                     trakSize *videoTrackSize)
+ *
+ * Description:
+ *
+ *   Write MOOV atom.
+ *
+ * Parameters:
+ *
+ *   handle          MP4 library handle
+ *   moovSize        Size of MOOV atom in bytes
+ *   haveAudio       Flag to indicate whether audio exists or not
+ *   haveVideo       Flag to indicate whether video exists or not
+ *   audioTrackSize  Size of audio track in bytes
+ *   videoTrackSize  Size of video track in bytes
+ *
+ * Return value:
+ *
+ *   0               Success
+ *   -1              Error
+ *
+ */
+mp4_i32 writeMOOV(MP4HandleImp handle, mp4_u32 moovSize, mp4_bool haveAudio, mp4_bool haveVideo, trakSize *audioTrackSize, trakSize *videoTrackSize)
+{
+  PRINT((_L("e_writemoov 1")));
+  mp4_u8  buf[8];
+  mp4_u32 i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, moovSize);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_MOOV);
+  i += 4;
+
+  PRINT((_L("e_writemoov_header 1")));
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+  PRINT((_L("e_writemoov_header 0")));  
+
+  PRINT((_L("e_writemoov_mvhd 1")));	
+  if (writeMVHD(handle) < 0)
+    return -1;
+  PRINT((_L("e_writemoov_mvhd 0")));
+
+  PRINT((_L("e_writemoov_video 1")));
+  if (haveVideo)
+    if (writeVideoTrak(handle, videoTrackSize) < 0)
+      return -1;
+  PRINT((_L("e_writemoov_video 0")));    
+
+  PRINT((_L("e_writemoov_audio 1")));
+  if (haveAudio)
+    if (writeAudioTrak(handle, audioTrackSize) < 0)
+      return -1;
+  PRINT((_L("e_writemoov_audio 0")));    
+    
+  PRINT((_L("e_writemoov_udta 1")));    
+  if (handle->moovUDTA)
+    {
+    if (writeUDTA(handle, handle->moovUDTA) < 0)
+        {
+        return -1;
+        }
+    }
+  PRINT((_L("e_writemoov_udta 0")));
+  PRINT((_L("e_writemoov 0")));
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeMVHD(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ *   Write MVHD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeMVHD(MP4HandleImp handle)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  u32;
+
+  size_t mvhdSize = mvhdAtomSize(handle);
+      
+  buf = (mp4_u8 *)mp4malloc(mvhdSize);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)mvhdSize);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_MVHD);
+  i += 4;
+
+
+  if (handle->videoDuration > MP4_INT_MAX || handle->audioDuration > MP4_INT_MAX)
+  {
+      /* Version and flags */
+      insertu32(buf+i, (mp4_u32)0x01000000);  //its going to be a version 1 atom
+      i += 4;
+    
+      /* Creation time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu64(buf+i, (mp4_u64)u32);
+      i += 8;
+    
+      /* Modification time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu64(buf+i, (mp4_u64)u32);
+      i += 8;
+    
+      /* Timescale */
+      insertu32(buf+i, (mp4_u32)MVHD_TIMESCALE);
+      i += 4;
+    
+      /* Duration */
+      {
+        mp4_u64  u64;
+        mp4_u64  videoDuration = 0;
+        mp4_u64  audioDuration = 0;
+    
+    
+        if (handle->videoTimeScale)
+          videoDuration = (mp4_u64)((mp4_double)MVHD_TIMESCALE *
+                                    (mp4_double)handle->videoDuration /
+                                    (mp4_double)handle->videoTimeScale +
+                                    (mp4_double)0.5);
+        if (handle->audioTimeScale)
+          audioDuration = (mp4_u64)((mp4_double)MVHD_TIMESCALE *
+                                    (mp4_double)handle->audioDuration /
+                                    (mp4_double)handle->audioTimeScale +
+                                    (mp4_double)0.5);
+    
+        if (audioDuration > videoDuration)
+          u64 = audioDuration;
+        else
+          u64 = videoDuration;
+    
+        insertu64(buf+i, u64);
+        i += 8;
+      }
+ 
+  }
+  else
+  {
+      /* Version and flags */
+      insertu32(buf+i, (mp4_u32)0);
+      i += 4;
+
+      /* Creation time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu32(buf+i, (mp4_u32)u32);
+      i += 4;
+    
+      /* Modification time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu32(buf+i, (mp4_u32)u32);
+      i += 4;
+    
+      /* Timescale */
+      insertu32(buf+i, (mp4_u32)MVHD_TIMESCALE);
+      i += 4;
+    
+      /* Duration */
+      {
+        mp4_u32  videoDuration = 0;
+        mp4_u32  audioDuration = 0;
+    
+    
+        if (handle->videoTimeScale)
+          videoDuration = (mp4_u32)((mp4_double)MVHD_TIMESCALE *
+                                    (mp4_double)handle->videoDuration /
+                                    (mp4_double)handle->videoTimeScale +
+                                    (mp4_double)0.5);
+        if (handle->audioTimeScale)
+          audioDuration = (mp4_u32)((mp4_double)MVHD_TIMESCALE *
+                                    (mp4_double)handle->audioDuration /
+                                    (mp4_double)handle->audioTimeScale +
+                                    (mp4_double)0.5);
+    
+        if (audioDuration > videoDuration)
+          u32 = audioDuration;
+        else
+          u32 = videoDuration;
+    
+        insertu32(buf+i, u32);
+        i += 4;
+      }
+  }
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0x00010000);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)0x0100);
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)0x0000);
+  i += 2;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00010000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00010000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x40000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00010000);
+  i += 4;
+
+  if (writeFile(handle, buf, mvhdSize) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoTrak(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video track atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoTrak(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[8];
+  mp4_u32 i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->trak);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_TRAK);
+  i += 4;
+
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+
+  if (writeVideoTKHD(handle, ts) < 0)
+    return -1;
+
+  if (writeVideoMDIA(handle, ts) < 0)
+    return -1;
+  
+  if (handle->videoUDTA)
+    {
+    if (writeUDTA(handle, handle->videoUDTA) < 0)
+        return -1;
+    }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoTKHD(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write TKHD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoTKHD(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8      *buf;
+  mp4_u32     i = 0;
+  mp4_u32     u32;
+  mp4_double  ud;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->tkhd);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->tkhd);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_TKHD);
+  i += 4;
+
+  
+  if (handle->videoDuration > MP4_INT_MAX)
+  {
+      mp4_u64     u64;
+      /* Version and flags */
+      buf[i++] = 1;     //make this a version 1 atom
+      buf[i++] = 0;
+      buf[i++] = 0;
+      buf[i++] = 7;  /* Track enabled, used in movie and preview */
+    
+      /* Creation time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu64(buf+i, (mp4_u64)u32);
+      i += 8;
+    
+      /* Modification time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu64(buf+i, (mp4_u64)u32);
+      i += 8;
+    
+      /* Track ID */
+      insertu32(buf+i, (mp4_u32)1);
+      i += 4;
+    
+      /* Reserved */
+      insertu32(buf+i, (mp4_u32)0);
+      i += 4;
+    
+      /* Duration */
+      if ( (handle->videoDuration == 0) || (handle->videoTimeScale == 0) )
+          {
+          ud = 0;
+          }
+      else
+          {
+          ud = (mp4_double)MVHD_TIMESCALE * (mp4_double)handle->videoDuration / (mp4_double)handle->videoTimeScale + (mp4_double)0.5;
+          }
+    
+      u64 = (mp4_u64)ud;
+      insertu64(buf+i, u64);
+      i += 8;
+  }
+  else
+  {
+      /* Version and flags */
+      buf[i++] = 0;
+      buf[i++] = 0;
+      buf[i++] = 0;
+      buf[i++] = 7;  /* Track enabled, used in movie and preview */
+    
+      /* Creation time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu32(buf+i, (mp4_u32)u32);
+      i += 4;
+    
+      /* Modification time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu32(buf+i, (mp4_u32)u32);
+      i += 4;
+    
+      /* Track ID */
+      insertu32(buf+i, (mp4_u32)1);
+      i += 4;
+    
+      /* Reserved */
+      insertu32(buf+i, (mp4_u32)0);
+      i += 4;
+    
+      /* Duration */
+      if ( (handle->videoDuration == 0) || (handle->videoTimeScale == 0) )
+          {
+          ud = 0;
+          }
+      else
+          {
+          ud = (mp4_double)MVHD_TIMESCALE * (mp4_double)handle->videoDuration / (mp4_double)handle->videoTimeScale + (mp4_double)0.5;
+          }
+    
+      u32 = (mp4_u32)ud;
+      insertu32(buf+i, u32);
+      i += 4;
+  }
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)0);  /* Visual track */
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)0);
+  i += 2;
+
+  insertu32(buf+i, (mp4_u32)0x00010000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00010000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x40000000);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)handle->videoWidth);  /* Width */
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)0);
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)handle->videoHeight);  /* Height */
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)0);
+  i += 2;
+
+  if (writeFile(handle, buf, ts->tkhd) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoMDIA(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video MDIA atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoMDIA(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[8];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->mdia);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_MDIA);
+  i += 4;
+
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+
+  if (writeVideoMDHD(handle, ts) < 0)
+    return -1;
+
+  if (writeVideoHDLR(handle, ts) < 0)
+    return -1;
+
+  if (writeVideoMINF(handle, ts) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoMDHD(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video MDHD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoMDHD(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  u32;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->mdhd);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->mdhd);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_MDHD);
+  i += 4;
+
+  if (handle->videoDuration > MP4_INT_MAX)
+  {
+      /* Version and flags */
+      insertu32(buf+i, (mp4_u32)0x01000000); //version 1 atom
+      i += 4;
+    
+      /* Creation time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu64(buf+i, (mp4_u64)u32);
+      i += 8;
+    
+      /* Modification time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu64(buf+i, (mp4_u64)u32);
+      i += 8;
+    
+      /* Timescale */
+      insertu32(buf+i, (mp4_u32)handle->videoTimeScale);
+      i += 4;
+    
+      /* Duration */
+      insertu64(buf+i, handle->videoDuration);
+      i += 8;
+  }
+  else
+  {
+      /* Version and flags */
+      insertu32(buf+i, (mp4_u32)0);
+      i += 4;
+    
+      /* Creation time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu32(buf+i, (mp4_u32)u32);
+      i += 4;
+    
+      /* Modification time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu32(buf+i, (mp4_u32)u32);
+      i += 4;
+    
+      /* Timescale */
+      insertu32(buf+i, (mp4_u32)handle->videoTimeScale);
+      i += 4;
+    
+      /* Duration */
+      insertu32(buf+i, (mp4_u32)handle->videoDuration);
+      i += 4;
+  }
+  
+  /* Language */
+  insertu16(buf+i, (mp4_u16)0x55c4); /* 'und' */
+  i += 2;
+
+  /* Reserved */
+  insertu16(buf+i, (mp4_u16)0x0000);
+  i += 2;
+
+  if (writeFile(handle, buf, ts->mdhd) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoHDLR(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video HDLR atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoHDLR(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->hdlr);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->hdlr);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_HDLR);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Handler type */
+  buf[i++] = 'v';
+  buf[i++] = 'i';
+  buf[i++] = 'd';
+  buf[i++] = 'e';
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Empty string */
+  buf[i++] = 0;
+
+  if (writeFile(handle, buf, ts->hdlr) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoMINF(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video MINF atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoMINF(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[8];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->minf);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_MINF);
+  i += 4;
+
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+
+  if (writeVMHD(handle, ts) < 0)
+    return -1;
+
+  if (writeDINF(handle, ts) < 0)
+    return -1;
+
+  if (writeVideoSTBL(handle, ts) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32  writeVMHD(MP4HandleImp handle,
+ *                      trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write VMHD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32  writeVMHD(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->vmhd);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->vmhd);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_VMHD);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0x00000001);
+  i += 4;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  if (writeFile(handle, buf, ts->vmhd) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeDINF(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write DINF atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeDINF(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[8];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->dinf);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_DINF);
+  i += 4;
+
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+
+  if (writeDREF(handle, ts) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32  writeDREF(MP4HandleImp handle,
+ *                      trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write DREF atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32  writeDREF(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->dref);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->dref);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_DREF);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)1);
+  i += 4;
+
+  /* URL atom */
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)12);
+  i += 4;
+
+  /* Type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_URL);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0x00000001);
+  i += 4;
+
+  if (writeFile(handle, buf, ts->dref) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTBL(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STBL atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTBL(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[8];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stbl);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STBL);
+  i += 4;
+
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+
+  if (writeVideoSTSD(handle, ts) < 0)
+    return -1;
+
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (writeVideoSTTSLongClip(handle, ts) < 0)
+      return -1;
+  }
+  else
+  {
+    if (writeVideoSTTS(handle, ts) < 0)
+      return -1;
+  }
+
+  if (writeVideoSTSC(handle, ts) < 0)
+    return -1;
+
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (writeVideoSTSZLongClip(handle, ts) < 0)
+      return -1;
+	
+	if (handle->videoSampleTable->stcoNeed64Bits)
+	{
+      if (writeVideoCO64LongClip(handle, ts) < 0)
+        return -1;
+	}
+	else
+	{
+      if (writeVideoSTCOLongClip(handle, ts) < 0)
+        return -1;
+	}
+
+    if (writeVideoSTSSLongClip(handle, ts) < 0)
+      return -1;
+    
+    if(ts->sdtp && writeVideoSDTPLongClip(handle, ts) < 0)
+      return -1;
+  }
+  else
+  {
+    if (writeVideoSTSZ(handle, ts) < 0)
+      return -1;
+
+	if (handle->videoSampleTable->stcoNeed64Bits)
+	{
+      if (writeVideoCO64(handle, ts) < 0)
+        return -1;
+	}
+	else
+	{
+      if (writeVideoSTCO(handle, ts) < 0)
+        return -1;
+	}
+
+    if (writeVideoSTSS(handle, ts) < 0)
+      return -1;
+    
+    if(ts->sdtp && writeVideoSDTP(handle, ts) < 0)
+      return -1;
+  }
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTSD(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STSD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTSD(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[16];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stsd);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STSD);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)1);
+  i += 4;
+
+  if (writeFile(handle, buf, 16) < 0)
+    return -1;
+
+  if (handle->type & MP4_TYPE_MPEG4_VIDEO)
+  {
+    if (writeMP4V(handle, ts) < 0)
+      return -1;
+  }
+  else if ((handle->type & MP4_TYPE_H263_PROFILE_0) ||
+           (handle->type & MP4_TYPE_H263_PROFILE_3))
+  {
+    if (writeS263(handle, ts) < 0)
+      return -1;
+  }
+  else if ( containsAvcVideo( handle->type ) )
+  {
+	  if (writeAVC1(handle, ts) < 0)
+		  return -1;
+  }
+  else
+  {
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeMP4V(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write MP4V atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeMP4V(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(86);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->mp4v);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_MP4V);
+  i += 4;
+
+  /* Reserved */
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+
+  /* Data reference index */
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Width */
+  insertu16(buf+i, (mp4_u16)handle->videoWidth);
+  i += 2;
+
+  /* Height */
+  insertu16(buf+i, (mp4_u16)handle->videoHeight);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0x00480000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00480000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)24);
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)0xffff);
+  i += 2;
+
+  if (writeFile(handle, buf, 86) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  if (writeVideoESD(handle, ts) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoESD(MP4HandleImp handle,
+ *                         trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video ESD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoESD(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->esds);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->esds);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_ESD);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* ES_DescrTag */
+  buf[i++] = 0x03;
+
+  /* Size */
+  buf[i++] = (mp4_u8)(23 + handle->videoDecSpecificInfoSize);
+
+  /* ES_ID */
+  insertu16(buf+i, (mp4_u16)0);
+  i += 2;
+
+  /* Flags */
+  buf[i++] = 0;
+
+  /* DecoderConfigDescrTag */
+  buf[i++] = 0x04;
+
+  /* Size */
+  buf[i++] = (mp4_u8)(15 + handle->videoDecSpecificInfoSize);
+
+  /* ObjectTypeIndication */
+  buf[i++] = 0x20;
+
+  /* Flags */
+  buf[i++] = 0x11;
+
+  /* BufferSizeDB */
+  buf[i++] = 0x00;
+  buf[i++] = 0x50;
+  buf[i++] = 0x00;
+
+  /* MaxBitrate */
+  insertu32(buf+i, (mp4_u32)handle->videoMaxBitrate);
+  i += 4;
+
+  /* AvgBitrate */
+  insertu32(buf+i, (mp4_u32)handle->videoAvgBitrate);
+  i += 4;
+
+  /* DecSpecificInfoTag */
+  buf[i++] = 0x05;
+
+  /* Size */
+  buf[i++] = (mp4_u8)handle->videoDecSpecificInfoSize;
+
+  /* DecoderSpecificInfo */
+  mp4memcpy(buf+i, handle->videoDecSpecificInfo, handle->videoDecSpecificInfoSize);
+  i += handle->videoDecSpecificInfoSize;
+
+  /* SLConfigDescrTag */
+  buf[i++] = 0x06;
+
+  /* Size */
+  buf[i++] = 1;
+
+  /* */
+  buf[i++] = 2;
+
+  if (writeFile(handle, buf, ts->esds) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeS263(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write S263 atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeS263(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(86);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->s263);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_S263);
+  i += 4;
+
+  /* Reserved */
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+
+  /* Data reference index */
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Width */
+  insertu16(buf+i, (mp4_u16)handle->videoWidth);
+  i += 2;
+
+  /* Height */
+  insertu16(buf+i, (mp4_u16)handle->videoHeight);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0x00480000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00480000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)24);
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)0xffff);
+  i += 2;
+
+  if (writeFile(handle, buf, 86) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  if (writeD263(handle, ts) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeD263(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write D263 atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeD263(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[15];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->d263);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_D263);
+  i += 4;
+
+  /* Vendor */
+  buf[i++] = 'S';
+  buf[i++] = '6';
+  buf[i++] = '0';
+  buf[i++] = ' ';
+
+  /* Decoder version */
+  buf[i++] = 0;
+
+  /* H263_Level */
+  buf[i++] = handle->videoLevel;
+
+  /* H263_Profile */
+  if (handle->type & MP4_TYPE_H263_PROFILE_0)
+    buf[i++] = 0;
+  else if (handle->type & MP4_TYPE_H263_PROFILE_3)
+    buf[i++] = 3;
+  else
+    return -1;
+
+  if (writeFile(handle, buf, 15) < 0)
+    return -1;
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAVC1(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write AVC1 atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAVC1(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(86);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->avc1);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_AVC1);
+  i += 4;
+
+  /* Reserved */
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+
+  /* Data reference index */
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Width */
+  insertu16(buf+i, (mp4_u16)handle->videoWidth);
+  i += 2;
+
+  /* Height */
+  insertu16(buf+i, (mp4_u16)handle->videoHeight);
+  i += 2;
+
+  /* H-res (default is 72dpi = 0x00480000) */
+  insertu32(buf+i, (mp4_u32)0x00480000);
+  i += 4;
+
+  /* V-res (default is 72dpi = 0x00480000) */
+  insertu32(buf+i, (mp4_u32)0x00480000);
+  i += 4;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+  
+  /* Frame count (default is 1) */
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  /* Compressor name (32 byte string) */
+  // The spec *recommends* inserting "\012AVC Coding" here
+  // but we just have a string of nulls.
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Depth (default is 0x0018 which indicates colour images with no alpha) */
+  insertu16(buf+i, (mp4_u16)24);
+  i += 2;
+
+  /* Pre-defined (-1) */
+  insertu16(buf+i, (mp4_u16)0xffff);
+  i += 2;
+
+  if (writeFile(handle, buf, 86) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  if (writeAVCC(handle, ts) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  /* Note: If necessary, include writing of btrt and m4ds atoms. */
+
+  mp4free(buf);
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAVCC(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write AVCC atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAVCC(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->avcc);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->avcc);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_AVCC);
+  i += 4;
+
+  /*mp4memcpy(buf+i, handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfig, 
+									 handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfigSize);*/
+  
+  mp4memcpy(buf+i, handle->videoDecSpecificInfo, handle->videoDecSpecificInfoSize);
+
+  /*i += handle->moov->trakVideo->mdia->minf->stbl->stsd->avc1[0]->avcc->avcConfigSize;*/
+
+  i += handle->videoDecSpecificInfoSize;
+
+  if (writeFile(handle, buf, ts->avcc) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTTS(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STTS atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTTS(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8   *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stts);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stts);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STTS);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->sttsEntryCount);
+  i += 4;
+
+  /* Sample count and sample delta */
+  for (j = 0; j < handle->videoSampleTable->sttsEntryCount; j++)
+  {
+    insertu32(buf+i, (mp4_u32)handle->videoSampleTable->sttsSampleCount[j]);
+    i += 4;
+    insertu32(buf+i, (mp4_u32)handle->videoSampleTable->sttsSampleDelta[j]);
+    i += 4;
+  }
+
+  if (writeFile(handle, buf, ts->stts) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTTSLongClip(MP4HandleImp handle,
+ *                                  trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STTS atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTTSLongClip(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8   *buf;
+  mp4_u8   *buf2;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+  mp4_u32  left;
+  mp4_u32  bytestoread;
+
+
+  buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE);
+  if (buf == NULL)
+    return -1;
+
+  buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE / 2);
+  if (buf2 == NULL)
+    {
+    mp4free(buf);
+    return -1;
+    }
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stts);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STTS);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->sttsEntryCount);
+  i += 4;
+
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+
+    return -1;
+  }
+
+  /* Sample count and delta */
+
+  /* Seek to the beginning of temporary files */
+
+  if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STTS_SAMPLE_COUNT) < 0)
+      {
+      mp4free(buf);
+      mp4free(buf2);
+      return -1;
+      }
+  if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STTS_SAMPLE_DELTA) < 0)
+      {
+      mp4free(buf);
+      mp4free(buf2);
+      return -1;
+      }
+
+  left = handle->videoSampleTable->sttsEntryCount * 4; /* Bytes left in each file */
+
+  while (left)
+  {
+    if (left > METADATA_COPY_BUFFERSIZE / 2)
+      bytestoread = METADATA_COPY_BUFFERSIZE / 2;
+    else
+      bytestoread = left;
+
+    if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STTS_SAMPLE_COUNT) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    for (j = 0; j < bytestoread; j += 4)
+    {
+      insertu32(buf + 2*j, ((mp4_u32 *)buf2)[j / 4]);
+    }
+
+    if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STTS_SAMPLE_DELTA) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    for (j = 0; j < bytestoread; j += 4)
+    {
+      insertu32(buf + 2*j + 4, ((mp4_u32 *)buf2)[j / 4]);
+    }
+
+    if (writeFile(handle, buf, 2 * bytestoread) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    left -= bytestoread;
+  }
+
+  mp4free(buf);
+  mp4free(buf2);
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTSC(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STSC atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTSC(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8   *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stsc);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stsc);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STSC);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stscEntryCount);
+  i += 4;
+
+  /* First chunk, samples per chunk and sample description index */
+  for (j = 0; j < handle->videoSampleTable->stscEntryCount; j++)
+  {
+    insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stscFirstChunk[j]);
+    i += 4;
+    insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stscSamplesPerChunk[j]);
+    i += 4;
+    insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stscSampleDescriptionIndex[j]);
+    i += 4;
+  }
+
+  if (writeFile(handle, buf, ts->stsc) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTSZ(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STSZ atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTSZ(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stsz);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stsz);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STSZ);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Sample size */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stszSampleSize);
+  i += 4;
+
+  /* Sample count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stszSampleCount);
+  i += 4;
+
+  /* Entry sizes */
+  if (handle->videoSampleTable->stszSampleSize == 0)
+  {
+    for (j = 0; j < handle->videoSampleTable->stszSampleCount; j++)
+    {
+      insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stszEntrySize[j]);
+      i += 4;
+    }
+  }
+
+  if (writeFile(handle, buf, ts->stsz) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTSZLongClip(MP4HandleImp handle,
+ *                                  trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STSZ atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTSZLongClip(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u8  *buf2;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+  mp4_u32  left;
+  mp4_u32  bytestoread;
+
+
+  buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE);
+  if (buf == NULL)
+    return -1;
+
+  buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE);
+  if (buf2 == NULL)
+    {
+    mp4free(buf);
+    return -1;
+    }
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stsz);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STSZ);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Sample size */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stszSampleSize);
+  i += 4;
+
+  /* Sample count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stszSampleCount);
+  i += 4;
+
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+
+    return -1;
+  }
+
+  /* Entry sizes */
+
+  if (handle->videoSampleTable->stszSampleSize == 0)
+  {
+    /* Seek to the beginning of temporary file */
+
+    if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STSZ_ENTRY_SIZE) < 0)
+        {
+        mp4free(buf);
+        mp4free(buf2);
+        return -1;
+        }
+
+    left = handle->videoSampleTable->stszSampleCount * 4; /* Bytes left in the file */
+
+    while (left)
+    {
+      if (left > METADATA_COPY_BUFFERSIZE)
+        bytestoread = METADATA_COPY_BUFFERSIZE;
+      else
+        bytestoread = left;
+
+      if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STSZ_ENTRY_SIZE) < 0)
+      {
+        mp4free(buf);
+        mp4free(buf2);
+
+        return -1;
+      }
+
+      for (j = 0; j < bytestoread; j += 4)
+      {
+        insertu32(buf + j, ((mp4_u32 *)buf2)[j / 4]);
+      }
+
+      if (writeFile(handle, buf, bytestoread) < 0)
+      {
+        mp4free(buf);
+        mp4free(buf2);
+
+        return -1;
+      }
+
+      left -= bytestoread;
+    }
+  }
+
+  mp4free(buf);
+  mp4free(buf2);
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTCO(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STCO atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTCO(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stco);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stco);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STCO);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stcoEntryCount);
+  i += 4;
+
+  /* Chunk offsets */
+  for (j = 0; j < handle->videoSampleTable->stcoEntryCount; j++)
+  {
+    insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stcoChunkOffset[j]);
+    i += 4;
+  }
+
+  if (writeFile(handle, buf, ts->stco) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoCO64(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video CO64 atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoCO64(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stco);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stco);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_CO64);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stcoEntryCount);
+  i += 4;
+
+  /* Chunk offsets */
+  for (j = 0; j < handle->videoSampleTable->stcoEntryCount; j++)
+  {
+    insertu64(buf+i, (mp4_u64)handle->videoSampleTable->stcoChunkOffset[j]);
+    i += 8;
+  }
+
+  if (writeFile(handle, buf, ts->stco) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTCOLongClip(MP4HandleImp handle,
+ *                                  trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STCO atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTCOLongClip(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8   *buf;
+  mp4_u8   *buf2;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+  mp4_u32  left;
+  mp4_u32  bytestoread;
+  mp4_u32  bufferSize = (METADATA_COPY_BUFFERSIZE/sizeof(mp4_u64)) * sizeof(mp4_u64); //must be a multiple of u64
+  																					  //METADATA_COPY_BUFFERSIZE is only guaranteed to be a multiple of 4
+	
+  buf = (mp4_u8 *)mp4malloc(bufferSize);
+  if (buf == NULL)
+    return -1;
+
+  buf2 = (mp4_u8 *)mp4malloc(bufferSize);
+  if (buf2 == NULL)
+    {
+    mp4free(buf);
+    return -1;
+    }
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stco);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STCO);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stcoEntryCount);
+  i += 4;
+
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+
+    return -1;
+  }
+
+  /* Chunk offsets */
+
+  /* Seek to the beginning of temporary file */
+
+  if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STCO_CHUNK_OFFSET) < 0)
+    {
+    mp4free(buf);
+    mp4free(buf2);
+    return -1;
+    }
+
+  left = handle->videoSampleTable->stcoEntryCount * 8; /* Bytes left in the file */
+
+  while (left)
+  {
+    if (left > bufferSize)
+      bytestoread = bufferSize;
+    else
+      bytestoread = left;
+
+    if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STCO_CHUNK_OFFSET) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    for (j = 0; j < bytestoread; j += 8)
+    {
+      ((mp4_u64 *)buf2)[j / 8] += (handle->metaDataSize + MDAT_HEADER_SIZE); /* Update chunk offsets */
+      insertu32(buf + j/2, ((mp4_u64 *)buf2)[j / 8]);
+    }
+
+    if (writeFile(handle, buf, bytestoread/2) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    left -= bytestoread;
+  }
+
+  mp4free(buf);
+  mp4free(buf2);
+
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoCO64LongClip(MP4HandleImp handle,
+ *                                  trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video CO64 atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoCO64LongClip(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8   *buf;
+  mp4_u8   *buf2;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+  mp4_u32  left;
+  mp4_u32  bytestoread;
+  mp4_u32  bufferSize = (METADATA_COPY_BUFFERSIZE/sizeof(mp4_u64)) * sizeof(mp4_u64); //must be a multiple of u64
+  																					  //METADATA_COPY_BUFFERSIZE is only guaranteed to be a multiple of 4
+	
+  buf = (mp4_u8 *)mp4malloc(bufferSize);
+  if (buf == NULL)
+    return -1;
+
+  buf2 = (mp4_u8 *)mp4malloc(bufferSize);
+  if (buf2 == NULL)
+    {
+    mp4free(buf);
+    return -1;
+    }
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stco);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_CO64);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stcoEntryCount);
+  i += 4;
+
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+
+    return -1;
+  }
+
+  /* Chunk offsets */
+
+  /* Seek to the beginning of temporary file */
+
+  if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STCO_CHUNK_OFFSET) < 0)
+    {
+    mp4free(buf);
+    mp4free(buf2);
+    return -1;
+    }
+
+  left = handle->videoSampleTable->stcoEntryCount * 8; /* Bytes left in the file */
+
+  while (left)
+  {
+    if (left > bufferSize)
+      bytestoread = bufferSize;
+    else
+      bytestoread = left;
+
+    if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STCO_CHUNK_OFFSET) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    for (j = 0; j < bytestoread; j += 8)
+    {
+      ((mp4_u64 *)buf2)[j / 8] += (handle->metaDataSize + MDAT_HEADER_SIZE); /* Update chunk offsets */
+      insertu64(buf + j, ((mp4_u64 *)buf2)[j / 8]);
+    }
+
+    if (writeFile(handle, buf, bytestoread) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    left -= bytestoread;
+  }
+
+  mp4free(buf);
+  mp4free(buf2);
+
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTSS(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STSS atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTSS(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stss);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stss);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STSS);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stssEntryCount);
+  i += 4;
+
+  /* Sample numbers */
+  for (j = 0; j < handle->videoSampleTable->stssEntryCount; j++)
+  {
+    insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stssSampleNumber[j]);
+    i += 4;
+  }
+
+  if (writeFile(handle, buf, ts->stss) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSTSSLongClip(MP4HandleImp handle,
+ *                                  trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video STSS atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSTSSLongClip(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8   *buf;
+  mp4_u8   *buf2;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+  mp4_u32  left;
+  mp4_u32  bytestoread;
+
+
+  buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE);
+  if (buf == NULL)
+    return -1;
+
+  buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE);
+  if (buf2 == NULL)
+      {
+      mp4free(buf);
+      return -1;
+      }
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stss);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STSS);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->videoSampleTable->stssEntryCount);
+  i += 4;
+
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+
+    return -1;
+  }
+
+  /* Sample numbers */
+
+  /* Seek to the beginning of temporary file */
+
+  if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_STSS_SAMPLE_NUMBER) < 0)
+    {
+    mp4free(buf);
+    mp4free(buf2);
+    return -1;
+    }
+
+  left = handle->videoSampleTable->stssEntryCount * 4; /* Bytes left in the file */
+
+  while (left)
+  {
+    if (left > METADATA_COPY_BUFFERSIZE)
+      bytestoread = METADATA_COPY_BUFFERSIZE;
+    else
+      bytestoread = left;
+
+    if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_STSS_SAMPLE_NUMBER) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    for (j = 0; j < bytestoread; j += 4)
+    {
+      insertu32(buf + j, ((mp4_u32 *)buf2)[j / 4]);
+    }
+
+    if (writeFile(handle, buf, bytestoread) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    left -= bytestoread;
+  }
+
+  mp4free(buf);
+  mp4free(buf2);
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioTrak(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio track atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioTrak(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[8];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->trak);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_TRAK);
+  i += 4;
+
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+
+  if (writeAudioTKHD(handle, ts) < 0)
+    return -1;
+
+  if (writeAudioMDIA(handle, ts) < 0)
+    return -1;
+  
+  if (handle->audioUDTA)
+    {
+    if (writeUDTA(handle, handle->audioUDTA) < 0)
+        return -1;
+    }  
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioTKHD(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio TKHD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioTKHD(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8      *buf;
+  mp4_u32     i = 0;
+  mp4_u32     u32;
+  mp4_double  ud;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->tkhd);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->tkhd);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_TKHD);
+  i += 4;
+
+  
+  if (handle->audioDuration > MP4_INT_MAX)
+  {
+      mp4_u64     u64;
+      /* Version and flags */
+      buf[i++] = 1;
+      buf[i++] = 0;
+      buf[i++] = 0;
+      buf[i++] = 7;  /* Track enabled, used in movie and preview */
+    
+      /* Creation time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu64(buf+i, (mp4_u64)u32);
+      i += 8;
+    
+      /* Modification time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu64(buf+i, (mp4_u64)u32);
+      i += 8;
+    
+      /* Track ID */
+      insertu32(buf+i, (mp4_u32)2);
+      i += 4;
+    
+      /* Reserved */
+      insertu32(buf+i, (mp4_u32)0);
+      i += 4;
+    
+      /* Duration */
+      if ( ( handle->audioTimeScale == 0 ) || ( handle->audioDuration == 0 ) )
+          {
+          ud = 0;
+          }
+      else
+          {
+          ud = (mp4_double)MVHD_TIMESCALE * (mp4_double)handle->audioDuration / (mp4_double)handle->audioTimeScale + (mp4_double)0.5;
+          }
+      u64 = (mp4_u64)ud;
+      insertu64(buf+i, u64);
+      i += 8;
+
+  }
+  else
+  {
+      /* Version and flags */
+      buf[i++] = 0;
+      buf[i++] = 0;
+      buf[i++] = 0;
+      buf[i++] = 7;  /* Track enabled, used in movie and preview */
+    
+      /* Creation time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu32(buf+i, (mp4_u32)u32);
+      i += 4;
+    
+      /* Modification time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu32(buf+i, (mp4_u32)u32);
+      i += 4;
+    
+      /* Track ID */
+      insertu32(buf+i, (mp4_u32)2);
+      i += 4;
+    
+      /* Reserved */
+      insertu32(buf+i, (mp4_u32)0);
+      i += 4;
+    
+      /* Duration */
+      if ( ( handle->audioTimeScale == 0 ) || ( handle->audioDuration == 0 ) )
+          {
+          ud = 0;
+          }
+      else
+          {
+          ud = (mp4_double)MVHD_TIMESCALE * (mp4_double)handle->audioDuration / (mp4_double)handle->audioTimeScale + (mp4_double)0.5;
+          }
+      u32 = (mp4_u32)ud;
+      insertu32(buf+i, u32);
+      i += 4;
+  }
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)0x0100);  /* Audio track */
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)0);
+  i += 2;
+
+  insertu32(buf+i, (mp4_u32)0x00010000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00010000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x40000000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);  /* Audio track */
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);  /* Audio track */
+  i += 4;
+
+  if (writeFile(handle, buf, ts->tkhd) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioMDIA(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio MDIA atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioMDIA(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[8];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->mdia);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_MDIA);
+  i += 4;
+
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+
+  if (writeAudioMDHD(handle, ts) < 0)
+    return -1;
+
+  if (writeAudioHDLR(handle, ts) < 0)
+    return -1;
+
+  if (writeAudioMINF(handle, ts) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioMDHD(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio MDHD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioMDHD(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  u32;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->mdhd);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->mdhd);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_MDHD);
+  i += 4;
+
+  if (handle->audioDuration > MP4_INT_MAX)
+  {
+      /* Version and flags */
+      insertu32(buf+i, (mp4_u32)0x1000000);     //version 1 atom
+      i += 4;
+    
+      /* Creation time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu64(buf+i, (mp4_u64)u32);
+      i += 8;
+    
+      /* Modification time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu64(buf+i, (mp4_u64)u32);
+      i += 8;
+    
+      /* Timescale */
+      insertu32(buf+i, (mp4_u32)handle->audioTimeScale);
+      i += 4;
+    
+      /* Duration */
+      insertu64(buf+i, handle->audioDuration);
+      i += 8;
+      
+  }
+  else
+  {
+      /* Version and flags */
+      insertu32(buf+i, (mp4_u32)0);
+      i += 4;
+    
+      /* Creation time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu32(buf+i, (mp4_u32)u32);
+      i += 4;
+    
+      /* Modification time */
+      if (getCurrentTime(&u32) < 0)
+        u32 = 0;
+      insertu32(buf+i, (mp4_u32)u32);
+      i += 4;
+    
+      /* Timescale */
+      insertu32(buf+i, (mp4_u32)handle->audioTimeScale);
+      i += 4;
+    
+      /* Duration */
+      insertu32(buf+i, (mp4_u32)handle->audioDuration);
+      i += 4;
+  }
+
+  /* Language */
+  insertu16(buf+i, (mp4_u16)0x55c4); /* 'und' */
+  i += 2;
+
+  /* Reserved */
+  insertu16(buf+i, (mp4_u16)0x0000);
+  i += 2;
+
+  if (writeFile(handle, buf, ts->mdhd) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioHDLR(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio HDLR atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioHDLR(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->hdlr);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->hdlr);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_HDLR);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Handler type */
+  buf[i++] = 's';
+  buf[i++] = 'o';
+  buf[i++] = 'u';
+  buf[i++] = 'n';
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Empty string */
+  buf[i++] = 0;
+
+  if (writeFile(handle, buf, ts->hdlr) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioMINF(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio MINF atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioMINF(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[8];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->minf);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_MINF);
+  i += 4;
+
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+
+  if (writeSMHD(handle, ts) < 0)
+    return -1;
+
+  if (writeDINF(handle, ts) < 0)
+    return -1;
+
+  if (writeAudioSTBL(handle, ts) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32  writeSMHD(MP4HandleImp handle,
+ *                      trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write SMHD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32  writeSMHD(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->smhd);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->smhd);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_SMHD);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  if (writeFile(handle, buf, ts->smhd) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioSTBL(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio STBL atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioSTBL(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[8];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stbl);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STBL);
+  i += 4;
+
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+
+  if (writeAudioSTSD(handle, ts) < 0)
+    return -1;
+
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (writeAudioSTTSLongClip(handle, ts) < 0)
+      return -1;
+  }
+  else
+  {
+    if (writeAudioSTTS(handle, ts) < 0)
+      return -1;
+  }
+
+  if (writeAudioSTSC(handle, ts) < 0)
+    return -1;
+
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (writeAudioSTSZLongClip(handle, ts) < 0)
+      return -1;
+    
+	if (handle->audioSampleTable->stcoNeed64Bits)
+	{
+	  if (writeAudioCO64LongClip(handle, ts) < 0)
+      	return -1;
+	}
+	else
+	{
+	  if (writeAudioSTCOLongClip(handle, ts) < 0)
+        return -1;
+	}
+  }
+  else
+  {
+    if (writeAudioSTSZ(handle, ts) < 0)
+      return -1;
+
+	if (handle->audioSampleTable->stcoNeed64Bits)
+	{
+      if (writeAudioCO64(handle, ts) < 0)
+        return -1;
+	}
+	else
+	{
+      if (writeAudioSTCO(handle, ts) < 0)
+        return -1;
+	}
+  }
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32  writeAudioSTSD(MP4HandleImp handle,
+ *                           trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio STSD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioSTSD(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[16];
+  mp4_u32 i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stsd);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STSD);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)1);
+  i += 4;
+
+  if (writeFile(handle, buf, 16) < 0)
+    return -1;
+
+  if (handle->type & MP4_TYPE_MPEG4_AUDIO)
+  {
+    if (writeMP4A(handle, ts) < 0)
+      return -1;
+  }
+  else if (handle->type & MP4_TYPE_AMR_NB)
+  {
+    if (writeSAMR(handle, ts) < 0)
+      return -1;
+  }
+  else if (handle->type & MP4_TYPE_AMR_WB)
+  {
+    if (writeSAWB(handle, ts) < 0)
+      return -1;
+  }
+  else if ((handle->type & MP4_TYPE_QCELP_13K) && (!handle->qcelpStoredAsMPEGAudio))
+  {
+    if (writeSQCP(handle, ts) < 0)
+      return -1;
+  }
+  else if ((handle->type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio))
+  {
+    if (writeMP4A(handle, ts) < 0)
+      return -1;
+  }
+  else
+  {
+  }
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeMP4A(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write MP4A atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeMP4A(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(36);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->mp4a);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_MP4A);
+  i += 4;
+
+  /* Reserved */
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+
+  /* Data reference index */
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)2);
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)16);
+  i += 2;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Timescale */
+  insertu16(buf+i, (mp4_u16)handle->audioTimeScale);
+  i += 2;
+
+  /* Reserved */
+  insertu16(buf+i, (mp4_u16)0);
+  i += 2;
+
+  if (writeFile(handle, buf, 36) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  if (writeAudioESD(handle, ts) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioESD(MP4HandleImp handle,
+ *                         trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio ESD atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioESD(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  bitrate = 0;
+  mp4_u32 num_of_bytes = 0;
+  mp4_u32 size = 0;
+  mp4_u32 index = 0;
+  mp4_u32 tempnum = 0;
+
+  mp4_u32 size1, size2;
+  mp4_u32 numofsizebytes1, numofsizebytes2;
+
+  buf = (mp4_u8 *)mp4malloc(ts->esds);
+  if (buf == NULL)
+    return -1;
+
+  /* Calculate the necessary size information */
+  size1 = handle->audioDecSpecificInfoSize;
+  if (size1 < 128)
+    numofsizebytes1 = 1;
+  else
+  {
+      numofsizebytes1 = 1;
+      while ( size1 >= 128 ) 
+      {
+        size1 = size1 >> 7;
+        numofsizebytes1++;
+      }  
+  }
+
+  size2 = 14 + numofsizebytes1 + handle->audioDecSpecificInfoSize;
+   if (size2 < 128)
+      numofsizebytes2 = 1;
+    else
+    {
+        numofsizebytes2 = 1;
+        while ( size2 >= 128 ) 
+        {
+          size2 = size2 >> 7;
+          numofsizebytes2++;
+        }  
+    }
+    /* End of size calculations */
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->esds);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_ESD);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* ES_DescrTag */
+  buf[i++] = 0x03;
+
+  /* Size */
+  size = 21 + numofsizebytes1 + numofsizebytes2 + handle->audioDecSpecificInfoSize; 
+  if (size < 128)
+    buf[i++] = (mp4_u8)(size);
+  else
+  {
+      num_of_bytes = 0;
+      while ( size >= 128 ) 
+      {
+        size = size >> 7;
+        num_of_bytes++;
+      }  
+      size = 21 + numofsizebytes1 + numofsizebytes2 + handle->audioDecSpecificInfoSize; 
+      for(index = num_of_bytes; index > 0; index--)  
+      {
+        tempnum = size >> (7 * index); 
+        buf[i++] = (mp4_u8)(0x80 | (mp4_u8) tempnum);
+        size -= (tempnum << (7 * index));
+      }
+      buf[i++] = (mp4_u8)size;
+  }
+
+  /* ES_ID */
+  insertu16(buf+i, (mp4_u16)0);
+  i += 2;
+
+  /* Flags */
+  buf[i++] = 0;
+
+  /* DecoderConfigDescrTag */
+  buf[i++] = 0x04;
+
+  /* Size */
+  size =  14 + numofsizebytes1 + handle->audioDecSpecificInfoSize; 
+  if (size < 128)
+    buf[i++] = (mp4_u8)(size);
+  else
+  {
+      num_of_bytes = 0;
+      while ( size >= 128 ) 
+      {
+        size = size >> 7;
+        num_of_bytes++;
+      }  
+      size =  14 + numofsizebytes1 + handle->audioDecSpecificInfoSize; 
+      for(index = num_of_bytes; index > 0; index--)  
+      {
+        tempnum = size >> (7 * index); 
+        buf[i++] = (mp4_u8)(0x80 | (mp4_u8) tempnum);
+        size -= (tempnum << (7 * index));
+      }
+      buf[i++] = (mp4_u8)size;
+  }
+
+  /* ObjectTypeIndication */
+  if (handle->type & MP4_TYPE_MPEG4_AUDIO)
+    buf[i++] = 0x40;
+  else if ((handle->type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio))
+    buf[i++] = 0xE1;
+  else
+  {
+  }
+
+  /* Flags */
+  buf[i++] = 0x15;
+
+  /* BufferSizeDB */
+  if (handle->type & MP4_TYPE_MPEG4_AUDIO) 
+  {
+      buf[i++] = 0x00;
+      buf[i++] = 0x00;
+      buf[i++] = 0x00;
+  }
+  else if ((handle->type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio))
+  { /* 4096 for QCELP 13K */
+      buf[i++] = 0x00;
+      buf[i++] = 0x10;
+      buf[i++] = 0x00;
+  }
+  else
+  {
+  }
+
+
+  if ((handle->audioDuration != 0) && (handle->audioTimeScale != 0))
+    bitrate = (mp4_u32)((mp4_double)8 *
+                              (mp4_double)handle->audioMediaDataSize /
+                              ((mp4_double)handle->audioDuration /
+                               (mp4_double)handle->audioTimeScale));
+  else
+    bitrate = 0;
+
+  /* MaxBitrate */
+  insertu32(buf+i, (mp4_u32)bitrate); /*0x00010000*/
+  i += 4;
+
+  /* AvgBitrate */
+  insertu32(buf+i, (mp4_u32)bitrate);/*0x00008000*/
+  i += 4;
+
+  /* DecSpecificInfoTag */
+  buf[i++] = 0x05;
+
+  /* Size */
+  size = handle->audioDecSpecificInfoSize;
+  if (size < 128)
+    buf[i++] = (mp4_u8)(size);
+  else
+  {
+      num_of_bytes = 0;
+      while ( size >= 128 ) 
+      {
+        size = size >> 7;
+        num_of_bytes++;
+      }  
+      size = handle->audioDecSpecificInfoSize;
+      for(index = num_of_bytes; index > 0; index--)  
+      {
+        tempnum = size >> (7 * index); 
+        buf[i++] = (mp4_u8)(0x80 | (mp4_u8) tempnum);
+        size -= (tempnum << (7 * index));
+      }
+      buf[i++] = (mp4_u8)size;
+  }
+
+  /* DecoderSpecificInfo */
+  mp4memcpy(buf+i, handle->audioDecSpecificInfo, handle->audioDecSpecificInfoSize);
+  i += handle->audioDecSpecificInfoSize;
+
+  /* SLConfigDescrTag */
+  buf[i++] = 0x06;
+
+  /* Size */
+  buf[i++] = 1;
+
+  /* */
+  buf[i++] = 2;
+
+  if (writeFile(handle, buf, ts->esds) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeSAMR(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write SAMR atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32  writeSAMR(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(36);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->samr);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_SAMR);
+  i += 4;
+
+  /* Reserved */
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+
+  /* Data reference index */
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)2);
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)16);
+  i += 2;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Timescale */
+  insertu16(buf+i, (mp4_u16)handle->audioTimeScale);
+  i += 2;
+
+  /* Reserved */
+  insertu16(buf+i, (mp4_u16)0);
+  i += 2;
+
+  if (writeFile(handle, buf, 36) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  if (writeDAMR(handle, ts) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeSAWB(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write SAWB atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeSAWB(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32 i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(36);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->sawb);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_SAWB);
+  i += 4;
+
+  /* Reserved */
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+
+  /* Data reference index */
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)2);
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)16);
+  i += 2;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Timescale */
+  insertu16(buf+i, (mp4_u16)handle->audioTimeScale);
+  i += 2;
+
+  /* Reserved */
+  insertu16(buf+i, (mp4_u16)0);
+  i += 2;
+
+  if (writeFile(handle, buf, 36) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  if (writeDAMR(handle, ts) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeDAMR(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write DAMR atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeDAMR(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[17];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->damr);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_DAMR);
+  i += 4;
+
+  /* Vendor */
+  buf[i++] = 'S';
+  buf[i++] = '6';
+  buf[i++] = '0';
+  buf[i++] = ' ';
+
+  /* Decoder version */
+  buf[i++] = 0;
+
+  /* Mode set */
+  insertu16(buf+i, (mp4_u16)handle->audioModeSet);
+  i += 2;
+
+  /* Mode change period */
+  buf[i++] = 0;
+
+  /* Frames per sample */
+  buf[i++] = handle->audioFramesPerSample;
+
+  if (writeFile(handle, buf, 17) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioSTTS(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio STTS atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioSTTS(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stts);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stts);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STTS);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->sttsEntryCount);
+  i += 4;
+
+  /* Sample count and sample delta */
+  for (j = 0; j < handle->audioSampleTable->sttsEntryCount; j++)
+  {
+    insertu32(buf+i, (mp4_u32)handle->audioSampleTable->sttsSampleCount[j]);
+    i += 4;
+    insertu32(buf+i, (mp4_u32)handle->audioSampleTable->sttsSampleDelta[j]);
+    i += 4;
+  }
+
+  if (writeFile(handle, buf, ts->stts) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioSTTSLongClip(MP4HandleImp handle,
+ *                                  trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio STTS atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioSTTSLongClip(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8   *buf;
+  mp4_u8   *buf2;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+  mp4_u32  left;
+  mp4_u32  bytestoread;
+
+
+  buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE);
+  if (buf == NULL)
+    return -1;
+
+  buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE / 2);
+  if (buf2 == NULL)
+      {
+      mp4free(buf);
+      return -1;
+      }
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stts);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STTS);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->sttsEntryCount);
+  i += 4;
+
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+
+    return -1;
+  }
+
+  /* Sample count and delta */
+
+  /* Seek to the beginning of temporary files */
+
+  if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_AUDIO_STTS_SAMPLE_COUNT) < 0)
+      {
+      mp4free(buf);
+      mp4free(buf2);
+      return -1;
+      }
+  if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_AUDIO_STTS_SAMPLE_DELTA) < 0)
+      {
+      mp4free(buf);
+      mp4free(buf2);
+      return -1;
+      }
+
+  left = handle->audioSampleTable->sttsEntryCount * 4; /* Bytes left in each file */
+
+  while (left)
+  {
+    if (left > METADATA_COPY_BUFFERSIZE / 2)
+      bytestoread = METADATA_COPY_BUFFERSIZE / 2;
+    else
+      bytestoread = left;
+
+    if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_AUDIO_STTS_SAMPLE_COUNT) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    for (j = 0; j < bytestoread; j += 4)
+    {
+      insertu32(buf + 2*j, ((mp4_u32 *)buf2)[j / 4]);
+    }
+
+    if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_AUDIO_STTS_SAMPLE_DELTA) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    for (j = 0; j < bytestoread; j += 4)
+    {
+      insertu32(buf + 2*j + 4, ((mp4_u32 *)buf2)[j / 4]);
+    }
+
+    if (writeFile(handle, buf, 2 * bytestoread) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    left -= bytestoread;
+  }
+
+  mp4free(buf);
+  mp4free(buf2);
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioSTSC(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio STSC atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioSTSC(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stsc);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stsc);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STSC);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stscEntryCount);
+  i += 4;
+
+  /* First chunk, samples per chunk and sample description index */
+  for (j = 0; j < handle->audioSampleTable->stscEntryCount; j++)
+  {
+    insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stscFirstChunk[j]);
+    i += 4;
+    insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stscSamplesPerChunk[j]);
+    i += 4;
+    insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stscSampleDescriptionIndex[j]);
+    i += 4;
+  }
+
+  if (writeFile(handle, buf, ts->stsc) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioSTSZ(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio STSZ atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioSTSZ(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stsz);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stsz);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STSZ);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Sample size */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stszSampleSize);
+  i += 4;
+
+  /* Sample count */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stszSampleCount);
+  i += 4;
+
+  /* Entry sizes */
+  if (handle->audioSampleTable->stszSampleSize == 0)
+  {
+    for (j = 0; j < handle->audioSampleTable->stszSampleCount; j++)
+    {
+      insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stszEntrySize[j]);
+      i += 4;
+    }
+  }
+
+  if (writeFile(handle, buf, ts->stsz) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioSTSZLongClip(MP4HandleImp handle,
+ *                                  trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio STSZ atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioSTSZLongClip(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u8  *buf2;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+  mp4_u32  left;
+  mp4_u32  bytestoread;
+
+
+  buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE);
+  if (buf == NULL)
+    return -1;
+
+  buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE);
+  if (buf2 == NULL)
+      {
+      mp4free(buf);
+      return -1;
+      }
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stsz);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STSZ);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Sample size */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stszSampleSize);
+  i += 4;
+
+  /* Sample count */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stszSampleCount);
+  i += 4;
+
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+
+    return -1;
+  }
+
+  /* Entry sizes */
+
+  if (handle->audioSampleTable->stszSampleSize == 0)
+  {
+    /* Seek to the beginning of temporary file */
+
+    if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_AUDIO_STSZ_ENTRY_SIZE) < 0)
+        {
+        mp4free(buf);
+        mp4free(buf2);
+        return -1;
+        }
+
+    left = handle->audioSampleTable->stszSampleCount * 4; /* Bytes left in the file */
+
+    while (left)
+    {
+      if (left > METADATA_COPY_BUFFERSIZE)
+        bytestoread = METADATA_COPY_BUFFERSIZE;
+      else
+        bytestoread = left;
+
+      if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_AUDIO_STSZ_ENTRY_SIZE) < 0)
+      {
+        mp4free(buf);
+        mp4free(buf2);
+
+        return -1;
+      }
+
+      for (j = 0; j < bytestoread; j += 4)
+      {
+        insertu32(buf + j, ((mp4_u32 *)buf2)[j / 4]);
+      }
+
+      if (writeFile(handle, buf, bytestoread) < 0)
+      {
+        mp4free(buf);
+        mp4free(buf2);
+
+        return -1;
+      }
+
+      left -= bytestoread;
+    }
+  }
+
+  mp4free(buf);
+  mp4free(buf2);
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioSTCO(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio STCO atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioSTCO(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stco);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stco);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STCO);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stcoEntryCount);
+  i += 4;
+
+  /* Chunk offsets */
+  for (j = 0; j < handle->audioSampleTable->stcoEntryCount; j++)
+  {
+    insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stcoChunkOffset[j]);
+    i += 4;
+  }
+
+  if (writeFile(handle, buf, ts->stco) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioCO64(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio CO64 atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioCO64(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+
+  buf = (mp4_u8 *)mp4malloc(ts->stco);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stco);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_CO64);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stcoEntryCount);
+  i += 4;
+
+  /* Chunk offsets */
+  for (j = 0; j < handle->audioSampleTable->stcoEntryCount; j++)
+  {
+    insertu64(buf+j, (mp4_u64)handle->audioSampleTable->stcoChunkOffset[j]);
+  }
+
+  if (writeFile(handle, buf, ts->stco) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioSTCOLongClip(MP4HandleImp handle,
+ *                                  trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio STCO atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioSTCOLongClip(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8   *buf;
+  mp4_u8   *buf2;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+  mp4_u32  left;
+  mp4_u32  bytestoread;
+  mp4_u32  bufferSize = (METADATA_COPY_BUFFERSIZE/sizeof(mp4_u64)) * sizeof(mp4_u64); //must be a multiple of u64
+  																					  //METADATA_COPY_BUFFERSIZE is only guaranteed to be a multiple of 4
+
+
+  buf = (mp4_u8 *)mp4malloc(bufferSize);
+  if (buf == NULL)
+    return -1;
+
+  buf2 = (mp4_u8 *)mp4malloc(bufferSize);
+  if (buf2 == NULL)
+      {
+      mp4free(buf);
+      return -1;
+      }
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stco);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_STCO);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stcoEntryCount);
+  i += 4;
+
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+
+    return -1;
+  }
+
+  /* Chunk offsets */
+
+  /* Seek to the beginning of temporary file */
+
+  if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_AUDIO_STCO_CHUNK_OFFSET) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+    return -1;
+  }
+
+  left = handle->audioSampleTable->stcoEntryCount * 8; /* Bytes left in the file */
+
+  while (left)
+  {
+    if (left > bufferSize)
+      bytestoread = bufferSize;
+    else
+      bytestoread = left;
+
+    if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_AUDIO_STCO_CHUNK_OFFSET) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    for (j = 0; j < bytestoread; j += 8)
+    {
+      ((mp4_u64 *)buf2)[j / 8] += (handle->metaDataSize + MDAT_HEADER_SIZE); /* Update chunk offsets */
+      insertu32(buf + j/2, ((mp4_u64 *)buf2)[j / 8]);
+    }
+
+    if (writeFile(handle, buf, bytestoread/2) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    left -= bytestoread;
+  }
+
+  mp4free(buf);
+  mp4free(buf2);
+
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAudioCO64LongClip(MP4HandleImp handle,
+ *                                  trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write audio CO64 atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAudioCO64LongClip(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8   *buf;
+  mp4_u8   *buf2;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+  mp4_u32  left;
+  mp4_u32  bytestoread;
+  mp4_u32  bufferSize = (METADATA_COPY_BUFFERSIZE/sizeof(mp4_u64)) * sizeof(mp4_u64); //must be a multiple of u64
+  																					  //METADATA_COPY_BUFFERSIZE is only guaranteed to be a multiple of 4
+
+
+  buf = (mp4_u8 *)mp4malloc(bufferSize);
+  if (buf == NULL)
+    return -1;
+
+  buf2 = (mp4_u8 *)mp4malloc(bufferSize);
+  if (buf2 == NULL)
+      {
+      mp4free(buf);
+      return -1;
+      }
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->stco);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_CO64);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Entry count */
+  insertu32(buf+i, (mp4_u32)handle->audioSampleTable->stcoEntryCount);
+  i += 4;
+
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+
+    return -1;
+  }
+
+  /* Chunk offsets */
+
+  /* Seek to the beginning of temporary file */
+
+  if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_AUDIO_STCO_CHUNK_OFFSET) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+    return -1;
+  }
+
+  left = handle->audioSampleTable->stcoEntryCount * 8; /* Bytes left in the file */
+
+  while (left)
+  {
+    if (left > bufferSize)
+      bytestoread = bufferSize;
+    else
+      bytestoread = left;
+
+    if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_AUDIO_STCO_CHUNK_OFFSET) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    for (j = 0; j < bytestoread; j += 8)
+    {
+      ((mp4_u64 *)buf2)[j / 8] += (handle->metaDataSize + MDAT_HEADER_SIZE); /* Update chunk offsets */
+      insertu64(buf + j, ((mp4_u64 *)buf2)[j / 8]);
+    }
+
+    if (writeFile(handle, buf, bytestoread) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    left -= bytestoread;
+  }
+
+  mp4free(buf);
+  mp4free(buf2);
+
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeMediaData(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ *   This function writes media data to the output file.
+ *
+ *   Before writing media data to the output file, meta data has
+ *   been written to the file. Media data that is in tmpfile is
+ *   read from there and written to the end of the output file.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   -1        Error
+ *
+ */
+mp4_i32 writeMediaData(MP4HandleImp handle)
+{
+  mp4_u8  *buf;
+  mp4_u32 i = 0;
+  mp4_u64 left;
+  mp4_u32 bytestoread;
+
+
+  buf = (mp4_u8 *)mp4malloc(1024);
+  if (buf == NULL)
+    return -1;
+
+
+  i = formatMdatHeader(buf, handle->bytesInTmpFile);
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  /* Seek to the beginning of tmpfile */
+  if (seekTmpFileAbs(handle, 0) < 0)
+      {
+      mp4free(buf);
+      return -1;
+      }
+
+  left = handle->bytesInTmpFile;
+
+  while (left)
+  {
+    if (left > 1024)
+      bytestoread = 1024;
+    else
+      bytestoread = left;
+
+    if (readTmpFile(handle, buf, bytestoread) < 0)
+    {
+      mp4free(buf);
+
+      return -1;
+    }
+
+    if (writeFile(handle, buf, bytestoread) < 0)
+    {
+      mp4free(buf);
+
+      return -1;
+    }
+
+    left -= bytestoread;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 insertu64(mp4_u8 *buf,
+ *                     mp4_u64 value)
+ *
+ * Description:
+ *
+ *   This function writes value into buf taking into account the endianism
+ *   of the current computer.
+ *
+ *   It is assumed that the caller of the function has allocated enough
+ *   space for buf.
+ *
+ * Parameters:
+ *
+ *   buf      Buffer to write to
+ *   value    Value to write to buf
+ *
+ * Return value:
+ *
+ *   0        Success
+ *
+ */
+mp4_i32 insertu64(mp4_u8 *buf, mp4_u64 value)
+{
+  mp4_u64 u64;
+
+
+  u64 = u64endian(value);
+  mp4memcpy(buf, &u64, sizeof(mp4_u64));
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 insertu32(mp4_u8 *buf,
+ *                     mp4_u32 value)
+ *
+ * Description:
+ *
+ *   This function writes value into buf taking into account the endianism
+ *   of the current computer.
+ *
+ *   It is assumed that the caller of the function has allocated enough
+ *   space for buf.
+ *
+ * Parameters:
+ *
+ *   buf      Buffer to write to
+ *   value    Value to write to buf
+ *
+ * Return value:
+ *
+ *   0        Success
+ *
+ */
+mp4_i32 insertu32(mp4_u8 *buf, mp4_u32 value)
+{
+  mp4_u32 u32;
+
+
+  u32 = u32endian(value);
+  mp4memcpy(buf, &u32, 4);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 insertu16(mp4_u8 *buf,
+ *                     mp4_u16 value)
+ *
+ * Description:
+ *
+ *   This function writes value into buf taking into account the endianism
+ *   of the current computer.
+ *
+ *   It is assumed that the caller of the function has allocated enough
+ *   space for buf.
+ *
+ * Parameters:
+ *
+ *   buf      Buffer to write to
+ *   value    Value to write to buf
+ *
+ * Return value:
+ *
+ *   0        Success
+ *
+ */
+mp4_i32 insertu16(mp4_u8 *buf, mp4_u16 value)
+{
+  mp4_u16 u16;
+
+
+  u16 = u16endian(value);
+  mp4memcpy(buf, &u16, 2);
+
+  return 0;
+}
+
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeMetaDataTmp(MP4HandleImp handle)
+ *
+ * Description:
+ *
+ *   This function writes metadata accumulated in memory to the disk.
+ *
+ * Parameters:
+ *
+ *   handle    MP4 library handle
+ *
+ * Return value:
+ *
+ *   0         Success
+ *   -1        Error
+ *
+ */
+mp4_i32 writeMetaDataTmp(MP4HandleImp handle)
+{
+  PRINT((_L("e_writemetadatatmp 1")));
+  if (handle->videoSampleTable)
+  {
+  	PRINT((_L("e_writemetadatatmp_writemetadata_video 1")));
+    if (writeMetaDataFileNum(handle,
+                             (mp4_u8 *)handle->videoSampleTable->sttsSampleCount,
+                             handle->videoSampleTable->sttsCurrentEntryCount * sizeof(mp4_u32),
+                             METADATAFILE_VIDEO_STTS_SAMPLE_COUNT) < 0)
+      return -1;
+
+    if (writeMetaDataFileNum(handle,
+                             (mp4_u8 *)handle->videoSampleTable->sttsSampleDelta,
+                             handle->videoSampleTable->sttsCurrentEntryCount * sizeof(mp4_u32),
+                             METADATAFILE_VIDEO_STTS_SAMPLE_DELTA) < 0)
+      return -1;
+
+    if (writeMetaDataFileNum(handle,
+                             (mp4_u8 *)handle->videoSampleTable->stszEntrySize,
+                             handle->videoSampleTable->stszCurrentSampleCount * sizeof(mp4_u32),
+                             METADATAFILE_VIDEO_STSZ_ENTRY_SIZE) < 0)
+      return -1;
+
+    if (writeMetaDataFileNum(handle,
+                             (mp4_u8 *)handle->videoSampleTable->stcoChunkOffset,
+                             handle->videoSampleTable->stcoCurrentEntryCount * sizeof(mp4_u64),
+                             METADATAFILE_VIDEO_STCO_CHUNK_OFFSET) < 0)
+      return -1;
+
+    if (writeMetaDataFileNum(handle,
+                             (mp4_u8 *)handle->videoSampleTable->stssSampleNumber,
+                             handle->videoSampleTable->stssCurrentEntryCount * sizeof(mp4_u32),
+                             METADATAFILE_VIDEO_STSS_SAMPLE_NUMBER) < 0)
+      return -1;
+
+    if (writeMetaDataFileNum(handle,
+                             (mp4_u8 *)handle->videoSampleTable->sdtpSampleDependency,
+                             handle->videoSampleTable->sdtpCurrentEntryCount * sizeof(mp4_u8),
+                             METADATAFILE_VIDEO_SDTP_SAMPLE_DEPENDENCY) < 0)
+      return -1;
+  	PRINT((_L("e_writemetadatatmp_writemetadata_video 0")));
+  }
+
+  if (handle->audioSampleTable)
+  {
+  	PRINT((_L("e_writemetadatatmp_writemetadata_audio 1")));
+    if (writeMetaDataFileNum(handle,
+                             (mp4_u8 *)handle->audioSampleTable->sttsSampleCount,
+                             handle->audioSampleTable->sttsCurrentEntryCount * sizeof(mp4_u32),
+                             METADATAFILE_AUDIO_STTS_SAMPLE_COUNT) < 0)
+      return -1;
+
+    if (writeMetaDataFileNum(handle,
+                             (mp4_u8 *)handle->audioSampleTable->sttsSampleDelta,
+                             handle->audioSampleTable->sttsCurrentEntryCount * sizeof(mp4_u32),
+                             METADATAFILE_AUDIO_STTS_SAMPLE_DELTA) < 0)
+      return -1;
+
+    if (writeMetaDataFileNum(handle,
+                             (mp4_u8 *)handle->audioSampleTable->stszEntrySize,
+                             handle->audioSampleTable->stszCurrentSampleCount * sizeof(mp4_u32),
+                             METADATAFILE_AUDIO_STSZ_ENTRY_SIZE) < 0)
+      return -1;
+
+    if (writeMetaDataFileNum(handle,
+                             (mp4_u8 *)handle->audioSampleTable->stcoChunkOffset,
+                             handle->audioSampleTable->stcoCurrentEntryCount * sizeof(mp4_u64),
+                             METADATAFILE_AUDIO_STCO_CHUNK_OFFSET) < 0)
+      return -1;
+  	PRINT((_L("e_writemetadatatmp_writemetadata_audio 0")));      
+  }
+
+	if (handle->videoSampleTable)
+		{
+  		handle->videoSampleTable->sttsCurrentEntryCount  = 0;
+  		handle->videoSampleTable->stszCurrentSampleCount = 0;
+  		handle->videoSampleTable->stcoCurrentEntryCount  = 0;
+  		handle->videoSampleTable->stssCurrentEntryCount  = 0;
+  		handle->videoSampleTable->sdtpCurrentEntryCount  = 0;  
+		}
+
+	if (handle->audioSampleTable)
+		{		
+  		handle->audioSampleTable->sttsCurrentEntryCount  = 0;
+  		handle->audioSampleTable->stszCurrentSampleCount = 0;
+  		handle->audioSampleTable->stcoCurrentEntryCount  = 0;		
+		}
+
+  handle->metaDataBlocks = 0;
+  handle->metaDataOnDisk = MP4TRUE;
+
+  PRINT((_L("e_writemetadatatmp 0")));
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeSQCP(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write SQCP atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32  writeSQCP(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(36);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->sqcp);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_SQCP);
+  i += 4;
+
+  /* Reserved */
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+
+  /* Data reference index */
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)2);
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)16);
+  i += 2;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Timescale */
+  insertu16(buf+i, (mp4_u16)handle->audioTimeScale);
+  i += 2;
+
+  /* Reserved */
+  insertu16(buf+i, (mp4_u16)0);
+  i += 2;
+
+  if (writeFile(handle, buf, 36) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  if (writeDQCP(handle, ts) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeDQCP(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write DQCP atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeDQCP(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  buf[14];
+  mp4_u32  i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->dqcp);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_DQCP);
+  i += 4;
+
+  /* Vendor */
+  buf[i++] = 'n';
+  buf[i++] = 'o';
+  buf[i++] = 'k';
+  buf[i++] = 'i';
+
+  /* Decoder version */
+  buf[i++] = 0;
+
+  /* Mode set */
+//  insertu16(buf+i, (mp4_u16)handle->audioModeSet);
+//  i += 2;
+
+  /* Mode change period */
+//  buf[i++] = 0;
+
+  /* Frames per sample */
+  buf[i++] = handle->audioFramesPerSample;
+
+  if (writeFile(handle, buf, 14) < 0)
+    return -1;
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 calculateES_DescriptorSize(mp4_u32 type)
+ *
+ * Description:
+ *
+ *   Calculated the ES_Descriptor size inside the ESDS box.
+ *    Updates handle->ES_DescriptorSize;
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *  type        the media type:
+ *                  MP4_TYPE_QCELP_13K
+ *                  MP4_TYPE_MPEG_AUDIO
+ *                  MP4_TYPE_MPEG4_VIDEO 
+ *
+ * Return value:
+ *
+ *   0        Success
+ *
+ */
+mp4_i32 calculateES_DescriptorSize(MP4HandleImp handle, mp4_u32 type)
+{
+  mp4_u32 size1, size2, size3;
+  mp4_u32 numofsizebytes1, numofsizebytes2, numofsizebytes3;
+  mp4_u32 decspecinfosize = 0;
+
+  if (((type & MP4_TYPE_QCELP_13K) && (handle->qcelpStoredAsMPEGAudio)) ||
+        (type & MP4_TYPE_MPEG4_AUDIO))
+    decspecinfosize = handle->audioDecSpecificInfoSize;
+  else /* MPEG video case */
+    decspecinfosize = handle->videoDecSpecificInfoSize;
+
+  size1 = decspecinfosize;
+  if (size1 < 128)
+    numofsizebytes1 = 1;
+  else
+  {
+      numofsizebytes1 = 1;
+      while ( size1 >= 128 ) 
+      {
+        size1 = size1 >> 7;
+        numofsizebytes1++;
+      }  
+  }
+
+  size2 = 14 + numofsizebytes1 + decspecinfosize;
+   if (size2 < 128)
+      numofsizebytes2 = 1;
+    else
+    {
+        numofsizebytes2 = 1;
+        while ( size2 >= 128 ) 
+        {
+          size2 = size2 >> 7;
+          numofsizebytes2++;
+        }  
+    }
+
+  size3 = 21 + numofsizebytes1 + numofsizebytes2 + decspecinfosize;
+   if (size3 < 128)
+      numofsizebytes3 = 1;
+    else
+    {
+        numofsizebytes3 = 1;
+        while ( size3 >= 128 ) 
+        {
+          size3 = size3 >> 7;
+          numofsizebytes3++;
+        }  
+    }
+
+    /* ES_DescriptorSize contains the size of the ES_Descriptor Field, including the 0x03 (ES_ID Tag) */
+    handle->ES_DescriptorSize =  21 + numofsizebytes1 + numofsizebytes2 + decspecinfosize + numofsizebytes3 + 1;
+    return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeUDTA(MP4HandleImp handle,
+ *                     userDataAtom *udta)
+ *
+ * Description:
+ *
+ *   Write UDTA atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32  writeUDTA(MP4HandleImp handle, userDataAtom *udta)
+{
+  mp4_u8  buf[8];
+  mp4_u32 i = 0;
+
+
+  /* Size */
+  insertu32(buf+i, 8 + (mp4_u32)udta->atomcontentsize);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_UDTA);
+  i += 4;
+
+  if (writeFile(handle, buf, 8) < 0)
+    return -1;
+
+  if (writeFile(handle, udta->contentdata, udta->atomcontentsize) < 0)
+    return -1;
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 updateVideoDependencyMetaData(MP4HandleImp handle,
+ *                                         mp4_u8 aDependsOn,
+ *                                         mp4_u8 aIsDependentOn,
+ *                                         mp4_u8 aHasRedundancy)
+ *
+ * Description:
+ *
+ *   Updates SDTP video dependency data
+ *
+ * Parameters:
+ *
+ *   handle          MP4 library handle
+ *   aDependsOn      This frame's dependency on other frames
+ *   aIsDependentOn  Other frames's dependency on this frame
+ *   aHasRedundancy  Whether there is redundant coding in this frame
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 updateVideoDependencyMetaData(MP4HandleImp handle, mp4_u8 aDependsOn, mp4_u8 aIsDependentOn, mp4_u8 aHasRedundancy)
+{
+  if (handle->flags & MP4_FLAG_LONGCLIP)
+  {
+    if (handle->videoSampleTable->sdtpCurrentEntryCount == handle->videoSampleTable->sdtpMaxEntryCount)
+    {
+      void *p;
+
+      p = mp4realloc(handle->videoSampleTable->sdtpSampleDependency,
+                     2 * sizeof(mp4_u8) * handle->videoSampleTable->sdtpMaxEntryCount,
+                     sizeof(mp4_u8) * handle->videoSampleTable->stssMaxEntryCount);
+      if (p == NULL)
+        return -1;
+
+      handle->videoSampleTable->sdtpSampleDependency = (mp4_u8 *)p;
+
+      handle->videoSampleTable->sdtpMaxEntryCount *= 2;
+    }
+
+    handle->videoSampleTable->sdtpSampleDependency[handle->videoSampleTable->sdtpCurrentEntryCount] = (aDependsOn << 4) | (aIsDependentOn << 2) | (aHasRedundancy);
+    handle->videoSampleTable->sdtpCurrentEntryCount++;
+    handle->videoSampleTable->sdtpEntryCount++;
+  }
+  else
+  {
+    if (handle->videoSampleTable->sdtpEntryCount == handle->videoSampleTable->sdtpMaxEntryCount)
+    {
+      void *p;
+
+      p = mp4realloc(handle->videoSampleTable->sdtpSampleDependency,
+                     2 * sizeof(mp4_u8) * handle->videoSampleTable->sdtpMaxEntryCount,
+                     sizeof(mp4_u8) * handle->videoSampleTable->sdtpMaxEntryCount);
+      if (p == NULL)
+        return -1;
+
+      handle->videoSampleTable->sdtpSampleDependency = (mp4_u8 *)p;
+
+      handle->videoSampleTable->sdtpMaxEntryCount *= 2;
+    }
+
+    handle->videoSampleTable->sdtpSampleDependency[handle->videoSampleTable->sdtpEntryCount] = (aDependsOn << 4) | (aIsDependentOn << 2) | (aHasRedundancy);
+    handle->videoSampleTable->sdtpEntryCount++;
+  }
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSDTP(MP4HandleImp handle,
+ *                          trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video SDTP atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSDTP(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+  mp4_u32  j;
+
+  buf = (mp4_u8 *)mp4malloc(ts->sdtp);
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->sdtp);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_SDTP);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Sample dependencies */
+  for (j = 0; j < handle->videoSampleTable->sdtpEntryCount; j++)
+  {
+    buf[i++] = (mp4_u8)handle->videoSampleTable->sdtpSampleDependency[j];
+  }
+
+  if (writeFile(handle, buf, ts->sdtp) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+
+  mp4free(buf);
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeVideoSDTPLongClip(MP4HandleImp handle,
+ *                                  trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write video SDTP atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeVideoSDTPLongClip(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8   *buf;
+  mp4_u8   *buf2;
+  mp4_u32  i = 0;
+  mp4_u32  left;
+  mp4_u32  bytestoread;
+
+
+  buf = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE);
+  if (buf == NULL)
+    return -1;
+
+  buf2 = (mp4_u8 *)mp4malloc(METADATA_COPY_BUFFERSIZE / 2);
+  if (buf2 == NULL)
+    {
+    mp4free(buf);
+    return -1;
+    }
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->sdtp);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_SDTP);
+  i += 4;
+
+  /* Version and flags */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  if (writeFile(handle, buf, i) < 0)
+  {
+    mp4free(buf);
+    mp4free(buf2);
+
+    return -1;
+  }
+
+  /* Sample count and delta */
+
+  /* Seek to the beginning of temporary files */
+
+  if (seekMetaDataFileNumAbs(handle, 0, METADATAFILE_VIDEO_SDTP_SAMPLE_DEPENDENCY) < 0)
+      {
+      mp4free(buf);
+      mp4free(buf2);
+      return -1;
+      }
+
+  left = handle->videoSampleTable->sdtpEntryCount; /* Bytes left in each file */
+
+  while (left)
+  {
+    if (left > METADATA_COPY_BUFFERSIZE / 2)
+      bytestoread = METADATA_COPY_BUFFERSIZE / 2;
+    else
+      bytestoread = left;
+
+    if (readMetaDataFileNum(handle, buf2, bytestoread, METADATAFILE_VIDEO_SDTP_SAMPLE_DEPENDENCY) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    if (writeFile(handle, buf2, bytestoread) < 0)
+    {
+      mp4free(buf);
+      mp4free(buf2);
+
+      return -1;
+    }
+
+    left -= bytestoread;
+  }
+
+  mp4free(buf);
+  mp4free(buf2);
+
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 writeAVCP(MP4HandleImp handle,
+ *                     trakSize *ts)
+ *
+ * Description:
+ *
+ *   Write AVCP atom.
+ *
+ * Parameters:
+ *
+ *   handle   MP4 library handle
+ *   ts       Atom sizes
+ *
+ * Return value:
+ *
+ *   0        Success
+ *   -1       Error
+ *
+ */
+mp4_i32 writeAVCP(MP4HandleImp handle, trakSize *ts)
+{
+  mp4_u8  *buf;
+  mp4_u32  i = 0;
+
+
+  buf = (mp4_u8 *)mp4malloc(86+7); // 86 = size of VisualSampleEntry, 7 = size of AVCDecoderConfigurationRecord
+  								 // with PPS and SPS sizes set to 0
+  if (buf == NULL)
+    return -1;
+
+  /* Size */
+  insertu32(buf+i, (mp4_u32)ts->avcp);
+  i += 4;
+
+  /* Atom type */
+  insertu32(buf+i, (mp4_u32)ATOMTYPE_AVCP);
+  i += 4;
+
+  /* Reserved */
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+  buf[i++] = 0;
+
+  /* Data reference index */
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  /* Width */
+  insertu16(buf+i, (mp4_u16)handle->videoWidth);
+  i += 2;
+
+  /* Height */
+  insertu16(buf+i, (mp4_u16)handle->videoHeight);
+  i += 2;
+
+  /* Reserved */
+  insertu32(buf+i, (mp4_u32)0x00480000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0x00480000);
+  i += 4;
+
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)1);
+  i += 2;
+
+// Compressorname
+  buf[i++] = 14;
+  insertu32(buf+i, (mp4_u32)0x41564320); // "AVC "
+  i += 4;
+  insertu32(buf+i, (mp4_u32)0x70617261); // "para"
+  i += 4;
+  insertu32(buf+i, (mp4_u32)0x6d657465); // "mete"
+  i += 4;
+  insertu16(buf+i, (mp4_u16)0x7273); // "rs"
+  i += 2;
+  buf[i++] = 0;
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+  insertu32(buf+i, (mp4_u32)0);
+  i += 4;
+
+  insertu16(buf+i, (mp4_u16)24);
+  i += 2;
+
+  insertu16(buf+i, (mp4_u16)0xffff);
+  i += 2;
+
+  // AVCC without picparams & seqparams
+  mp4memcpy(buf+i, handle->videoDecSpecificInfo, 5); // 5 = configurationVersion + AVCProfileIndication +
+													 //     profile_compatibility + AVCLevelIndication +
+													 //     '111111' + lengthSizeMinusOne (2 bits)
+  i += 5;
+  buf[i++] = 0xE0 | 0; // '111' + numOfSequenceParameterSets (5 bits)
+  buf[i++] = 0;        // numOfPictureParameterSets
+  
+  if (writeFile(handle, buf, 86+7) < 0)
+  {
+    mp4free(buf);
+
+    return -1;
+  }
+  
+  mp4free(buf);
+
+  return 0;
+}
+
+/*
+ * Function:
+ *
+ *   mp4_i32 formatMdatHeader(mp4_u8 *buffer, 
+ *                            mp4_u64 size)
+ *
+ * Description:
+ *
+ *   Formats the MDAT header into buffer
+ *
+ * Parameters:
+ *
+ *   buffer   buffer to write the MDAT header into
+ *   size     Size of the media data (excluding the MDAT header)
+ *
+ * Return value:
+ *
+ *   size of header
+ *
+ */
+mp4_i32 formatMdatHeader(mp4_u8 *buf, mp4_u64 size)
+{
+  TInt i = 0;
+  if (size < MP4_INT_MAX)
+  {
+  	//insert free box
+    insertu32(buf, (mp4_u32)8);
+    i += sizeof(mp4_u32);
+    insertu32(buf + i, (mp4_u32)ATOMTYPE_FREE);
+    i += sizeof(mp4_u32);
+    
+    //insert mdat box
+    insertu32(buf + i, (mp4_u32)size + 8);
+    i += sizeof(mp4_u32);
+    insertu32(buf + i, (mp4_u32)ATOMTYPE_MDAT);
+    i += sizeof(mp4_u32);
+  }
+  else
+  {
+    //insert mdat box
+    insertu32(buf + i, (mp4_u32)1);
+    i += sizeof(mp4_u32);
+    insertu32(buf + i, (mp4_u32)ATOMTYPE_MDAT);
+    i += sizeof(mp4_u32);
+	insertu64(buf + i, (mp4_u64)size + 16);        
+	i += sizeof(mp4_u64);
+  }
+
+  ASSERT(MDAT_HEADER_SIZE == i);  
+  return i;
+}
+	
+// End of File