shithub: aacdec

Download patch

ref: 7b5ba33ae15aaa2a01dd04bac88ffa6f0fb09d8c
parent: 976c310f1d8d21d5f76415d124522dbda55f0b79
author: menno <menno>
date: Thu Dec 11 13:32:39 EST 2003

Peter Pawlowski added mp4 tag editing to the new mp4 library!

--- a/common/mp4ff/Makefile.am
+++ b/common/mp4ff/Makefile.am
@@ -2,7 +2,8 @@
 
 include_HEADERS = mp4ff.h
 
-libmp4ff_la_SOURCES = mp4ff.c mp4atom.c mp4meta.c mp4sample.c mp4util.c mp4ff.h mp4ffint.h
+libmp4ff_la_SOURCES = mp4ff.c mp4atom.c mp4meta.c mp4sample.c mp4util.c \
+  mp4tagupdate.c mp4ff.h mp4ffint.h mp4ff_int_types.h
 
 AM_CFLAGS = -O2 -g -DUSE_TAGGING=1
 LIBTOOL_DEPS =
--- a/common/mp4ff/mp4atom.c
+++ b/common/mp4ff/mp4atom.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: mp4atom.c,v 1.6 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4atom.c,v 1.7 2003/12/11 18:32:39 menno Exp $
 **/
 
 #include <stdlib.h>
@@ -213,7 +213,7 @@
 static int32_t mp4ff_read_esds(mp4ff_t *f)
 {
     uint8_t tag;
-
+	
     mp4ff_read_char(f); /* version */
     mp4ff_read_int24(f); /* flags */
 
@@ -246,11 +246,11 @@
     }
 
     /* skip 13 bytes */
+	mp4ff_read_char(f);
     mp4ff_read_int32(f);
-    mp4ff_read_int32(f);
-    mp4ff_read_int32(f);
-    mp4ff_read_char(f);
-
+    f->track[f->total_tracks - 1]->maxBitrate = mp4ff_read_int32(f);
+    f->track[f->total_tracks - 1]->avgBitrate = mp4ff_read_int32(f);
+    
     /* get and verify DecSpecificInfoTag */
     if (mp4ff_read_char(f) != 0x05)
     {
@@ -440,6 +440,75 @@
     return 0;
 }
 
+#if 0
+static int32_t mp4ff_read_tkhd(mp4ff_t *f)
+{
+	uint8_t version;
+	uint32_t flags;
+    version = mp4ff_read_char(f); /* version */
+    flags = mp4ff_read_int24(f); /* flags */
+	if (version==1)
+	{
+		mp4ff_read_int64(f);//creation-time
+		mp4ff_read_int64(f);//modification-time
+		mp4ff_read_int32(f);//track-id
+		mp4ff_read_int32(f);//reserved
+		f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration
+	}
+	else //version == 0
+	{
+		mp4ff_read_int32(f);//creation-time
+		mp4ff_read_int32(f);//modification-time
+		mp4ff_read_int32(f);//track-id
+		mp4ff_read_int32(f);//reserved
+		f->track[f->total_tracks - 1]->duration = mp4ff_read_int32(f);//duration
+		if (f->track[f->total_tracks - 1]->duration == 0xFFFFFFFF)
+			f->track[f->total_tracks - 1]->duration = 0xFFFFFFFFFFFFFFFF;
+
+	}
+	mp4ff_read_int32(f);//reserved
+	mp4ff_read_int32(f);//reserved
+	mp4ff_read_int16(f);//layer
+	mp4ff_read_int16(f);//pre-defined
+	mp4ff_read_int16(f);//volume
+	mp4ff_read_int16(f);//reserved
+	
+	//matrix
+	mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f);
+	mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f);
+	mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f);
+	mp4ff_read_int32(f);//width
+	mp4ff_read_int32(f);//height
+	return 1;
+}
+#endif
+
+static int32_t mp4ff_read_mdhd(mp4ff_t *f)
+{
+	uint32_t version;
+
+	version = mp4ff_read_int32(f);
+	if (version==1)
+	{
+		mp4ff_read_int64(f);//creation-time
+		mp4ff_read_int64(f);//modification-time
+		f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale
+		f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration
+	}
+	else //version == 0
+	{
+		uint32_t temp;
+
+		mp4ff_read_int32(f);//creation-time
+		mp4ff_read_int32(f);//modification-time
+		f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale
+		temp = mp4ff_read_int32(f);
+		f->track[f->total_tracks - 1]->duration = (temp == (uint32_t)(-1)) ? (uint64_t)(-1) : (uint64_t)(temp);
+	}
+	mp4ff_read_int16(f);
+	mp4ff_read_int16(f);
+	return 1;
+}
 #ifdef USE_TAGGING
 static int32_t mp4ff_read_meta(mp4ff_t *f, const uint64_t size)
 {
@@ -455,7 +524,7 @@
         subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
         if (atom_type == ATOM_ILST)
         {
-            mp4ff_parse_metadata(f, subsize-(header_size+4));
+            mp4ff_parse_metadata(f, (uint32_t)(subsize-(header_size+4)));
         } else {
             mp4ff_set_position(f, mp4ff_position(f)+subsize-header_size);
         }
@@ -468,6 +537,7 @@
 
 int32_t mp4ff_atom_read(mp4ff_t *f, const int32_t size, const uint8_t atom_type)
 {
+	uint64_t dest_position = mp4ff_position(f)+size-8;
     if (atom_type == ATOM_STSZ)
     {
         /* sample size box */
@@ -487,6 +557,9 @@
     } else if (atom_type == ATOM_MVHD) {
         /* movie header box */
         mp4ff_read_mvhd(f);
+    } else if (atom_type == ATOM_MDHD) {
+        /* track header */
+        mp4ff_read_mdhd(f);
 #ifdef USE_TAGGING
     } else if (atom_type == ATOM_META) {
         /* iTunes Metadata box */
@@ -494,7 +567,7 @@
 #endif
     } else {
         /* skip this atom: not needed for reading */
-        mp4ff_set_position(f, mp4ff_position(f)+size-8);
+        mp4ff_set_position(f, dest_position);
     }
 
     return 0;
--- a/common/mp4ff/mp4ff.c
+++ b/common/mp4ff/mp4ff.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: mp4ff.c,v 1.6 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4ff.c,v 1.7 2003/12/11 18:32:39 menno Exp $
 **/
 
 #include <stdlib.h>
@@ -42,44 +42,6 @@
     return ff;
 }
 
-#ifdef USE_TAGGING
-mp4ff_t *mp4ff_open_edit(mp4ff_callback_t *f)
-{
-    mp4ff_t *ff = malloc(sizeof(mp4ff_t));
-
-    memset(ff, 0, sizeof(mp4ff_t));
-
-    ff->stream = f;
-
-    parse_atoms(ff);
-
-    /* copy moov atom to end of the file */
-    if (ff->last_atom != ATOM_MOOV)
-    {
-        char *free_data = "free";
-        char *moov_data;
-
-        moov_data = (unsigned char*)malloc(ff->moov_size);
-
-        /* read the moov atom */
-        mp4ff_set_position(ff, ff->moov_offset);
-        mp4ff_read_data(ff, moov_data, ff->moov_size);
-
-        /* rename old moov to free */
-        mp4ff_set_position(ff, ff->moov_offset + 4);
-        mp4ff_write_data(ff, free_data, 4);
-
-        /* write old moov at end of file */
-        mp4ff_set_position(ff, ff->file_size);
-        mp4ff_write_data(ff, moov_data, ff->moov_size);
-
-        free(moov_data);
-    }
-
-    return ff;
-}
-#endif
-
 void mp4ff_close(mp4ff_t *ff)
 {
     int32_t i;
@@ -154,7 +116,7 @@
         {
             parse_sub_atoms(f, size-header_size);
         } else {
-            mp4ff_atom_read(f, size, atom_type);
+            mp4ff_atom_read(f, (uint32_t)size, atom_type);
         }
     }
 
@@ -162,7 +124,7 @@
 }
 
 /* parse root atoms */
-static int32_t parse_atoms(mp4ff_t *f)
+int32_t parse_atoms(mp4ff_t *f)
 {
     uint64_t size;
     uint8_t atom_type = 0;
@@ -205,23 +167,66 @@
 
 int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample)
 {
-    int32_t i, ci = 0, co = 0;
+    int32_t i, co = 0;
 
     for (i = 0; i < f->track[track]->stts_entry_count; i++)
     {
-        int32_t j;
-        for (j = 0; j < f->track[track]->stts_sample_count[i]; j++)
-        {
-            if (co == sample)
-                return f->track[track]->stts_sample_delta[ci];
-            co++;
-        }
-        ci++;
+		int32_t delta = f->track[track]->stts_sample_count[i];
+		if (sample < co + delta)
+			return f->track[track]->stts_sample_delta[i];
+		co += delta;
     }
+    return (int32_t)(-1);
+}
 
-    return 0;
+int64_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample)
+{
+    int32_t i, co = 0;
+	int64_t acc = 0;
+
+    for (i = 0; i < f->track[track]->stts_entry_count; i++)
+    {
+		int32_t delta = f->track[track]->stts_sample_count[i];
+		if (sample < co + delta)
+		{
+			acc += f->track[track]->stts_sample_delta[i] * (sample - co);
+			return acc;
+		}
+		else
+		{
+			acc += f->track[track]->stts_sample_delta[i] * delta;
+		}
+		co += delta;
+    }
+    return (int64_t)(-1);
 }
 
+int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip)
+{
+	int32_t i, co = 0;
+	int64_t offset_total = 0;
+
+	for (i = 0; i < f->track[track]->stts_entry_count; i++)
+	{
+		int32_t sample_count = f->track[track]->stts_sample_count[i];
+		int32_t sample_delta = f->track[track]->stts_sample_delta[i];
+		int64_t offset_delta = (int64_t)sample_delta * (int64_t)sample_count;
+		if (offset < offset_total + offset_delta)
+		{
+			int64_t offset_fromstts = offset - offset_total;
+			if (toskip) *toskip = (int32_t)(offset_fromstts % sample_delta);
+			return (int32_t)(offset_fromstts / sample_delta);
+		}
+		else
+		{
+			offset_total += offset_delta;
+		}
+		co += sample_count;
+	}
+	return (int32_t)(-1);
+}
+
+
 int32_t mp4ff_read_sample(mp4ff_t *f, const int32_t track, const int32_t sample,
                           uint8_t **audio_buffer,  uint32_t *bytes)
 {
@@ -276,9 +281,25 @@
 
 int32_t mp4ff_time_scale(const mp4ff_t *f, const int32_t track)
 {
-    return f->track[track]->sampleRate;
+    return f->track[track]->timeScale;
 }
 
+uint32_t mp4ff_get_avg_bitrate(const mp4ff_t *f, const int32_t track)
+{
+	return f->track[track]->avgBitrate;
+}
+
+uint32_t mp4ff_get_max_bitrate(const mp4ff_t *f, const int32_t track)
+{
+	return f->track[track]->maxBitrate;
+}
+
+uint64_t mp4ff_get_track_duration(const mp4ff_t *f, const int32_t track)
+{
+	return f->track[track]->duration;
+}
+
+
 int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track)
 {
     int32_t i;
@@ -290,3 +311,5 @@
     }
     return total;
 }
+
+
--- a/common/mp4ff/mp4ff.dsp
+++ b/common/mp4ff/mp4ff.dsp
@@ -25,7 +25,7 @@
 # PROP AllowPerConfigDependencies 0
 # PROP Scc_ProjName ""
 # PROP Scc_LocalPath ""
-CPP=xicl6.exe
+CPP=cl.exe
 RSC=rc.exe
 
 !IF  "$(CFG)" == "mp4ff - Win32 Release"
@@ -105,6 +105,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\mp4tagupdate.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\mp4util.c
 # End Source File
 # End Group
@@ -111,6 +115,14 @@
 # Begin Group "Header Files"
 
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\mp4ff.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\mp4ff_int_types.h
+# End Source File
 # Begin Source File
 
 SOURCE=.\mp4ffint.h
--- a/common/mp4ff/mp4ff.h
+++ b/common/mp4ff/mp4ff.h
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: mp4ff.h,v 1.9 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4ff.h,v 1.10 2003/12/11 18:32:39 menno Exp $
 **/
 
 #ifndef MP4FF_H
@@ -32,35 +32,42 @@
 extern "C" {
 #endif /* __cplusplus */
 
+#include "mp4ff_int_types.h"
+
 /* file callback structure */
 typedef struct
 {
-    int (*read)(void *user_data, void *buffer, int length);
-    int (*write)(void *udata, void *buffer, int length);
-    int (*seek)(void *user_data, int position);
+    uint32_t (*read)(void *user_data, void *buffer, uint32_t length);
+    uint32_t (*write)(void *udata, void *buffer, uint32_t length);
+    uint32_t (*seek)(void *user_data, uint64_t position);
+	uint32_t (*truncate)(void *user_data);
     void *user_data;
 } mp4ff_callback_t;
 
 /* mp4 main file structure */
-typedef void *mp4ff_t;
+typedef void* mp4ff_t;
 
 
 /* API */
 
 mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f);
-#ifdef USE_TAGGING
-mp4ff_t *mp4ff_open_edit(mp4ff_callback_t *f);
-#endif
 void mp4ff_close(mp4ff_t *f);
-int mp4ff_get_sample_duration(const mp4ff_t *f, const int track, const int sample);
-int mp4ff_read_sample(mp4ff_t *f, const int track, const int sample,
+int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample);
+int64_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample);
+int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip);
+int32_t mp4ff_read_sample(mp4ff_t *f, const int track, const int sample,
                           unsigned char **audio_buffer,  unsigned int *bytes);
-int mp4ff_get_decoder_config(const mp4ff_t *f, const int track,
+int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int track,
                              unsigned char** ppBuf, unsigned int* pBufSize);
-int mp4ff_total_tracks(const mp4ff_t *f);
-int mp4ff_time_scale(const mp4ff_t *f, const int track);
-int mp4ff_num_samples(const mp4ff_t *f, const int track);
+int32_t mp4ff_total_tracks(const mp4ff_t *f);
+int32_t mp4ff_num_samples(const mp4ff_t *f, const int track);
+int32_t mp4ff_time_scale(const mp4ff_t *f, const int track);
 
+uint32_t mp4ff_get_avg_bitrate(const mp4ff_t *f, const int32_t track);
+uint32_t mp4ff_get_max_bitrate(const mp4ff_t *f, const int32_t track);
+uint64_t mp4ff_get_track_duration(const mp4ff_t *f, const int32_t track); //returns (uint64_t)(-1) if unknown
+
+
 /* metadata */
 int mp4ff_meta_get_num_items(const mp4ff_t *f);
 int mp4ff_meta_get_by_index(const mp4ff_t *f, unsigned int index,
@@ -77,6 +84,27 @@
 int mp4ff_meta_get_disc(const mp4ff_t *f, char **value);
 int mp4ff_meta_get_compilation(const mp4ff_t *f, char **value);
 int mp4ff_meta_get_tempo(const mp4ff_t *f, char **value);
+
+#ifdef USE_TAGGING
+
+/* metadata tag structure */
+typedef struct
+{
+    char *item;
+    char *value;
+} mp4ff_tag_t;
+
+/* metadata list structure */
+typedef struct
+{
+    mp4ff_tag_t *tags;
+    uint32_t count;
+} mp4ff_metadata_t;
+
+int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data);
+
+#endif
+
 
 #ifdef __cplusplus
 }
--- /dev/null
+++ b/common/mp4ff/mp4ff_int_types.h
@@ -1,0 +1,20 @@
+#ifndef _MP4FF_INT_TYPES_H_
+#define _MP4FF_INT_TYPES_H_
+
+typedef char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef long int32_t;
+typedef unsigned long uint32_t;
+
+#ifdef _WIN32
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+#endif
+
+
+#endif
\ No newline at end of file
--- a/common/mp4ff/mp4ffint.h
+++ b/common/mp4ff/mp4ffint.h
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: mp4ffint.h,v 1.3 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4ffint.h,v 1.4 2003/12/11 18:32:39 menno Exp $
 **/
 
 #ifndef MP4FF_INTERNAL_H
@@ -32,7 +32,9 @@
 extern "C" {
 #endif /* __cplusplus */
 
+#include "mp4ff_int_types.h"
 
+
 #define MAX_TRACKS 1024
 #define TRACK_UNKNOWN 0
 #define TRACK_AUDIO   1
@@ -93,45 +95,21 @@
 #define ATOM_GENRE2 20
 #define ATOM_TEMPO 21
 
-
-#ifdef _WIN32
-typedef __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#else
-
-#define stricmp strcasecmp
-
 #ifdef HAVE_CONFIG_H
 #include "../../config.h"
 #endif
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#else
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#define u_int8_t uint8_t
-#define u_int16_t uint16_t
-#define u_int32_t uint32_t
-#define u_int64_t uint64_t
-#else
-typedef unsigned long long uint64_t;
-typedef unsigned long uint32_t;
-typedef unsigned short uint16_t;
-typedef unsigned char uint8_t;
-typedef long long int64_t;
-typedef long int32_t;
-typedef short int16_t;
-typedef char int8_t;
-#endif
-#endif
-#endif
 
+/* file callback structure */
+typedef struct
+{
+    uint32_t (*read)(void *user_data, void *buffer, uint32_t length);
+    uint32_t (*write)(void *udata, void *buffer, uint32_t length);
+    uint32_t (*seek)(void *user_data, uint64_t position);
+	uint32_t (*truncate)(void *user_data);
+    void *user_data;
+} mp4ff_callback_t;
+
+
 /* metadata tag structure */
 typedef struct
 {
@@ -147,17 +125,8 @@
 } mp4ff_metadata_t;
 
 
-/* file callback structure */
 typedef struct
 {
-    int32_t (*read)(void *udata, void *buffer, int32_t length);
-    int32_t (*write)(void *udata, void *buffer, int32_t length);
-    int32_t (*seek)(void *udata, int32_t position);
-    void *user_data;
-} mp4ff_callback_t;
-
-typedef struct
-{
     int32_t type;
     int32_t channelCount;
     int32_t sampleSize;
@@ -190,6 +159,12 @@
     uint8_t *decoderConfig;
     int32_t decoderConfigLen;
 
+	uint32_t maxBitrate;
+	uint32_t avgBitrate;
+	
+	uint32_t timeScale;
+	uint64_t duration;
+
 } mp4ff_track_t;
 
 /* mp4 main file structure */
@@ -197,7 +172,7 @@
 {
     /* stream to read from */
 	mp4ff_callback_t *stream;
-    int32_t current_position;
+    int64_t current_position;
 
     int32_t moov_read;
     uint64_t moov_offset;
@@ -223,16 +198,19 @@
 
 
 /* mp4util.c */
-int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, const int32_t size);
-int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, const int32_t size);
+int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, uint32_t size);
+int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, uint32_t size);
 uint64_t mp4ff_read_int64(mp4ff_t *f);
 uint32_t mp4ff_read_int32(mp4ff_t *f);
 uint32_t mp4ff_read_int24(mp4ff_t *f);
 uint16_t mp4ff_read_int16(mp4ff_t *f);
 uint8_t mp4ff_read_char(mp4ff_t *f);
+int32_t mp4ff_write_int32(mp4ff_t *f,const uint32_t data);
 uint32_t mp4ff_read_mp4_descr_length(mp4ff_t *f);
-int32_t mp4ff_position(const mp4ff_t *f);
-int32_t mp4ff_set_position(mp4ff_t *f, const int32_t position);
+int64_t mp4ff_position(const mp4ff_t *f);
+int32_t mp4ff_set_position(mp4ff_t *f, const int64_t position);
+int32_t mp4ff_truncate(mp4ff_t * f);
+char * mp4ff_read_string(mp4ff_t * f,uint32_t length);
 
 /* mp4atom.c */
 static int32_t mp4ff_atom_get_size(const int8_t *data);
@@ -266,11 +244,6 @@
 /* mp4meta.c */
 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t *tags, const char *item, const char *value);
 static int32_t mp4ff_tag_set_field(mp4ff_metadata_t *tags, const char *item, const char *value);
-static int32_t GenreToString(char** GenreStr, const uint16_t genre);
-static int32_t StringToGenre(const char* GenreStr);
-static int32_t TrackToString(char** str, const uint16_t track, const uint16_t totalTracks);
-static int32_t StringToTrack(const char *str, uint16_t *track, uint16_t *totalTracks);
-static int32_t TempoToString(char** str, const uint16_t tempo);
 static int32_t mp4ff_set_metadata_name(mp4ff_t *f, const uint8_t atom_type, char **name);
 static int32_t mp4ff_parse_tag(mp4ff_t *f, const uint8_t parent_atom_type, const int32_t size);
 static int32_t mp4ff_meta_find_by_name(const mp4ff_t *f, const char *item, char **value);
@@ -299,10 +272,14 @@
 mp4ff_t *mp4ff_open_edit(mp4ff_callback_t *f);
 #endif
 void mp4ff_close(mp4ff_t *ff);
-static void mp4ff_track_add(mp4ff_t *f);
-static int32_t parse_sub_atoms(mp4ff_t *f, const uint64_t total_size);
-static int32_t parse_atoms(mp4ff_t *f);
+void mp4ff_track_add(mp4ff_t *f);
+int32_t parse_sub_atoms(mp4ff_t *f, const uint64_t total_size);
+int32_t parse_atoms(mp4ff_t *f);
+
 int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample);
+int64_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample);
+int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip);
+
 int32_t mp4ff_read_sample(mp4ff_t *f, const int32_t track, const int32_t sample,
                           uint8_t **audio_buffer,  uint32_t *bytes);
 int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int32_t track,
@@ -311,6 +288,8 @@
 int32_t mp4ff_time_scale(const mp4ff_t *f, const int32_t track);
 int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track);
 
+uint32_t mp4ff_meta_genre_to_index(const char * genrestr);//returns 1-based index, 0 if not found
+const char * mp4ff_meta_index_to_genre(uint32_t idx);//returns pointer to static string
 
 #ifdef __cplusplus
 }
--- a/common/mp4ff/mp4meta.c
+++ b/common/mp4ff/mp4meta.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: mp4meta.c,v 1.3 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4meta.c,v 1.4 2003/12/11 18:32:39 menno Exp $
 **/
 
 #ifdef USE_TAGGING
@@ -44,12 +44,9 @@
         if (backup) free(backup);
         return 0;
     } else {
-        int i_len = strlen(item);
-        int v_len = strlen(value);
+        tags->tags[tags->count].item = strdup(item);
+        tags->tags[tags->count].value = strdup(value);
 
-        tags->tags[tags->count].item = (char *)malloc(i_len+1);
-        tags->tags[tags->count].value = (char *)malloc(v_len+1);
-
         if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
         {
             if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
@@ -59,11 +56,6 @@
             return 0;
         }
 
-        memcpy(tags->tags[tags->count].item, item, i_len);
-        memcpy(tags->tags[tags->count].value, value, v_len);
-        tags->tags[tags->count].item[i_len] = '\0';
-        tags->tags[tags->count].value[v_len] = '\0';
-
         tags->count++;
         return 1;
     }
@@ -146,55 +138,37 @@
     "SynthPop",
 };
 
-static int32_t GenreToString(char** GenreStr, const uint16_t genre)
+uint32_t mp4ff_meta_genre_to_index(const char * genrestr)
 {
-    if (genre > 0 && genre <= sizeof(ID3v1GenreList)/sizeof(*ID3v1GenreList))
-    {
-        *GenreStr = (char*)malloc((strlen(ID3v1GenreList[genre-1])+1)*sizeof(char));
-        memset(*GenreStr, 0, (strlen(ID3v1GenreList[genre-1])+1)*sizeof(char));
-        strcpy(*GenreStr, ID3v1GenreList[genre-1]);
-        return 0;
-    }
-
-    *GenreStr = NULL;
-    return 1;
+	unsigned n;
+	for(n=0;n<sizeof(ID3v1GenreList)/sizeof(ID3v1GenreList[0]);n++)
+	{
+		if (!stricmp(genrestr,ID3v1GenreList[n])) return n+1;
+	}
+	return 0;
 }
 
-static int32_t StringToGenre(const char* GenreStr)
+const char * mp4ff_meta_index_to_genre(uint32_t idx)
 {
-    int32_t i;
-
-    for (i = 0; i < sizeof(ID3v1GenreList)/sizeof(*ID3v1GenreList); i++)
-    {
-        if (stricmp(GenreStr, ID3v1GenreList[i]) == 0)
-            return i+1;
-    }
-    return 0;
+	if (idx>0 && idx<=sizeof(ID3v1GenreList)/sizeof(ID3v1GenreList[0]))
+	{
+		return ID3v1GenreList[idx-1];
+	}
+	else
+	{
+		return 0;
+	}
 }
 
+
 static int32_t TrackToString(char** str, const uint16_t track, const uint16_t totalTracks)
 {
-    *str = malloc(12);
-    sprintf(*str, "%.5u of %.5u", track, totalTracks);
-
+	char temp[32];
+    sprintf(temp, "%.5u of %.5u", track, totalTracks);
+	*str = strdup(temp);
     return 0;
 }
 
-static int32_t StringToTrack(const char *str, uint16_t *track, uint16_t *totalTracks)
-{
-    sscanf(str, "%.5u of %.5u", &track, &totalTracks);
-
-    return 0;
-}
-
-static int32_t TempoToString(char** str, const uint16_t tempo)
-{
-    *str = malloc(12);
-    sprintf(*str, "%.5u BPM", tempo);
-
-    return 0;
-}
-
 static int32_t mp4ff_set_metadata_name(mp4ff_t *f, const uint8_t atom_type, char **name)
 {
     static char *tag_names[] = {
@@ -203,7 +177,6 @@
         "disc", "compilation", "genre", "tempo"
     };
     uint8_t tag_idx = 0;
-    uint16_t size;
 
     switch (atom_type)
     {
@@ -223,10 +196,7 @@
     default: tag_idx = 0; break;
     }
 
-    size = strlen(tag_names[tag_idx])+1;
-    *name = malloc(size+1);
-    memset(*name, 0, size+1);
-    memcpy(*name, tag_names[tag_idx], size);
+	*name = strdup(tag_names[tag_idx]);
 
     return 0;
 }
@@ -236,77 +206,97 @@
     uint8_t atom_type;
     uint8_t header_size = 0;
     uint64_t subsize, sumsize = 0;
-    char *name = NULL;
-    char *data = NULL;
+    char * name = NULL;
+	char * data = NULL;
+	uint32_t done = 0;
 
+
     while (sumsize < size)
     {
+		uint64_t destpos;
         subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
-        if (atom_type == ATOM_DATA)
-        {
-            mp4ff_read_char(f); /* version */
-            mp4ff_read_int24(f); /* flags */
-            mp4ff_read_int32(f); /* reserved */
-            data = malloc(subsize-(header_size+8)+1);
-            mp4ff_read_data(f, data, subsize-(header_size+8));
-            data[subsize-(header_size+8)] = '\0';
+		destpos = mp4ff_position(f)+subsize-header_size;
+		if (!done)
+		{
+			if (atom_type == ATOM_DATA)
+			{
+				mp4ff_read_char(f); /* version */
+				mp4ff_read_int24(f); /* flags */
+				mp4ff_read_int32(f); /* reserved */
 
-            /* some need special attention */
-            if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO)
-            {
-                uint16_t val = 0;
-                char *tmp;
-                tmp = data;
+				/* some need special attention */
+				if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO)
+				{
+					if (subsize - header_size >= 8 + 2)
+					{
+						uint16_t val = mp4ff_read_int16(f);
 
-                val = (uint16_t)(tmp[1]);
-                val += (uint16_t)(tmp[0]<<8);
+						if (parent_atom_type == ATOM_TEMPO)
+						{
+							char temp[16];
+							sprintf(temp, "%.5u BPM", val);
+							mp4ff_tag_add_field(&(f->tags), "tempo", temp);
+						}
+						else
+						{
+							const char * temp = mp4ff_meta_index_to_genre(val);
+							if (temp)
+							{
+								mp4ff_tag_add_field(&(f->tags), "genre", temp);
+							}
+						}
+						done = 1;
+					}
+				} else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
+					if (!done && subsize - header_size >= 8 + 8)
+					{
+						uint16_t index,total;
+						char temp[32];
+						mp4ff_read_int16(f);
+						index = mp4ff_read_int16(f);
+						total = mp4ff_read_int16(f);
+						mp4ff_read_int16(f);
 
-                if (data)
-                {
-                    free(data);
-                    data = NULL;
-                }
-                if (parent_atom_type == ATOM_TEMPO)
-                    TempoToString(&data, val);
-                else
-                    GenreToString(&data, val);
-            } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
-                uint16_t val1 = 0, val2 = 0;
-                char *tmp;
-                tmp = data;
-
-                val1 = (uint16_t)(tmp[3]);
-                val1 += (uint16_t)(tmp[2]<<8);
-                val2 = (uint16_t)(tmp[5]);
-                val2 += (uint16_t)(tmp[4]<<8);
-
-                if (data)
-                {
-                    free(data);
-                    data = NULL;
-                }
-                TrackToString(&data, val1, val2);
-            }
-        } else if (atom_type == ATOM_NAME) {
-            mp4ff_read_char(f); /* version */
-            mp4ff_read_int24(f); /* flags */
-            name = malloc(subsize-(header_size+4)+1);
-            mp4ff_read_data(f, name, subsize-(header_size+4));
-            name[subsize-12] = '\0';
-        } else {
-            mp4ff_set_position(f, mp4ff_position(f)+subsize-header_size);
-        }
-        sumsize += subsize;
+						itoa(index,temp,10);
+						mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "track" : "disc", temp);
+						if (total>0)
+						{
+							itoa(total,temp,10);
+							mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "totaltracks" : "totaldiscs", temp);
+						}
+						done = 1;
+					}
+				} else
+				{
+					if (data) {free(data);data = NULL;}
+					data = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+8)));
+				}
+			} else if (atom_type == ATOM_NAME) {
+				if (!done)
+				{
+					mp4ff_read_char(f); /* version */
+					mp4ff_read_int24(f); /* flags */
+					if (name) free(name);
+					name = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+4)));
+				}
+			}
+			mp4ff_set_position(f, destpos);
+			sumsize += subsize;
+		}
     }
 
-    if (name == NULL)
-    {
-        mp4ff_set_metadata_name(f, parent_atom_type, &name);
-    }
+	if (data)
+	{
+		if (!done)
+		{
+			if (name == NULL) mp4ff_set_metadata_name(f, parent_atom_type, &name);
+			if (name) mp4ff_tag_add_field(&(f->tags), name, data);
+		}
 
-    mp4ff_tag_set_field(&(f->tags), (const char*)name, (const char*)data);
-
-    return 0;
+		free(data);
+	}
+	if (name) free(name);
+    return 1;
 }
 
 int32_t mp4ff_parse_metadata(mp4ff_t *f, const int32_t size)
@@ -318,7 +308,7 @@
     while (sumsize < size)
     {
         subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
-        mp4ff_parse_tag(f, atom_type, subsize-header_size);
+        mp4ff_parse_tag(f, atom_type, (uint32_t)(subsize-header_size));
         sumsize += subsize;
     }
 
@@ -335,13 +325,8 @@
     {
         if (!stricmp(f->tags.tags[i].item, item))
         {
-            int v_len = strlen(f->tags.tags[i].value);
-
-            *value = (char*)malloc(v_len + 1);
-            memcpy(*value, f->tags.tags[i].value, v_len);
-            (*value)[v_len] = '\0';
-
-            return 0;
+			*value = strdup(f->tags.tags[i].value);
+            return 1;
         }
     }
 
@@ -348,7 +333,7 @@
     *value = NULL;
 
     /* not found */
-    return 1;
+    return 0;
 }
 
 int32_t mp4ff_meta_get_num_items(const mp4ff_t *f)
@@ -363,20 +348,12 @@
     {
         *item = NULL;
         *value = NULL;
-        return 1;
+        return 0;
     } else {
-        int i_len = strlen(f->tags.tags[index].item);
-        int v_len = strlen(f->tags.tags[index].value);
-
-        *item = (char*)malloc(i_len + 1);
-        memcpy(*item, f->tags.tags[index].item, i_len);
-        (*item)[i_len] = '\0';
-        *value = (char*)malloc(v_len + 1);
-        memcpy(*value, f->tags.tags[index].value, v_len);
-        (*value)[v_len] = '\0';
+		*item = strdup(f->tags.tags[index].item);
+		*value = strdup(f->tags.tags[index].value);
+		return 1;
     }
-
-    return 0;
 }
 
 int32_t mp4ff_meta_get_title(const mp4ff_t *f, char **value)
--- a/common/mp4ff/mp4sample.c
+++ b/common/mp4ff/mp4sample.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: mp4sample.c,v 1.4 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4sample.c,v 1.10 2003/12/23 18:53:24 menno Exp $
 **/
 
 #include <stdlib.h>
@@ -77,11 +77,13 @@
 
 static int32_t mp4ff_chunk_to_offset(const mp4ff_t *f, const int32_t track, const int32_t chunk)
 {
-    if (f->track[track]->stco_entry_count && (chunk > f->track[track]->stco_entry_count))
+	const mp4ff_track_t * p_track = f->track[track];
+
+    if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count))
     {
-        return f->track[track]->stco_chunk_offset[f->track[track]->stco_entry_count - 1];
-    } else if (f->track[track]->stco_entry_count) {
-        return f->track[track]->stco_chunk_offset[chunk - 1];
+        return p_track->stco_chunk_offset[p_track->stco_entry_count - 1];
+    } else if (p_track->stco_entry_count) {
+        return p_track->stco_chunk_offset[chunk - 1];
     } else {
         return 8;
     }
@@ -93,14 +95,15 @@
                                        const int32_t chunk_sample, const int32_t sample)
 {
     int32_t i, total;
+	const mp4ff_track_t * p_track = f->track[track];
 
-    if (f->track[track]->stsz_sample_size)
+    if (p_track->stsz_sample_size)
     {
-        return sample * f->track[track]->channelCount * f->track[track]->sampleSize/8;
+        return sample * p_track->channelCount * p_track->sampleSize/8;
     } else {
         for(i = chunk_sample, total = 0; i < sample; i++)
         {
-            total += f->track[track]->stsz_table[i];
+            total += p_track->stsz_table[i];
         }
     }
 
@@ -122,12 +125,13 @@
 int32_t mp4ff_audio_frame_size(const mp4ff_t *f, const int32_t track, const int32_t sample)
 {
     int32_t bytes;
+	const mp4ff_track_t * p_track = f->track[track];
 
-    if (f->track[track]->stsz_sample_size)
+    if (p_track->stsz_sample_size)
     {
-        bytes = f->track[track]->stsz_sample_size;
+        bytes = p_track->stsz_sample_size;
     } else {
-        bytes = f->track[track]->stsz_table[sample];
+        bytes = p_track->stsz_table[sample];
     }
 
     return bytes;
--- /dev/null
+++ b/common/mp4ff/mp4tagupdate.c
@@ -1,0 +1,644 @@
+#include <stdlib.h>
+#include <string.h>
+#include "mp4ffint.h"
+
+#ifdef USE_TAGGING
+
+static uint32_t fix_byte_order_32(uint32_t src)
+{
+    uint32_t result;
+    uint32_t a, b, c, d;
+    int8_t data[4];
+    
+    memcpy(data,&src,sizeof(src));
+    a = (uint8_t)data[0];
+    b = (uint8_t)data[1];
+    c = (uint8_t)data[2];
+    d = (uint8_t)data[3];
+
+    result = (a<<24) | (b<<16) | (c<<8) | d;
+    return (uint32_t)result;
+}
+
+static uint16_t fix_byte_order_16(uint16_t src)
+{
+    uint16_t result;
+    uint16_t a, b;
+    int8_t data[2];
+    
+    memcpy(data,&src,sizeof(src));
+    a = (uint8_t)data[0];
+    b = (uint8_t)data[1];
+
+    result = (a<<8) | b;
+    return (uint16_t)result;
+}
+
+
+typedef struct
+{
+	void * data;
+	unsigned written;
+	unsigned allocated;
+	unsigned error;
+} membuffer;
+
+unsigned membuffer_write(membuffer * buf,const void * ptr,unsigned bytes)
+{
+	unsigned dest_size = buf->written + bytes;
+
+	if (buf->error) return 0;
+	if (dest_size > buf->allocated)
+	{
+		do
+		{
+			buf->allocated <<= 1;
+		} while(dest_size > buf->allocated);
+		
+		{
+			void * newptr = realloc(buf->data,buf->allocated);
+			if (newptr==0)
+			{
+				free(buf->data);
+				buf->data = 0;
+				buf->error = 1;
+				return 0;
+			}
+			buf->data = newptr;
+		}
+	}
+
+	if (ptr) memcpy((char*)buf->data + buf->written,ptr,bytes);
+	buf->written += bytes;
+	return bytes;
+}
+
+#define membuffer_write_data membuffer_write
+
+unsigned membuffer_write_int32(membuffer * buf,uint32_t data)
+{
+	uint8_t temp[4] = {(uint8_t)(data>>24),(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data};	
+	return membuffer_write_data(buf,temp,4);
+}
+
+unsigned membuffer_write_int24(membuffer * buf,uint32_t data)
+{
+	uint8_t temp[3] = {(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data};
+	return membuffer_write_data(buf,temp,3);
+}
+
+unsigned membuffer_write_int16(membuffer * buf,uint16_t data)
+{
+	uint8_t temp[2] = {(uint8_t)(data>>8),(uint8_t)data};
+	return membuffer_write_data(buf,temp,2);
+}
+
+unsigned membuffer_write_atom_name(membuffer * buf,const char * data)
+{
+	return membuffer_write_data(buf,data,4)==4 ? 1 : 0;
+}
+
+void membuffer_write_atom(membuffer * buf,const char * name,unsigned size,const void * data)
+{
+	membuffer_write_int32(buf,size + 8);
+	membuffer_write_atom_name(buf,name);
+	membuffer_write_data(buf,data,size);
+}
+
+unsigned membuffer_write_string(membuffer * buf,const char * data)
+{
+	return membuffer_write_data(buf,data,strlen(data));
+}
+
+unsigned membuffer_write_int8(membuffer * buf,uint8_t data)
+{
+	return membuffer_write_data(buf,&data,1);
+}
+
+void * membuffer_get_ptr(const membuffer * buf)
+{
+	return buf->data;
+}
+
+unsigned membuffer_get_size(const membuffer * buf)
+{
+	return buf->written;
+}
+
+unsigned membuffer_error(const membuffer * buf)
+{
+	return buf->error;
+}
+
+void membuffer_set_error(membuffer * buf) {buf->error = 1;}
+
+unsigned membuffer_transfer_from_file(membuffer * buf,mp4ff_t * src,unsigned bytes)
+{
+	unsigned oldsize;
+	void * bufptr;
+	
+	oldsize = membuffer_get_size(buf);
+	if (membuffer_write_data(buf,0,bytes) != bytes) return 0;
+
+	bufptr = membuffer_get_ptr(buf);
+	if (bufptr==0) return 0;
+	
+	if ((unsigned)mp4ff_read_data(src,(char*)bufptr + oldsize,bytes)!=bytes)
+	{
+		membuffer_set_error(buf);
+		return 0;
+	}
+	
+	return bytes;
+}
+
+
+membuffer * membuffer_create()
+{
+	const unsigned initial_size = 256;
+
+	membuffer * buf = (membuffer *) malloc(sizeof(membuffer));
+	buf->data = malloc(initial_size);
+	buf->written = 0;
+	buf->allocated = initial_size;
+	buf->error = buf->data == 0 ? 1 : 0;
+
+	return buf;
+}
+
+void membuffer_free(membuffer * buf)
+{
+	if (buf->data) free(buf->data);
+	free(buf);
+}
+
+void * membuffer_detach(membuffer * buf)
+{
+	void * ret;
+
+	if (buf->error) return 0;
+
+	ret = realloc(buf->data,buf->written);
+	
+	if (ret == 0) free(buf->data);
+
+	buf->data = 0;
+	buf->error = 1;
+	
+	return ret;
+}
+
+#if 0
+/* metadata tag structure */
+typedef struct
+{
+    char *item;
+    char *value;
+} mp4ff_tag_t;
+
+/* metadata list structure */
+typedef struct
+{
+    mp4ff_tag_t *tags;
+    uint32_t count;
+} mp4ff_metadata_t;
+#endif
+
+typedef struct
+{
+	const char * atom;
+	const char * name;	
+} stdmeta_entry;
+
+static stdmeta_entry stdmetas[] = 
+{
+	{"�nam","title"},
+	{"�ART","artist"},
+	{"�wrt","writer"},
+	{"�alb","album"},
+	{"�day","date"},
+	{"�too","tool"},
+	{"�cmt","comment"},
+//	{"�gen","genre"},
+	{"cpil","compilation"},
+//	{"trkn","track"},
+//	{"disk","disc"},
+//	{"gnre","genre"},
+};
+
+
+static const char* find_standard_meta(const char * name) //returns atom name if found, 0 if not
+{
+	unsigned n;
+	for(n=0;n<sizeof(stdmetas)/sizeof(stdmetas[0]);n++)
+	{
+		if (!stricmp(name,stdmetas[n].name)) return stdmetas[n].atom;
+	}
+    return 0;
+}
+
+static void membuffer_write_track_tag(membuffer * buf,const char * name,uint32_t index,uint32_t total)
+{
+	membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
+	membuffer_write_atom_name(buf,name);
+	membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
+	membuffer_write_atom_name(buf,"data");
+	membuffer_write_int32(buf,0);//flags
+	membuffer_write_int32(buf,0);//reserved
+	membuffer_write_int16(buf,0);
+	membuffer_write_int16(buf,(uint16_t)index);//track number
+	membuffer_write_int16(buf,(uint16_t)total);//total tracks
+	membuffer_write_int16(buf,0);
+}
+
+static void membuffer_write_int16_tag(membuffer * buf,const char * name,uint16_t value)
+{
+	membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
+	membuffer_write_atom_name(buf,name);
+	membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
+	membuffer_write_atom_name(buf,"data");
+	membuffer_write_int32(buf,0);//flags
+	membuffer_write_int32(buf,0);//reserved
+	membuffer_write_int16(buf,value);//value
+}
+
+static void membuffer_write_std_tag(membuffer * buf,const char * name,const char * value)
+{
+	membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value) );
+	membuffer_write_atom_name(buf,name);
+	membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
+	membuffer_write_atom_name(buf,"data");
+	membuffer_write_int32(buf,1);//flags
+	membuffer_write_int32(buf,0);//reserved
+	membuffer_write_data(buf,value,strlen(value));
+}
+
+static void membuffer_write_custom_tag(membuffer * buf,const char * name,const char * value)
+{
+	membuffer_write_int32(buf,8 /*atom header*/ + 0x1C /*weirdo itunes atom*/ + 12 /*name atom header*/ + strlen(name) + 16 /*data atom header + flags*/ + strlen(value) );
+	membuffer_write_atom_name(buf,"----");
+	membuffer_write_int32(buf,0x1C);//weirdo itunes atom
+	membuffer_write_atom_name(buf,"mean");
+	membuffer_write_int32(buf,0);
+	membuffer_write_data(buf,"com.apple.iTunes",16);
+	membuffer_write_int32(buf,12 + strlen(name));
+	membuffer_write_atom_name(buf,"name");
+	membuffer_write_int32(buf,0);
+	membuffer_write_data(buf,name,strlen(name));
+	membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
+	membuffer_write_atom_name(buf,"data");
+	membuffer_write_int32(buf,1);//flags
+	membuffer_write_int32(buf,0);//reserved
+	membuffer_write_data(buf,value,strlen(value));
+
+}
+
+static uint32_t myatoi(const char * param)
+{
+	return param ? atoi(param) : 0;
+}
+
+static uint32_t create_ilst(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
+{
+	membuffer * buf = membuffer_create();
+	unsigned metaptr;
+	char * mask = (char*)malloc(data->count);
+	memset(mask,0,data->count);
+
+	{
+		const char * tracknumber_ptr = 0, * totaltracks_ptr = 0;
+		const char * discnumber_ptr = 0, * totaldiscs_ptr = 0;
+		const char * genre_ptr = 0, * tempo_ptr = 0;
+		for(metaptr = 0; metaptr < data->count; metaptr++)
+		{
+			mp4ff_tag_t * tag = &data->tags[metaptr];
+			if (!stricmp(tag->item,"tracknumber") || !stricmp(tag->item,"track"))
+			{
+				if (tracknumber_ptr==0) tracknumber_ptr = tag->value;
+				mask[metaptr] = 1;
+			}
+			else if (!stricmp(tag->item,"totaltracks"))
+			{
+				if (totaltracks_ptr==0) totaltracks_ptr = tag->value;
+				mask[metaptr] = 1;
+			}
+			else if (!stricmp(tag->item,"discnumber") || !stricmp(tag->item,"disc"))
+			{
+				if (discnumber_ptr==0) discnumber_ptr = tag->value;
+				mask[metaptr] = 1;
+			}
+			else if (!stricmp(tag->item,"totaldiscs"))
+			{
+				if (totaldiscs_ptr==0) totaldiscs_ptr = tag->value;
+				mask[metaptr] = 1;
+			}
+			else if (!stricmp(tag->item,"genre"))
+			{
+				if (genre_ptr==0) genre_ptr = tag->value;
+				mask[metaptr] = 1;
+			}
+			else if (!stricmp(tag->item,"tempo"))
+			{
+				if (tempo_ptr==0) tempo_ptr = tag->value;
+				mask[metaptr] = 1;
+			}
+
+		}
+
+		if (tracknumber_ptr) membuffer_write_track_tag(buf,"trkn",myatoi(tracknumber_ptr),myatoi(totaltracks_ptr));
+		if (discnumber_ptr) membuffer_write_track_tag(buf,"disk",myatoi(discnumber_ptr),myatoi(totaldiscs_ptr));
+		if (tempo_ptr) membuffer_write_int16_tag(buf,"tmpo",(uint16_t)myatoi(tempo_ptr));
+
+		if (genre_ptr)
+		{
+			uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
+			if (index==0)
+				membuffer_write_std_tag(buf,"gnre",genre_ptr);
+			else
+				membuffer_write_int16_tag(buf,"�gen",(uint16_t)index);
+		}
+	}
+	
+	for(metaptr = 0; metaptr < data->count; metaptr++)
+	{
+		if (!mask[metaptr])
+		{
+			mp4ff_tag_t * tag = &data->tags[metaptr];
+			const char * std_meta_atom = find_standard_meta(tag->item);
+			if (std_meta_atom)
+			{
+				membuffer_write_std_tag(buf,std_meta_atom,tag->value);
+			}
+			else
+			{
+				membuffer_write_custom_tag(buf,tag->item,tag->value);
+			}
+		}
+	}
+
+	free(mask);
+
+	if (membuffer_error(buf))
+	{
+		membuffer_free(buf);
+		return 0;
+	}
+
+	*out_size = membuffer_get_size(buf);
+	*out_buffer = membuffer_detach(buf);
+	membuffer_free(buf);
+
+	return 1;
+}
+
+static uint32_t find_atom(mp4ff_t * f,uint64_t base,uint32_t size,const char * name)
+{
+	uint32_t remaining = size;
+	uint64_t atom_offset = base;
+	for(;;)
+	{
+		char atom_name[4];
+		uint32_t atom_size;
+
+		mp4ff_set_position(f,atom_offset);
+		
+		if (remaining < 8) break;
+		atom_size = mp4ff_read_int32(f);
+		if (atom_size > remaining || atom_size < 8) break;
+		mp4ff_read_data(f,atom_name,4);
+		
+		if (!memcmp(atom_name,name,4))
+		{
+			mp4ff_set_position(f,atom_offset);
+			return 1;
+		}
+		
+		remaining -= atom_size;
+		atom_offset += atom_size;
+	}
+	return 0;
+}
+
+static uint32_t find_atom_v2(mp4ff_t * f,uint64_t base,uint32_t size,const char * name,uint32_t extraheaders,const char * name_inside)
+{
+	uint64_t first_base = (uint64_t)(-1);
+	while(find_atom(f,base,size,name))//try to find atom <name> with atom <name_inside> in it
+	{
+		uint64_t mybase = mp4ff_position(f);
+		uint32_t mysize = mp4ff_read_int32(f);
+
+		if (first_base == (uint64_t)(-1)) first_base = mybase;
+
+		if (mysize < 8 + extraheaders) break;
+
+		if (find_atom(f,mybase+(8+extraheaders),mysize-(8+extraheaders),name_inside))
+		{
+			mp4ff_set_position(f,mybase);
+			return 2;
+		}
+		base += mysize;
+		if (size<=mysize) {size=0;break;}
+		size -= mysize;
+	}
+
+	if (first_base != (uint64_t)(-1))//wanted atom inside not found
+	{
+		mp4ff_set_position(f,first_base);
+		return 1;
+	}
+	else return 0;	
+}
+
+static uint32_t create_meta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
+{
+	membuffer * buf;
+	uint32_t ilst_size;
+	void * ilst_buffer;
+
+	if (!create_ilst(data,&ilst_buffer,&ilst_size)) return 0;
+
+	buf = membuffer_create();
+
+	membuffer_write_int32(buf,0);
+	membuffer_write_atom(buf,"ilst",ilst_size,ilst_buffer);
+	free(ilst_buffer);
+
+	*out_size = membuffer_get_size(buf);
+	*out_buffer = membuffer_detach(buf);
+	membuffer_free(buf);
+	return 1;
+}
+
+static uint32_t create_udta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
+{
+	membuffer * buf;
+	uint32_t meta_size;
+	void * meta_buffer;
+
+	if (!create_meta(data,&meta_buffer,&meta_size)) return 0;
+
+	buf = membuffer_create();
+
+	membuffer_write_atom(buf,"meta",meta_size,meta_buffer);
+
+	free(meta_buffer);
+
+	*out_size = membuffer_get_size(buf);
+	*out_buffer = membuffer_detach(buf);
+	membuffer_free(buf);
+	return 1;
+}
+
+static uint32_t modify_moov(mp4ff_t * f,const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
+{
+	uint64_t total_base = f->moov_offset + 8;
+	uint32_t total_size = (uint32_t)(f->moov_size - 8);
+
+	uint64_t udta_offset,meta_offset,ilst_offset;
+	uint32_t udta_size,  meta_size,  ilst_size;
+	
+	uint32_t new_ilst_size;
+	void * new_ilst_buffer;
+	
+	uint8_t * p_out;
+	int32_t size_delta;
+	
+	
+	if (!find_atom_v2(f,total_base,total_size,"udta",0,"meta"))
+	{
+		membuffer * buf;
+		void * new_udta_buffer;
+		uint32_t new_udta_size;
+		if (!create_udta(data,&new_udta_buffer,&new_udta_size)) return 0;
+		
+		buf = membuffer_create();
+		mp4ff_set_position(f,total_base);
+		membuffer_transfer_from_file(buf,f,total_size);
+		
+		membuffer_write_atom(buf,"udta",new_udta_size,new_udta_buffer);
+
+		free(new_udta_buffer);
+	
+		*out_size = membuffer_get_size(buf);
+		*out_buffer = membuffer_detach(buf);
+		membuffer_free(buf);
+		return 1;		
+	}
+	else
+	{
+		udta_offset = mp4ff_position(f);
+		udta_size = mp4ff_read_int32(f);
+		if (find_atom_v2(f,udta_offset+8,udta_size-8,"meta",4,"ilst")<2)
+		{
+			membuffer * buf;
+			void * new_meta_buffer;
+			uint32_t new_meta_size;
+			if (!create_meta(data,&new_meta_buffer,&new_meta_size)) return 0;
+			
+			buf = membuffer_create();
+			mp4ff_set_position(f,total_base);
+			membuffer_transfer_from_file(buf,f,(uint32_t)(udta_offset - total_base));
+			
+			membuffer_write_int32(buf,udta_size + 8 + new_meta_size);
+			membuffer_write_atom_name(buf,"udta");
+			membuffer_transfer_from_file(buf,f,udta_size);
+						
+			membuffer_write_atom(buf,"meta",new_meta_size,new_meta_buffer);
+			free(new_meta_buffer);
+		
+			*out_size = membuffer_get_size(buf);
+			*out_buffer = membuffer_detach(buf);
+			membuffer_free(buf);
+			return 1;		
+		}
+		meta_offset = mp4ff_position(f);
+		meta_size = mp4ff_read_int32(f);
+		if (!find_atom(f,meta_offset+12,meta_size-12,"ilst")) return 0;//shouldn't happen, find_atom_v2 above takes care of it
+		ilst_offset = mp4ff_position(f);
+		ilst_size = mp4ff_read_int32(f);
+
+		if (!create_ilst(data,&new_ilst_buffer,&new_ilst_size)) return 0;
+		
+		size_delta = new_ilst_size - (ilst_size - 8);
+
+		*out_size = total_size + size_delta;
+		*out_buffer = malloc(*out_size);
+		if (*out_buffer == 0)
+		{
+			free(new_ilst_buffer);
+			return 0;
+		}
+
+		p_out = (uint8_t*)*out_buffer;
+		
+		mp4ff_set_position(f,total_base);
+		mp4ff_read_data(f,p_out,(uint32_t)(udta_offset - total_base )); p_out += (uint32_t)(udta_offset - total_base );
+		*(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
+		mp4ff_read_data(f,p_out,4); p_out += 4;
+		mp4ff_read_data(f,p_out,(uint32_t)(meta_offset - udta_offset - 8)); p_out += (uint32_t)(meta_offset - udta_offset - 8);
+		*(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
+		mp4ff_read_data(f,p_out,4); p_out += 4;
+		mp4ff_read_data(f,p_out,(uint32_t)(ilst_offset - meta_offset - 8)); p_out += (uint32_t)(ilst_offset - meta_offset - 8);
+		*(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
+		mp4ff_read_data(f,p_out,4); p_out += 4;
+
+		memcpy(p_out,new_ilst_buffer,new_ilst_size);
+		p_out += new_ilst_size;
+
+		mp4ff_set_position(f,ilst_offset + ilst_size);
+		mp4ff_read_data(f,p_out,(uint32_t)(total_size - (ilst_offset - total_base) - ilst_size));
+
+		free(new_ilst_buffer);
+	}
+	return 1;
+
+}
+
+int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data)
+{
+	void * new_moov_data;
+	uint32_t new_moov_size;
+
+    mp4ff_t *ff = malloc(sizeof(mp4ff_t));
+
+    memset(ff, 0, sizeof(mp4ff_t));
+    ff->stream = f;
+	mp4ff_set_position(ff,0);
+
+    parse_atoms(ff);
+
+
+	if (!modify_moov(ff,data,&new_moov_data,&new_moov_size))
+	{
+		mp4ff_close(ff);
+		return 0;
+	}
+
+    /* copy moov atom to end of the file */
+    if (ff->last_atom != ATOM_MOOV)
+    {
+        char *free_data = "free";
+
+        /* rename old moov to free */
+        mp4ff_set_position(ff, ff->moov_offset + 4);
+        mp4ff_write_data(ff, free_data, 4);
+	
+        mp4ff_set_position(ff, ff->file_size);
+		mp4ff_write_int32(ff,new_moov_size + 8);
+		mp4ff_write_data(ff,"moov",4);
+		mp4ff_write_data(ff, new_moov_data, new_moov_size);
+    }
+	else
+	{
+        mp4ff_set_position(ff, ff->moov_offset);
+		mp4ff_write_int32(ff,new_moov_size + 8);
+		mp4ff_write_data(ff,"moov",4);
+		mp4ff_write_data(ff, new_moov_data, new_moov_size);
+	}
+
+	mp4ff_truncate(ff);
+
+	mp4ff_close(ff);
+    return 1;
+}
+#endif
--- a/common/mp4ff/mp4util.c
+++ b/common/mp4ff/mp4util.c
@@ -22,12 +22,13 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through [email protected].
 **
-** $Id: mp4util.c,v 1.5 2003/12/04 21:29:52 menno Exp $
+** $Id: mp4util.c,v 1.11 2003/12/23 18:53:24 menno Exp $
 **/
 
 #include "mp4ffint.h"
+#include <stdlib.h>
 
-int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, const int32_t size)
+int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, uint32_t size)
 {
     int32_t result = 1;
 
@@ -38,8 +39,13 @@
     return result;
 }
 
-int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, const int32_t size)
+int32_t mp4ff_truncate(mp4ff_t * f)
 {
+	return f->stream->truncate(f->stream->user_data);
+}
+
+int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, uint32_t size)
+{
     int32_t result = 1;
 
     result = f->stream->write(f->stream->user_data, data, size);
@@ -49,8 +55,25 @@
     return result;
 }
 
-int32_t mp4ff_set_position(mp4ff_t *f, const int32_t position)
+int32_t mp4ff_write_int32(mp4ff_t *f,const uint32_t data)
 {
+	uint32_t result;
+    uint32_t a, b, c, d;
+    int8_t temp[4];
+    
+    *(uint32_t*)temp = data;
+    a = (uint8_t)temp[0];
+    b = (uint8_t)temp[1];
+    c = (uint8_t)temp[2];
+    d = (uint8_t)temp[3];
+
+    result = (a<<24) | (b<<16) | (c<<8) | d;
+
+    return mp4ff_write_data(f,(uint8_t*)&result,sizeof(result));
+}
+
+int32_t mp4ff_set_position(mp4ff_t *f, const int64_t position)
+{
     f->stream->seek(f->stream->user_data, position);
     f->current_position = position;
 
@@ -57,7 +80,7 @@
     return 0;
 }
 
-int32_t mp4ff_position(const mp4ff_t *f)
+int64_t mp4ff_position(const mp4ff_t *f)
 {
     return f->current_position;
 }
@@ -64,7 +87,7 @@
 
 uint64_t mp4ff_read_int64(mp4ff_t *f)
 {
-    int8_t data[8];
+    uint8_t data[8];
     uint64_t result = 0;
     int8_t i;
 
@@ -121,6 +144,24 @@
 
     result = (a<<8) | b;
     return (uint16_t)result;
+}
+
+char * mp4ff_read_string(mp4ff_t * f,uint32_t length)
+{
+	char * str = (char*)malloc(length + 1);
+	if (str!=0)
+	{
+		if ((uint32_t)mp4ff_read_data(f,str,length)!=length)
+		{
+			free(str);
+			str = 0;
+		}
+		else
+		{
+			str[length] = 0;
+		}
+	}
+	return str;	
 }
 
 uint8_t mp4ff_read_char(mp4ff_t *f)