shithub: aacdec

Download patch

ref: e41eb73bd0685c8ce47e08fcce64f639398b071a
parent: ed5b482f2272e9f447fe7b9d188f0d5e4221899c
author: menno <menno>
date: Sat Nov 22 10:30:19 EST 2003

added tag reading to mp4ff

--- a/common/mp4ff/Makefile.am
+++ b/common/mp4ff/Makefile.am
@@ -2,7 +2,7 @@
 
 include_HEADERS = mp4ff.h
 
-libmp4ff_la_SOURCES = mp4ff.c mp4atom.c mp4sample.c mp4util.c mp4ff.h
+libmp4ff_la_SOURCES = mp4ff.c mp4atom.c mp4meta.c mp4sample.c mp4util.c mp4ff.h mp4ffint.h
 
 AM_CFLAGS = -O2 -g
 LIBTOOL_DEPS =
--- a/common/mp4ff/mp4atom.c
+++ b/common/mp4ff/mp4atom.c
@@ -22,15 +22,15 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
 **
-** $Id: mp4atom.c,v 1.3 2003/11/21 19:02:02 menno Exp $
+** $Id: mp4atom.c,v 1.4 2003/11/22 15:30:19 menno Exp $
 **/
 
 #include <stdlib.h>
-#include "mp4ff.h"
+#include "mp4ffint.h"
 
 
 /* parse atom header size */
-int32_t mp4ff_atom_get_size(int8_t *data)
+static int32_t mp4ff_atom_get_size(const int8_t *data)
 {
     uint32_t result;
     uint32_t a, b, c, d;
@@ -47,8 +47,8 @@
 }
 
 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
-int32_t mp4ff_atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
-                           int8_t a2, int8_t b2, int8_t c2, int8_t d2)
+static int32_t mp4ff_atom_compare(const int8_t a1, const int8_t b1, const int8_t c1, const int8_t d1,
+                                  const int8_t a2, const int8_t b2, const int8_t c2, const int8_t d2)
 {
     if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
         return 1;
@@ -56,7 +56,8 @@
         return 0;
 }
 
-uint8_t mp4ff_atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d)
+static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b,
+                                       const int8_t c, const int8_t d)
 {
     if (a == 'm')
     {
@@ -78,6 +79,8 @@
             return ATOM_MP4V;
         else if (mp4ff_atom_compare(a,b,c,d, 'm','p','4','s'))
             return ATOM_MP4S;
+        else if (mp4ff_atom_compare(a,b,c,d, 'm','e','t','a'))
+            return ATOM_META;
     } else if (a == 't') {
         if (mp4ff_atom_compare(a,b,c,d, 't','r','a','k'))
             return ATOM_TRAK;
@@ -85,6 +88,10 @@
             return ATOM_TKHD;
         else if (mp4ff_atom_compare(a,b,c,d, 't','r','e','f'))
             return ATOM_TREF;
+        else if (mp4ff_atom_compare(a,b,c,d, 't','r','k','n'))
+            return ATOM_TRACK;
+        else if (mp4ff_atom_compare(a,b,c,d, 't','m','p','o'))
+            return ATOM_TEMPO;
     } else if (a == 's') {
         if (mp4ff_atom_compare(a,b,c,d, 's','t','b','l'))
             return ATOM_STBL;
@@ -104,6 +111,23 @@
             return ATOM_STZ2;
         else if (mp4ff_atom_compare(a,b,c,d, 's','k','i','p'))
             return ATOM_SKIP;
+    } else if (a == '�') {
+        if (mp4ff_atom_compare(a,b,c,d, '�','n','a','m'))
+            return ATOM_TITLE;
+        else if (mp4ff_atom_compare(a,b,c,d, '�','A','R','T'))
+            return ATOM_ARTIST;
+        else if (mp4ff_atom_compare(a,b,c,d, '�','w','r','t'))
+            return ATOM_WRITER;
+        else if (mp4ff_atom_compare(a,b,c,d, '�','a','l','b'))
+            return ATOM_ALBUM;
+        else if (mp4ff_atom_compare(a,b,c,d, '�','d','a','y'))
+            return ATOM_DATE;
+        else if (mp4ff_atom_compare(a,b,c,d, '�','t','o','o'))
+            return ATOM_TOOL;
+        else if (mp4ff_atom_compare(a,b,c,d, '�','c','m','t'))
+            return ATOM_COMMENT;
+        else if (mp4ff_atom_compare(a,b,c,d, '�','g','e','n'))
+            return ATOM_GENRE1;
     }
 
     if (mp4ff_atom_compare(a,b,c,d, 'e','d','t','s'))
@@ -118,6 +142,20 @@
         return ATOM_HMHD;
     else if (mp4ff_atom_compare(a,b,c,d, 'v','m','h','d'))
         return ATOM_VMHD;
+    else if (mp4ff_atom_compare(a,b,c,d, 'u','d','t','a'))
+        return ATOM_UDTA;
+    else if (mp4ff_atom_compare(a,b,c,d, 'i','l','s','t'))
+        return ATOM_ILST;
+    else if (mp4ff_atom_compare(a,b,c,d, 'n','a','m','e'))
+        return ATOM_NAME;
+    else if (mp4ff_atom_compare(a,b,c,d, 'd','a','t','a'))
+        return ATOM_DATA;
+    else if (mp4ff_atom_compare(a,b,c,d, 'd','i','s','k'))
+        return ATOM_DISC;
+    else if (mp4ff_atom_compare(a,b,c,d, 'g','n','r','e'))
+        return ATOM_GENRE2;
+    else if (mp4ff_atom_compare(a,b,c,d, 'c','p','i','l'))
+        return ATOM_COMPILATION;
     else
         return ATOM_UNKNOWN;
 }
@@ -135,7 +173,7 @@
 
     size = mp4ff_atom_get_size(atom_header);
 
-    //fprintf(stdout, "%c%c%c%c\n", atom_header[4], atom_header[5], atom_header[6], atom_header[7]);
+    //printf("%c%c%c%c\n", atom_header[4], atom_header[5], atom_header[6], atom_header[7]);
 
     *atom_type = mp4ff_atom_name_to_type(atom_header[4], atom_header[5], atom_header[6], atom_header[7]);
 
@@ -142,11 +180,10 @@
     return size;
 }
 
-
-int32_t mp4ff_read_stsz(mp4ff_t *f)
+static int32_t mp4ff_read_stsz(mp4ff_t *f)
 {
-    /* version */ mp4ff_read_char(f);
-    /* flags */ mp4ff_read_int24(f);
+    mp4ff_read_char(f); /* version */
+    mp4ff_read_int24(f); /* flags */
     f->track[f->total_tracks - 1]->stsz_sample_size = mp4ff_read_int32(f);
     f->track[f->total_tracks - 1]->stsz_sample_count = mp4ff_read_int32(f);
 
@@ -165,7 +202,7 @@
     return 0;
 }
 
-int32_t mp4ff_read_esds(mp4ff_t *f)
+static int32_t mp4ff_read_esds(mp4ff_t *f)
 {
     uint8_t tag;
 
@@ -229,7 +266,7 @@
     return 0;
 }
 
-int32_t mp4ff_read_mp4a(mp4ff_t *f)
+static int32_t mp4ff_read_mp4a(mp4ff_t *f)
 {
     int32_t i, size;
     uint8_t atom_type = 0;
@@ -262,7 +299,7 @@
     return 0;
 }
 
-int32_t mp4ff_read_stsd(mp4ff_t *f)
+static int32_t mp4ff_read_stsd(mp4ff_t *f)
 {
     int32_t i;
 
@@ -297,7 +334,7 @@
     return 0;
 }
 
-int32_t mp4ff_read_stsc(mp4ff_t *f)
+static int32_t mp4ff_read_stsc(mp4ff_t *f)
 {
     int32_t i;
 
@@ -322,12 +359,12 @@
     return 0;
 }
 
-int32_t mp4ff_read_stco(mp4ff_t *f)
+static int32_t mp4ff_read_stco(mp4ff_t *f)
 {
     int32_t i;
 
-    /* version */ mp4ff_read_char(f);
-    /* flags */ mp4ff_read_int24(f);
+    mp4ff_read_char(f); /* version */
+    mp4ff_read_int24(f); /* flags */
     f->track[f->total_tracks - 1]->stco_entry_count = mp4ff_read_int32(f);
 
     f->track[f->total_tracks - 1]->stco_chunk_offset =
@@ -341,7 +378,7 @@
     return 0;
 }
 
-int32_t mp4ff_read_stts(mp4ff_t *f)
+static int32_t mp4ff_read_stts(mp4ff_t *f)
 {
     int32_t i;
 
@@ -361,12 +398,12 @@
     return 0;
 }
 
-int32_t mp4ff_read_mvhd(mp4ff_t *f)
+static int32_t mp4ff_read_mvhd(mp4ff_t *f)
 {
     int32_t i;
 
-    /* version */ mp4ff_read_char(f);
-    /* flags */ mp4ff_read_int24(f);
+    mp4ff_read_char(f); /* version */
+    mp4ff_read_int24(f); /* flags */
     /* creation_time */ mp4ff_read_int32(f);
     /* modification_time */ mp4ff_read_int32(f);
     f->time_scale = mp4ff_read_int32(f);
@@ -392,8 +429,31 @@
     return 0;
 }
 
-int32_t mp4ff_atom_read(mp4ff_t *f, int32_t size, uint8_t atom_type)
+static int32_t mp4ff_read_meta(mp4ff_t *f, const int32_t size)
 {
+    int32_t subsize, sumsize = 0;
+    uint8_t atom_type;
+
+    mp4ff_read_char(f); /* version */
+    mp4ff_read_int24(f); /* flags */
+
+    while (sumsize < (size-12))
+    {
+        subsize = mp4ff_atom_read_header(f, &atom_type);
+        if (atom_type == ATOM_ILST)
+        {
+            mp4ff_parse_metadata(f, subsize);
+        } else {
+            mp4ff_set_position(f, mp4ff_position(f)+subsize-8);
+        }
+        sumsize += subsize;
+    }
+
+    return 0;
+}
+
+int32_t mp4ff_atom_read(mp4ff_t *f, const int32_t size, const uint8_t atom_type)
+{
     if (atom_type == ATOM_STSZ)
     {
         /* sample size box */
@@ -413,6 +473,9 @@
     } else if (atom_type == ATOM_MVHD) {
         /* movie header box */
         mp4ff_read_mvhd(f);
+    } else if (atom_type == ATOM_META) {
+        /* iTunes Metadata box */
+        mp4ff_read_meta(f, size);
     } else {
         /* skip this atom: not needed for reading */
         mp4ff_set_position(f, mp4ff_position(f)+size-8);
--- a/common/mp4ff/mp4ff.c
+++ b/common/mp4ff/mp4ff.c
@@ -22,12 +22,12 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
 **
-** $Id: mp4ff.c,v 1.3 2003/11/21 19:02:02 menno Exp $
+** $Id: mp4ff.c,v 1.4 2003/11/22 15:30:19 menno Exp $
 **/
 
 #include <stdlib.h>
 #include <string.h>
-#include "mp4ff.h"
+#include "mp4ffint.h"
 
 mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f)
 {
@@ -70,12 +70,12 @@
         }
     }
 
+    mp4ff_tag_delete(&(ff->tags));
+
     if (ff) free(ff);
 }
 
-
-
-void mp4ff_track_add(mp4ff_t *f)
+static void mp4ff_track_add(mp4ff_t *f)
 {
     f->total_tracks++;
 
@@ -85,7 +85,7 @@
 }
 
 /* parse atoms that are sub atoms of other atoms */
-int32_t parse_sub_atoms(mp4ff_t *f, int32_t total_size)
+static int32_t parse_sub_atoms(mp4ff_t *f, const int32_t total_size)
 {
     int32_t size;
     uint8_t atom_type = 0;
@@ -121,7 +121,7 @@
 }
 
 /* parse root atoms */
-int32_t parse_atoms(mp4ff_t *f)
+static int32_t parse_atoms(mp4ff_t *f)
 {
     int32_t size;
     uint8_t atom_type = 0;
@@ -162,7 +162,7 @@
 }
 
 
-int32_t mp4ff_get_sample_duration(mp4ff_t *f, int32_t track, int32_t sample)
+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;
 
@@ -181,7 +181,8 @@
     return 0;
 }
 
-int32_t mp4ff_read_sample(mp4ff_t *f, int32_t track, int32_t sample, uint8_t **audio_buffer,  uint32_t *bytes)
+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 result = 0;
 
@@ -199,7 +200,8 @@
     return *bytes;
 }
 
-int32_t mp4ff_get_decoder_config(mp4ff_t *f, int32_t track, uint8_t** ppBuf, uint32_t* pBufSize)
+int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int32_t track,
+                                 uint8_t** ppBuf, uint32_t* pBufSize)
 {
     if (track >= f->total_tracks)
     {
@@ -226,17 +228,17 @@
     return 0;
 }
 
-int32_t mp4ff_total_tracks(mp4ff_t *f)
+int32_t mp4ff_total_tracks(const mp4ff_t *f)
 {
     return f->total_tracks;
 }
 
-int32_t mp4ff_time_scale(mp4ff_t *f, int32_t track)
+int32_t mp4ff_time_scale(const mp4ff_t *f, const int32_t track)
 {
     return f->track[track]->sampleRate;
 }
 
-int32_t mp4ff_num_samples(mp4ff_t *f, int32_t track)
+int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track)
 {
     int32_t i;
     int32_t total = 0;
--- a/common/mp4ff/mp4ff.dsp
+++ b/common/mp4ff/mp4ff.dsp
@@ -40,8 +40,8 @@
 # PROP Output_Dir "Release"
 # PROP Intermediate_Dir "Release"
 # PROP Target_Dir ""
-F90=df.exe
 MTL=midl.exe
+F90=df.exe
 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
 # ADD CPP /nologo /MD /W3 /GX /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
 # ADD BASE RSC /l 0x413 /d "NDEBUG"
@@ -65,8 +65,8 @@
 # PROP Output_Dir "Debug"
 # PROP Intermediate_Dir "Debug"
 # PROP Target_Dir ""
-F90=df.exe
 MTL=midl.exe
+F90=df.exe
 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
 # ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
 # ADD BASE RSC /l 0x413 /d "_DEBUG"
@@ -97,6 +97,10 @@
 # End Source File
 # Begin Source File
 
+SOURCE=.\mp4meta.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\mp4sample.c
 # End Source File
 # Begin Source File
@@ -109,7 +113,7 @@
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
 # Begin Source File
 
-SOURCE=.\mp4ff.h
+SOURCE=.\mp4ffint.h
 # End Source File
 # End Group
 # End Target
--- 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 Mpeg4AAClicense@nero.com.
 **
-** $Id: mp4ff.h,v 1.6 2003/11/21 19:02:02 menno Exp $
+** $Id: mp4ff.h,v 1.7 2003/11/22 15:30:19 menno Exp $
 **/
 
 #ifndef MP4FF_H
@@ -32,192 +32,50 @@
 extern "C" {
 #endif /* __cplusplus */
 
-
-#define MAX_TRACKS 1024
-#define TRACK_UNKNOWN 0
-#define TRACK_AUDIO   1
-#define TRACK_VIDEO   2
-#define TRACK_SYSTEM  3
-
-
-#define SUBATOMIC 128
-
-/* atoms without subatoms */
-#define ATOM_FTYP 129
-#define ATOM_MDAT 130
-#define ATOM_MVHD 131
-#define ATOM_TKHD 132
-#define ATOM_TREF 133
-#define ATOM_MDHD 134
-#define ATOM_VMHD 135
-#define ATOM_SMHD 136
-#define ATOM_HMHD 137
-#define ATOM_STSD 138
-#define ATOM_STTS 139
-#define ATOM_STSZ 140
-#define ATOM_STZ2 141
-#define ATOM_STCO 142
-#define ATOM_STSC 143
-#define ATOM_MP4A 144
-#define ATOM_MP4V 145
-#define ATOM_MP4S 146
-#define ATOM_ESDS 147
-
-#define ATOM_UNKNOWN 255
-#define ATOM_FREE ATOM_UNKNOWN
-#define ATOM_SKIP ATOM_UNKNOWN
-
-/* atoms with subatoms */
-#define ATOM_MOOV 1
-#define ATOM_TRAK 2
-#define ATOM_EDTS 3
-#define ATOM_MDIA 4
-#define ATOM_MINF 5
-#define ATOM_STBL 6
-
-#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
-#ifdef HAVE_INTTYPES_H
-#include <inttypes.h>
-#else
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#define u_int8_t uint8_t
-#define u_int16_t uint16_t
-#define u_int32_t uint32_t
-#define u_int64_t uint64_t
-#endif
-#endif
-
 /* file callback structure */
 typedef struct
 {
-    int32_t (*read)(void *udata, void *buffer, int32_t length);
-    int32_t (*seek)(void *udata, int32_t position);
+    int (*read)(void *user_data, void *buffer, int length);
+    int (*seek)(void *user_data, int position);
     void *user_data;
 } mp4ff_callback_t;
 
-typedef struct
-{
-    int32_t type;
-    int32_t channelCount;
-    int32_t sampleSize;
-    uint16_t sampleRate;
-
-    /* stsd */
-    int32_t stsd_entry_count;
-
-    /* stsz */
-	int32_t stsz_sample_size;
-	int32_t stsz_sample_count;
-    int32_t *stsz_table;
-
-    /* stts */
-	int32_t stts_entry_count;
-    int32_t *stts_sample_count;
-    int32_t *stts_sample_delta;
-
-    /* stsc */
-	int32_t stsc_entry_count;
-    int32_t *stsc_first_chunk;
-    int32_t *stsc_samples_per_chunk;
-    int32_t *stsc_sample_desc_index;
-
-    /* stsc */
-	int32_t stco_entry_count;
-    int32_t *stco_chunk_offset;
-
-    /* esde */
-    uint8_t *decoderConfig;
-    int32_t decoderConfigLen;
-
-} mp4ff_track_t;
-
 /* mp4 main file structure */
-typedef struct
-{
-    /* stream to read from */
-	mp4ff_callback_t *stream;
-    int32_t current_position;
+typedef void *mp4ff_t;
 
-    int32_t moov_read;
-    int32_t moov_offset;
-    int32_t moov_size;
-    int32_t mdat_read;
-    int32_t mdat_offset;
-    int32_t mdat_size;
 
-    /* mvhd */
-    int32_t time_scale;
-    int32_t duration;
+/* API */
 
-    /* incremental track index while reading the file */
-    int32_t total_tracks;
-
-    /* track data */
-    mp4ff_track_t *track[MAX_TRACKS];
-} mp4ff_t;
-
-
-
-
-/* mp4util.c */
-int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, int32_t size);
-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);
-uint32_t mp4ff_read_mp4_descr_length(mp4ff_t *f);
-int32_t mp4ff_position(mp4ff_t *f);
-int32_t mp4ff_set_position(mp4ff_t *f, int32_t position);
-
-/* mp4atom.c */
-int32_t mp4ff_atom_get_size(int8_t *data);
-int32_t mp4ff_atom_compare(int8_t a1, int8_t b1, int8_t c1, int8_t d1,
-                           int8_t a2, int8_t b2, int8_t c2, int8_t d2);
-uint8_t mp4ff_atom_name_to_type(int8_t a, int8_t b, int8_t c, int8_t d);
-int32_t mp4ff_atom_read_header(mp4ff_t *f, uint8_t *atom_type);
-int32_t mp4ff_read_stsz(mp4ff_t *f);
-int32_t mp4ff_read_esds(mp4ff_t *f);
-int32_t mp4ff_read_mp4a(mp4ff_t *f);
-int32_t mp4ff_read_stsd(mp4ff_t *f);
-int32_t mp4ff_read_stsc(mp4ff_t *f);
-int32_t mp4ff_read_stco(mp4ff_t *f);
-int32_t mp4ff_read_stts(mp4ff_t *f);
-int32_t mp4ff_atom_read(mp4ff_t *f, int32_t size, uint8_t atom_type);
-
-/* mp4sample.c */
-int32_t mp4ff_chunk_of_sample(mp4ff_t *f, int32_t track, int32_t sample,
-                              int32_t *chunk_sample, int32_t *chunk);
-int32_t mp4ff_chunk_to_offset(mp4ff_t *f, int32_t track, int32_t chunk);
-int32_t mp4ff_sample_range_size(mp4ff_t *f, int32_t track, int32_t chunk_sample, int32_t sample);
-int32_t mp4ff_sample_to_offset(mp4ff_t *f, int32_t track, int32_t sample);
-int32_t mp4ff_audio_frame_size(mp4ff_t *f, int32_t track, int32_t sample);
-int32_t mp4ff_set_sample_position(mp4ff_t *f, int32_t track, int32_t sample);
-
-
-/* mp4ff.c */
 mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f);
 void mp4ff_close(mp4ff_t *ff);
-void mp4ff_track_add(mp4ff_t *f);
-int32_t parse_sub_atoms(mp4ff_t *f, int32_t total_size);
-int32_t parse_atoms(mp4ff_t *f);
-int32_t mp4ff_get_sample_duration(mp4ff_t *f, int32_t track, int32_t sample);
-int32_t mp4ff_read_sample(mp4ff_t *f, int32_t track, int32_t sample, uint8_t **audio_buffer,  uint32_t *bytes);
-int32_t mp4ff_get_decoder_config(mp4ff_t *f, int32_t track, uint8_t** ppBuf, uint32_t* pBufSize);
-int32_t mp4ff_total_tracks(mp4ff_t *f);
-int32_t mp4ff_time_scale(mp4ff_t *f, int32_t track);
-int32_t mp4ff_num_samples(mp4ff_t *f, int32_t track);
+static void mp4ff_track_add(mp4ff_t *f);
+static int parse_sub_atoms(mp4ff_t *f, const int total_size);
+static int parse_atoms(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,
+                          unsigned char **audio_buffer,  unsigned int *bytes);
+int 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);
 
+/* metadata */
+int mp4ff_meta_get_num_items(const mp4ff_t *f);
+int mp4ff_meta_get_by_index(const mp4ff_t *f, unsigned int index,
+                            char **item, char **value);
+int mp4ff_meta_get_title(const mp4ff_t *f, char **value);
+int mp4ff_meta_get_artist(const mp4ff_t *f, char **value);
+int mp4ff_meta_get_writer(const mp4ff_t *f, char **value);
+int mp4ff_meta_get_album(const mp4ff_t *f, char **value);
+int mp4ff_meta_get_date(const mp4ff_t *f, char **value);
+int mp4ff_meta_get_tool(const mp4ff_t *f, char **value);
+int mp4ff_meta_get_comment(const mp4ff_t *f, char **value);
+int mp4ff_meta_get_genre(const mp4ff_t *f, char **value);
+int mp4ff_meta_get_track(const mp4ff_t *f, char **value);
+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 __cplusplus
 }
--- a/common/mp4ff/mp4sample.c
+++ b/common/mp4ff/mp4sample.c
@@ -22,15 +22,15 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
 **
-** $Id: mp4sample.c,v 1.1 2003/11/21 15:08:48 menno Exp $
+** $Id: mp4sample.c,v 1.3 2003/11/25 13:16:09 menno Exp $
 **/
 
 #include <stdlib.h>
-#include "mp4ff.h"
+#include "mp4ffint.h"
 
 
-int32_t mp4ff_chunk_of_sample(mp4ff_t *f, int32_t track, int32_t sample,
-                              int32_t *chunk_sample, int32_t *chunk)
+static int32_t mp4ff_chunk_of_sample(const mp4ff_t *f, const int32_t track, const int32_t sample,
+                                     int32_t *chunk_sample, int32_t *chunk)
 {
     int32_t total_entries = 0;
     int32_t chunk2entry;
@@ -75,7 +75,7 @@
     return 0;
 }
 
-int32_t mp4ff_chunk_to_offset(mp4ff_t *f, int32_t track, int32_t chunk)
+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))
     {
@@ -89,7 +89,8 @@
     return 0;
 }
 
-int32_t mp4ff_sample_range_size(mp4ff_t *f, int32_t track, int32_t chunk_sample, int32_t sample)
+static int32_t mp4ff_sample_range_size(const mp4ff_t *f, const int32_t track,
+                                       const int32_t chunk_sample, const int32_t sample)
 {
     int32_t i, total;
 
@@ -106,7 +107,7 @@
     return total;
 }
 
-int32_t mp4ff_sample_to_offset(mp4ff_t *f, int32_t track, int32_t sample)
+static int32_t mp4ff_sample_to_offset(const mp4ff_t *f, const int32_t track, const int32_t sample)
 {
     int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
 
@@ -118,7 +119,7 @@
 	return chunk_offset2;
 }
 
-int32_t mp4ff_audio_frame_size(mp4ff_t *f, int32_t track, int32_t sample)
+int32_t mp4ff_audio_frame_size(const mp4ff_t *f, const int32_t track, const int32_t sample)
 {
     int32_t bytes;
 
@@ -132,7 +133,7 @@
     return bytes;
 }
 
-int32_t mp4ff_set_sample_position(mp4ff_t *f, int32_t track, int32_t sample)
+int32_t mp4ff_set_sample_position(mp4ff_t *f, const int32_t track, const int32_t sample)
 {
     int32_t offset;
 
--- a/common/mp4ff/mp4util.c
+++ b/common/mp4ff/mp4util.c
@@ -22,12 +22,12 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
 **
-** $Id: mp4util.c,v 1.2 2003/11/21 19:02:03 menno Exp $
+** $Id: mp4util.c,v 1.3 2003/11/22 15:30:19 menno Exp $
 **/
 
-#include "mp4ff.h"
+#include "mp4ffint.h"
 
-int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, int32_t size)
+int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, const int32_t size)
 {
     int32_t result = 1;
 
@@ -38,7 +38,7 @@
     return result;
 }
 
-int32_t mp4ff_set_position(mp4ff_t *f, int32_t position)
+int32_t mp4ff_set_position(mp4ff_t *f, const int32_t position)
 {
     f->stream->seek(f->stream->user_data, position);
     f->current_position = position;
@@ -46,7 +46,7 @@
     return 0;
 }
 
-int32_t mp4ff_position(mp4ff_t *f)
+int32_t mp4ff_position(const mp4ff_t *f)
 {
     return f->current_position;
 }
--- a/frontend/main.c
+++ b/frontend/main.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
 **
-** $Id: main.c,v 1.64 2003/11/21 19:07:32 menno Exp $
+** $Id: main.c,v 1.65 2003/11/22 15:30:19 menno Exp $
 **/
 
 #ifdef _WIN32
@@ -793,8 +793,10 @@
     }
 
     /* print some mp4 file info */
-    fprintf(stderr, "%s file info:\n", mp4file);
+    fprintf(stderr, "%s file info:\n\n", mp4file);
     {
+        char *tag = NULL, *item = NULL;
+        int k, j;
         char *ot[6] = { "NULL", "MAIN AAC", "LC AAC", "SSR AAC", "LTP AAC", "HE AAC" };
         long samples = mp4ff_num_samples(infile, track);
         float f = 1024.0;
@@ -807,6 +809,21 @@
 
         fprintf(stderr, "%s\t%.3f secs, %d ch, %d Hz\n\n", ot[(mp4ASC.objectTypeIndex > 5)?0:mp4ASC.objectTypeIndex],
             seconds, mp4ASC.channelsConfiguration, mp4ASC.samplingFrequency);
+
+        j = mp4ff_meta_get_num_items(infile);
+        for (k = 0; k < j; k++)
+        {
+            if (!mp4ff_meta_get_by_index(infile, k, &item, &tag))
+            {
+                if (item != NULL && tag != NULL)
+                {
+                    fprintf(stderr, "%s: %s\n", item, tag);
+                    free(item); item = NULL;
+                    free(tag); tag = NULL;
+                }
+            }
+        }
+        if (j > 0) printf("\n");
     }
 
     if (infoOnly)