* all : preliminary mp4 (and some mov) demux plugin. I've not enabled
authorLaurent Aimar <fenrir@videolan.org>
Wed, 17 Jul 2002 21:37:27 +0000 (21:37 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Wed, 17 Jul 2002 21:37:27 +0000 (21:37 +0000)
it ( add by hand to Makefile ... and link it with zlib -lz ) as I will
probably break it too many times. It work for some mp4(but without
audio, need aac decoder) and mov with sorenson v1(ffmpeg :).

plugins/mp4/Makefile [new file with mode: 0644]
plugins/mp4/libmp4.c [new file with mode: 0644]
plugins/mp4/libmp4.h [new file with mode: 0644]
plugins/mp4/mp4.c [new file with mode: 0644]
plugins/mp4/mp4.h [new file with mode: 0644]

diff --git a/plugins/mp4/Makefile b/plugins/mp4/Makefile
new file mode 100644 (file)
index 0000000..8eae3cc
--- /dev/null
@@ -0,0 +1,4 @@
+mp4_SOURCES = mp4.c libmp4.c
+
+
+
diff --git a/plugins/mp4/libmp4.c b/plugins/mp4/libmp4.c
new file mode 100644 (file)
index 0000000..0944337
--- /dev/null
@@ -0,0 +1,2488 @@
+/*****************************************************************************
+ * libmp4.c : LibMP4 library for mp4 module for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: libmp4.c,v 1.1 2002/07/17 21:37:27 fenrir Exp $
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                              /* strdup() */
+#include <errno.h>
+#include <sys/types.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include <zlib.h>                                     /* for compressed moov */
+#include "libmp4.h"
+
+/*****************************************************************************
+ * Here are defined some macro to make life simpler but before using it 
+ *  *look* at the code. 
+ *
+ *  XXX: All macro are written in capital letters
+ *
+ *****************************************************************************/
+#define MP4_BOX_HEADERSIZE( p_box ) \
+  ( 8 + ( p_box->i_shortsize == 1 ? 8 : 0 ) \
+      + ( p_box->i_type == FOURCC_uuid ? 16 : 0 ) )
+    
+#define MP4_BOX_DESCEND( p_box ) \
+    MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) );
+
+#define MP4_GET1BYTE( dst ) \
+    dst = *p_peek; p_peek++; i_read--
+
+#define MP4_GET2BYTES( dst ) \
+    dst = GetWBE( p_peek ); p_peek += 2; i_read -= 2
+
+#define MP4_GET3BYTES( dst ) \
+    dst = GetDWBE( p_peek ) >> 8 ; p_peek += 3; i_read -= 3
+
+#define MP4_GET4BYTES( dst ) \
+    dst = GetDWBE( p_peek ); p_peek += 4; i_read -= 4
+
+#define MP4_GET8BYTES( dst ) \
+    dst = GetQWBE( p_peek ); p_peek += 8; i_read -= 8
+        
+#define MP4_GETVERSIONFLAGS( p_void ) \
+    MP4_GET1BYTE( p_void->i_version ); \
+    MP4_GET3BYTES( p_void->i_flags )
+    
+#define MP4_GETSTRING( p_str ) \
+    if( p_peek[0] ) \
+    { \
+        p_str = calloc( sizeof( char ), __MIN( strlen( p_peek ), i_read )+1);\
+        memcpy( p_str, p_peek, __MIN( strlen( p_peek ), i_read ) ); \
+        p_str[__MIN( strlen( p_peek ), i_read )] = 0; \
+        p_peek += strlen( p_str ) + 1; \
+        i_read -= strlen( p_str ) + 1; \
+    } \
+    else \
+    { \
+        p_str = NULL; \
+    }
+    
+
+#define MP4_READBOX_ENTER( MP4_Box_data_TYPE_t ) \
+    s64 i_read = p_box->i_size; \
+    u8 *p_peek, *p_buff; \
+    i_read = p_box->i_size; \
+    if( !( p_peek = p_buff = malloc( i_read ) ) ) \
+    { \
+        return( 0 ); \
+    } \
+    if( !MP4_ReadStream( p_stream, p_peek, i_read ) )\
+    { \
+        free( p_buff ); \
+        return( 0 ); \
+    } \
+    p_peek += MP4_BOX_HEADERSIZE( p_box ); \
+    i_read -= MP4_BOX_HEADERSIZE( p_box ); \
+    if( !( p_box->data.p_data = malloc( sizeof( MP4_Box_data_TYPE_t ) ) ) ) \
+    { \
+      free( p_buff ); \
+      return( 0 ); \
+    } 
+                
+
+#define MP4_READBOX_EXIT( i_code ) \
+    if( !i_code ) \
+    free( p_buff ); \
+    if( i_read < 0 ) \
+    { \
+        msg_Warn( p_stream->p_input, "Not enougth data" ); \
+    } \
+    return( i_code )
+
+    
+/* Some assumptions:
+        * The input method HAVE to be seekable 
+*/
+
+/* Some functions to manipulate memory */
+static inline u16 GetWLE( u8 *p_buff )
+{
+    return( (p_buff[0]) + ( p_buff[1] <<8 ) );
+}
+
+static inline u32 GetDWLE( u8 *p_buff )
+{
+    return( p_buff[0] + ( p_buff[1] <<8 ) +
+            ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
+}
+
+static inline u16 GetWBE( u8 *p_buff )
+{
+    return( (p_buff[0]<<8) + p_buff[1] );
+}
+
+static inline u32 GetDWBE( u8 *p_buff )
+{
+    return( (p_buff[0] << 24) + ( p_buff[1] <<16 ) +
+            ( p_buff[2] <<8 ) + p_buff[3] );
+}
+
+static inline u64 GetQWBE( u8 *p_buff )
+{
+    return( ( (u64)GetDWBE( p_buff ) << 32 )|( (u64)GetDWBE( p_buff + 4 ) ) );
+}
+
+
+static inline void GetUUID( UUID_t *p_uuid, u8 *p_buff )
+{
+    memcpy( p_uuid, 
+            p_buff,
+            16 );
+}
+
+static inline void CreateUUID( UUID_t *p_uuid, u32 i_fourcc )
+{
+    /* made by 0xXXXXXXXX-0011-0010-8000-00aa00389b71 
+            where XXXXXXXX is the fourcc */
+    /* FIXME implement this */
+}
+
+/* some functions for mp4 encoding of variables */
+
+void MP4_ConvertDate2Str( char *psz, u64 i_date )
+{
+    int i_day;
+    int i_hour;
+    int i_min;
+    int i_sec;
+
+    i_day = i_date / ( 60*60*24);
+    i_hour = ( i_date /( 60*60 ) ) % 60;
+    i_min  = ( i_date / 60 ) % 60;
+    i_sec =  i_date % 60;
+    /* FIXME do it correctly, date begin at 1 jan 1904 */ 
+    sprintf( psz, "%dd-%2.2dh:%2.2dm:%2.2ds",
+                   i_day, i_hour, i_min, i_sec );
+}
+
+
+
+/*****************************************************************************
+ * Some basic functions to manipulate stream more easily in vlc
+ *
+ * MP4_TellAbsolute get file position
+ * 
+ * MP4_SeekAbsolute seek in the file
+ *
+ * MP4_ReadData read data from the file in a buffer
+ *
+ *****************************************************************************/
+off_t MP4_TellAbsolute( input_thread_t *p_input )
+{
+    off_t i_pos;
+    
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    
+    i_pos= p_input->stream.p_selected_area->i_tell -
+            ( p_input->p_last_data - p_input->p_current_data  );
+
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    return( i_pos );
+}
+int MP4_SeekAbsolute( input_thread_t *p_input,
+                       off_t i_pos)
+{
+    off_t i_filepos;
+
+    if( i_pos >= p_input->stream.p_selected_area->i_size )
+    {
+        return( 0 );
+    }
+            
+    i_filepos = MP4_TellAbsolute( p_input );
+    if( i_pos != i_filepos )
+    {
+        p_input->pf_seek( p_input, i_pos );
+        input_AccessReinit( p_input );
+    }
+    return( 1 );
+}
+
+/* return 1 if success, 0 if fail */
+int MP4_ReadData( input_thread_t *p_input, u8 *p_buff, int i_size )
+{
+    data_packet_t *p_data;
+
+    int i_read;
+
+                
+    if( !i_size )
+    {
+        return( 1 );
+    }
+
+    do
+    {
+        i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 1024 ) );
+        if( i_read <= 0 )
+        {
+            return( 0 );
+        }
+        memcpy( p_buff, p_data->p_payload_start, i_read );
+        input_DeletePacket( p_input->p_method_data, p_data );
+        
+        p_buff += i_read;
+        i_size -= i_read;
+                
+    } while( i_size );
+    
+    return( 1 );
+}
+
+/*****************************************************************************
+ * Some basic functions to manipulate MP4_Stream_t, an abstraction o p_input
+ *  in the way that you can read from a memory buffer or from an input
+ *
+ *****************************************************************************/
+
+/****  ------- First some function to make abstract from input --------  */
+
+/****************************************************************************
+ * MP4_InputStream create an stram with an input
+ *
+ ****************************************************************************/
+MP4_Stream_t *MP4_InputStream( input_thread_t *p_input )
+{
+    MP4_Stream_t *p_stream;
+
+    if( !( p_stream = malloc( sizeof( MP4_Stream_t ) ) ) )
+    {
+        return( NULL );
+    }
+    p_stream->b_memory = 0;
+    p_stream->p_input = p_input;
+    p_stream->i_start = 0;
+    p_stream->i_stop = 0;
+    p_stream->p_buffer = NULL;
+    return( p_stream );
+}
+
+
+/****************************************************************************
+ * MP4_MemoryStream create a memory stream
+ * if p_buffer == NULL, will allocate a buffer of i_size, else 
+ *     it uses p_buffer XXX you have to unallocate it yourself !
+ *
+ ****************************************************************************/
+MP4_Stream_t *MP4_MemoryStream( input_thread_t *p_input,
+                                int i_size, u8 *p_buffer )
+{
+    MP4_Stream_t *p_stream;
+
+    if( !( p_stream = malloc( sizeof( MP4_Stream_t ) ) ) )
+    {
+        return( NULL );
+    }
+    p_stream->b_memory = 1;
+    p_stream->p_input = p_input;
+    p_stream->i_start = 0;
+    p_stream->i_stop = i_size;
+    if( !p_stream->p_buffer )
+    {
+        if( !( p_stream->p_buffer = malloc( i_size ) ) )
+        {
+            free( p_stream );
+            return( NULL );
+        }
+    }
+    else
+    {
+        p_stream->p_buffer = p_buffer;
+    }
+
+    return( p_stream );
+}
+/****************************************************************************
+ * MP4_ReadStream read from a MP4_Stream_t
+ *
+ ****************************************************************************/
+int MP4_ReadStream( MP4_Stream_t *p_stream, u8 *p_buff, int i_size )
+{
+    if( p_stream->b_memory )
+    {
+        if( i_size > p_stream->i_stop - p_stream->i_start )
+        {
+            return( 0 );
+        }
+        memcpy( p_buff, 
+                p_stream->p_buffer + p_stream->i_start,
+                i_size );
+        p_stream->i_start += i_size;
+        return( 1 );
+    }
+    else
+    {
+        return( MP4_ReadData( p_stream->p_input, p_buff, i_size ) );
+    }
+}
+
+/****************************************************************************
+ * MP4_PeekStream peek from a MP4_Stream_t
+ *
+ ****************************************************************************/
+int MP4_PeekStream( MP4_Stream_t *p_stream, u8 **pp_peek, int i_size )
+{
+    if( p_stream->b_memory )
+    {
+        *pp_peek = p_stream->p_buffer + p_stream->i_start;
+
+        return( __MIN(i_size,p_stream->i_stop - p_stream->i_start ));
+    }
+    else
+    {
+        return( input_Peek( p_stream->p_input, pp_peek, i_size ) );
+    }
+}
+
+/****************************************************************************
+ * MP4_TellStream give absolute position in the stream
+ * XXX for a memory stream give position from begining of the buffer
+ ****************************************************************************/
+off_t MP4_TellStream( MP4_Stream_t *p_stream )
+{
+    if( p_stream->b_memory )
+    {
+        return( p_stream->i_start );
+    }
+    else
+    {
+        return( MP4_TellAbsolute( p_stream->p_input ) );
+    }
+}
+
+/****************************************************************************
+ * MP4_SeekStream seek in a MP4_Stream_t
+ *
+ ****************************************************************************/
+int MP4_SeekStream( MP4_Stream_t *p_stream, off_t i_pos)
+{
+    if( p_stream->b_memory )
+    {
+        if( i_pos < p_stream->i_stop )
+        {
+            p_stream->i_start = i_pos;
+            return( 1 );
+        }
+        else
+        {
+            return( 0 );
+        }
+    }
+    else
+    {
+        return( MP4_SeekAbsolute( p_stream->p_input, i_pos ) );
+    }
+}
+
+
+
+/*****************************************************************************
+ * MP4_ReadBoxCommon : Load only common parameters for all boxes 
+ *****************************************************************************
+ * p_box need to be an already allocated MP4_Box_t, and all data 
+ *  will only be peek not read
+ *
+ * RETURN : 0 if it fail, 1 otherwise
+ *****************************************************************************/
+int MP4_ReadBoxCommon( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i_read;
+    u8  *p_peek;
+    
+    if( ( ( i_read = MP4_PeekStream( p_stream, &p_peek, 32 ) ) < 8 ) )
+    {
+        return( 0 );
+    }
+    p_box->i_pos = MP4_TellStream( p_stream );
+
+    p_box->data.p_data = NULL;
+    p_box->p_father = NULL;
+    p_box->p_first  = NULL;
+    p_box->p_last  = NULL;
+    p_box->p_next   = NULL;
+    
+    MP4_GET4BYTES( p_box->i_shortsize );
+    MP4_GET4BYTES( p_box->i_type );
+
+    /* Now special case */
+
+    if( p_box->i_shortsize == 1 )
+    {
+        /* get the true size on 64 bits */
+        MP4_GET8BYTES( p_box->i_size );
+    }
+    else
+    {
+        p_box->i_size = p_box->i_shortsize;
+        /* XXX size of 0 means that the box extends to end of file */
+    }
+    
+    if( p_box->i_type == FOURCC_uuid )
+    {
+        /* get extented type on 16 bytes */
+        GetUUID( &p_box->i_uuid, p_peek );
+        p_peek += 16; i_read -= 16;
+    }
+    else
+    {
+        CreateUUID( &p_box->i_uuid, p_box->i_type );
+    }
+#ifdef MP4_VERBOSE
+    /* FIXME how to write u64 ??? */
+    if( p_box->i_size )
+    {
+        msg_Dbg( p_stream->p_input, "Found Box: %c%c%c%c size %d",
+                 (p_box->i_type>>24)&0xff, (p_box->i_type>>16)&0xff, 
+                     (p_box->i_type>>8)&0xff, (p_box->i_type)&0xff,
+                 (u32)p_box->i_size );
+    }
+#endif
+
+    return( 1 ); 
+}
+
+
+/*****************************************************************************
+ * MP4_MP4_NextBox : Go to the next box 
+ *****************************************************************************
+ * if p_box == NULL, go to the next box in witch we are( at the begining ).
+ *****************************************************************************/
+int MP4_NextBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_Box_t box;
+
+    if( !p_box )
+    {
+        MP4_ReadBoxCommon( p_stream, &box );
+        p_box = &box;
+    }
+
+    if( !p_box->i_size )
+    {
+        return( 2 ); /* Box with infinite size */
+    }
+
+    if( p_box->p_father )
+    {
+        /* check if it's within p-father */
+        if( p_box->i_size + p_box->i_pos >= 
+                    p_box->p_father->i_size + p_box->p_father->i_pos )
+        {
+            return( 0 ); /* out of bound */
+        }
+    }
+    return( MP4_SeekStream( p_stream, p_box->i_size + p_box->i_pos ) );
+}
+/*****************************************************************************
+ * MP4_MP4_GotoBox : Go to this particular box 
+ *****************************************************************************
+ * RETURN : 0 if it fail, 1 otherwise
+ *****************************************************************************/
+int MP4_GotoBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    return( MP4_SeekStream( p_stream, p_box->i_pos ) );
+}
+
+
+/*****************************************************************************
+ * For all known box a loader is given, 
+ *  XXX: all common struct have to be already read by MP4_ReadBoxCommon
+ *       after called one of theses functions, file position is unknown
+ *       you need to call MP4_GotoBox to go where you want 
+ *****************************************************************************/
+int MP4_ReadBoxContainerRaw( MP4_Stream_t *p_stream, MP4_Box_t *p_container )
+{
+    MP4_Box_t *p_box;
+    
+    if( MP4_TellStream( p_stream ) + 8 > 
+                        p_container->i_pos + p_container->i_size  )
+    {
+        /* there is no box to load */
+        return( 0 );
+    }
+    
+    do
+    {
+        p_box = malloc( sizeof( MP4_Box_t ) );
+
+        if( MP4_ReadBox( p_stream, p_box , p_container ) )
+        {
+            /* chain this box with the father and the other at same level */
+            if( !p_container->p_first )
+            {
+                p_container->p_first = p_box;
+            }
+            else
+            {
+                p_container->p_last->p_next = p_box;
+            }
+            p_container->p_last = p_box;
+        }
+        else
+        {
+            /* free memory */
+            free( p_box );
+            break;
+        }
+        
+    }while( MP4_NextBox( p_stream, p_box ) == 1 );
+    
+    return( 1 );
+}
+
+
+int MP4_ReadBoxContainer( MP4_Stream_t *p_stream, MP4_Box_t *p_container )
+{
+    
+    if( p_container->i_size <= MP4_BOX_HEADERSIZE(p_container ) + 8 )
+    {
+        /* container is empty, 8 stand for the first header in this box */
+        return( 1 );
+    }
+    
+    /* enter box */
+    MP4_BOX_DESCEND( p_container );
+
+    return( MP4_ReadBoxContainerRaw( p_stream, p_container ) );
+}
+
+void MP4_FreeBox_Common( input_thread_t *p_input, MP4_Box_t *p_box )
+{
+    if( p_box->data.p_data )
+    {
+        free( p_box->data.p_data );
+        p_box->data.p_data = NULL;
+    }
+}
+
+int MP4_ReadBoxSkip( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "
+             Skip box: \"%c%c%c%c\"", 
+            (p_box->i_type>>24)&0xff, 
+            (p_box->i_type>>16)&0xff,
+            (p_box->i_type>>8)&0xff, 
+            (p_box->i_type)&0xff );
+#endif
+    return( 1 );
+}
+
+int MP4_ReadBox_ftyp( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_ftyp_t );
+    
+    MP4_GET4BYTES( p_box->data.p_ftyp->i_major_brand );
+    MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version );
+    
+    if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) )
+    {
+        int i;
+        p_box->data.p_ftyp->i_compatible_brands = 
+            calloc( p_box->data.p_ftyp->i_compatible_brands_count, sizeof(u32));
+
+        for( i =0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )
+        {
+            MP4_GET4BYTES( p_box->data.p_ftyp->i_compatible_brands[i] );
+        }
+    }
+    else
+    {
+        p_box->data.p_ftyp->i_compatible_brands = NULL;
+    }
+
+    MP4_READBOX_EXIT( 1 );
+}
+
+
+int MP4_ReadBox_mvhd(  MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+#ifdef MP4_VERBOSE
+    char s_creation_time[128];
+    char s_modification_time[128];
+    char s_duration[128];
+#endif
+    MP4_READBOX_ENTER( MP4_Box_data_mvhd_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );
+
+    if( p_box->data.p_mvhd->i_version )
+    {
+        MP4_GET8BYTES( p_box->data.p_mvhd->i_creation_time );
+        MP4_GET8BYTES( p_box->data.p_mvhd->i_modification_time );
+        MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
+        MP4_GET8BYTES( p_box->data.p_mvhd->i_duration );
+    }
+    else
+    {
+        MP4_GET4BYTES( p_box->data.p_mvhd->i_creation_time );
+        MP4_GET4BYTES( p_box->data.p_mvhd->i_modification_time );
+        MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
+        MP4_GET4BYTES( p_box->data.p_mvhd->i_duration );
+    }
+    MP4_GET4BYTES( p_box->data.p_mvhd->i_rate ); 
+    MP4_GET2BYTES( p_box->data.p_mvhd->i_volume ); 
+    MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 );
+
+  
+    for( i = 0; i < 2; i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] );
+    }
+    for( i = 0; i < 9; i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] );
+    }
+    for( i = 0; i < 6; i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] );
+    }
+    
+    MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id );
+    
+            
+#ifdef MP4_VERBOSE
+    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
+    MP4_ConvertDate2Str( s_modification_time, 
+                         p_box->data.p_mvhd->i_modification_time );
+    if( p_box->data.p_mvhd->i_rate )
+    {
+        MP4_ConvertDate2Str( s_duration, 
+                 p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate );
+    }
+    else
+    {
+        s_duration[0] = 0;
+    }    
+    msg_Dbg( p_stream->p_input, "Read Box: \"mvhd\" creation %s modification %s time scale %d duration %s rate %f volume %f next track id %d",
+                  s_creation_time,
+                  s_modification_time,
+                  (u32)p_box->data.p_mvhd->i_timescale,
+                  s_duration,
+                  (float)p_box->data.p_mvhd->i_rate / (1<<16 ),
+                  (float)p_box->data.p_mvhd->i_volume / 256 ,
+                  (u32)p_box->data.p_mvhd->i_next_track_id );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_tkhd(  MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+#ifdef MP4_VERBOSE
+    char s_creation_time[128];
+    char s_modification_time[128];
+    char s_duration[128];
+#endif
+    MP4_READBOX_ENTER( MP4_Box_data_tkhd_t );
+    
+    MP4_GETVERSIONFLAGS( p_box->data.p_tkhd );
+
+    if( p_box->data.p_tkhd->i_version )
+    {
+        MP4_GET8BYTES( p_box->data.p_tkhd->i_creation_time );
+        MP4_GET8BYTES( p_box->data.p_tkhd->i_modification_time );
+        MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
+        MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
+        MP4_GET8BYTES( p_box->data.p_tkhd->i_duration );
+    }
+    else
+    {
+        MP4_GET4BYTES( p_box->data.p_tkhd->i_creation_time );
+        MP4_GET4BYTES( p_box->data.p_tkhd->i_modification_time );
+        MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
+        MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
+        MP4_GET4BYTES( p_box->data.p_tkhd->i_duration );
+    }
+    
+    for( i = 0; i < 2; i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved2[i] );
+    }
+    MP4_GET2BYTES( p_box->data.p_tkhd->i_layer );
+    MP4_GET2BYTES( p_box->data.p_tkhd->i_predefined );
+    MP4_GET2BYTES( p_box->data.p_tkhd->i_volume );
+    MP4_GET2BYTES( p_box->data.p_tkhd->i_reserved3 );
+
+    for( i = 0; i < 9; i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_tkhd->i_matrix[i] );
+    }
+    MP4_GET4BYTES( p_box->data.p_tkhd->i_width );
+    MP4_GET4BYTES( p_box->data.p_tkhd->i_height );
+            
+#ifdef MP4_VERBOSE
+    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
+    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time );
+    MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration );
+    
+    msg_Dbg( p_stream->p_input, "Read Box: \"tkhd\" creation %s modification %s duration %s track ID %d layer %d volume %f width %f height %f",
+                  s_creation_time,
+                  s_modification_time,
+                  s_duration,
+                  p_box->data.p_tkhd->i_track_ID,
+                  p_box->data.p_tkhd->i_layer,
+                  (float)p_box->data.p_tkhd->i_volume / 256 ,
+                  (float)p_box->data.p_tkhd->i_width / 65536,
+                  (float)p_box->data.p_tkhd->i_height / 65536 );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_tref( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_Box_t *p_ref;
+
+    if( p_box->i_size < MP4_BOX_HEADERSIZE(p_box ) + 8 )
+    {
+        /* container is empty, 8 stand for the first header in this box */
+        return( 1 );
+    }
+   
+    if( !MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) ) )
+    {
+        return( 0 );
+    }
+      
+    do
+    {
+        p_ref = malloc( sizeof( MP4_Box_t ) );
+        if( MP4_ReadBoxCommon( p_stream, p_ref ) )
+        {
+            switch( p_ref->i_type )
+            {
+                case( FOURCC_hint ):
+                case( FOURCC_dpnd ):
+                case( FOURCC_ipir ):
+                case( FOURCC_mpod ):
+                default:
+                    msg_Warn( p_stream->p_input, "Unknown TrackReferenceType %c%c%c%c (uncompletetly loaded)",
+                                       ( p_ref->i_type >> 24 )&0xff,
+                                       ( p_ref->i_type >> 16 )&0xff,
+                                       ( p_ref->i_type >>  8 )&0xff,
+                                       ( p_ref->i_type )&0xff );
+                    break;
+            }
+            /* chain this box with the father and the other at same level */
+            if( !p_box->p_first )
+            {
+                p_box->p_first = p_ref;
+                p_box->p_last = p_ref;
+            }
+            else
+            {
+                p_box->p_last->p_next = p_ref;
+                p_box->p_last = p_ref;
+            }
+            p_ref->p_father = p_box;
+        }
+        else
+        {
+            /* free memory */
+            free( p_ref );
+        }
+        
+        
+    }while( MP4_NextBox( p_stream, p_ref ) == 1 );
+    
+    
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"tref\" " );
+
+#endif
+    return( 1 );
+}
+
+
+
+int MP4_ReadBox_mdhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+    u16 i_language;
+#ifdef MP4_VERBOSE
+    char s_creation_time[128];
+    char s_modification_time[128];
+    char s_duration[128];
+#endif
+    MP4_READBOX_ENTER( MP4_Box_data_mdhd_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_mdhd );
+
+    if( p_box->data.p_mdhd->i_version )
+    {
+        MP4_GET8BYTES( p_box->data.p_mdhd->i_creation_time );
+        MP4_GET8BYTES( p_box->data.p_mdhd->i_modification_time );
+        MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
+        MP4_GET8BYTES( p_box->data.p_mdhd->i_duration );
+    }
+    else
+    {
+        MP4_GET4BYTES( p_box->data.p_mdhd->i_creation_time );
+        MP4_GET4BYTES( p_box->data.p_mdhd->i_modification_time );
+        MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
+        MP4_GET4BYTES( p_box->data.p_mdhd->i_duration );
+    }
+    i_language = GetWBE( p_peek ); 
+    for( i = 0; i < 3; i++ )
+    {
+        p_box->data.p_mdhd->i_language[i] = 
+                    ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
+    }
+
+    MP4_GET2BYTES( p_box->data.p_mdhd->i_predefined );
+  
+#ifdef MP4_VERBOSE
+    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time );
+    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time );
+    MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration );
+    msg_Dbg( p_stream->p_input, "Read Box: \"mdhd\" creation %s modification %s time scale %d duration %s language %c%c%c",
+                  s_creation_time,
+                  s_modification_time,
+                  (u32)p_box->data.p_mdhd->i_timescale,
+                  s_duration,
+                  p_box->data.p_mdhd->i_language[0],
+                  p_box->data.p_mdhd->i_language[1],
+                  p_box->data.p_mdhd->i_language[2] );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+
+int MP4_ReadBox_hdlr( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_hdlr_t ); 
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_hdlr );
+    MP4_GET4BYTES( p_box->data.p_hdlr->i_predefined );
+    MP4_GET4BYTES( p_box->data.p_hdlr->i_handler_type );
+
+    p_box->data.p_hdlr->psz_name = calloc( sizeof( char ), i_read + 1 );
+    memcpy( p_box->data.p_hdlr->psz_name, p_peek, i_read );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"hdlr\" hanler type %c%c%c%c name %s",
+                       ( p_box->data.p_hdlr->i_handler_type >> 24 )&0xff,
+                       ( p_box->data.p_hdlr->i_handler_type >> 16 )&0xff,
+                       ( p_box->data.p_hdlr->i_handler_type >>  8 )&0xff,
+                       ( p_box->data.p_hdlr->i_handler_type )&0xff,
+                       p_box->data.p_hdlr->psz_name );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_vmhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+   
+    MP4_READBOX_ENTER( MP4_Box_data_vmhd_t ); 
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_vmhd );
+    
+    MP4_GET2BYTES( p_box->data.p_vmhd->i_graphics_mode );
+    for( i = 0; i < 3; i++ )
+    {
+        MP4_GET2BYTES( p_box->data.p_vmhd->i_opcolor[i] );
+    }
+    
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"vmhd\" graphics-mode %d opcolor (%d, %d, %d)",
+                      p_box->data.p_vmhd->i_graphics_mode,
+                      p_box->data.p_vmhd->i_opcolor[0],
+                      p_box->data.p_vmhd->i_opcolor[1],
+                      p_box->data.p_vmhd->i_opcolor[2] );
+                      
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_smhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_smhd_t ); 
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_smhd );
+
+
+
+    MP4_GET2BYTES( p_box->data.p_smhd->i_balance );
+
+    MP4_GET4BYTES( p_box->data.p_smhd->i_reserved );
+    
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"smhd\" balance %f",
+                      (float)p_box->data.p_smhd->i_balance / 256 );
+                      
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+
+int MP4_ReadBox_hmhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_hmhd_t ); 
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_hmhd );
+
+    MP4_GET2BYTES( p_box->data.p_hmhd->i_max_PDU_size );
+    MP4_GET2BYTES( p_box->data.p_hmhd->i_avg_PDU_size );
+
+    MP4_GET4BYTES( p_box->data.p_hmhd->i_max_bitrate );
+    MP4_GET4BYTES( p_box->data.p_hmhd->i_avg_bitrate );
+
+    MP4_GET4BYTES( p_box->data.p_hmhd->i_reserved );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"hmhd\" maxPDU-size %d avgPDU-size %d max-bitrate %d avg-bitrate %d",
+                      p_box->data.p_hmhd->i_max_PDU_size,
+                      p_box->data.p_hmhd->i_avg_PDU_size,
+                      p_box->data.p_hmhd->i_max_bitrate,
+                      p_box->data.p_hmhd->i_avg_bitrate );
+                      
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_url( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_url_t ); 
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_url );
+    MP4_GETSTRING( p_box->data.p_url->psz_location );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"url\" url: %s",
+                       p_box->data.p_url->psz_location );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_urn( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_urn_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_urn );
+
+    MP4_GETSTRING( p_box->data.p_urn->psz_name );
+    MP4_GETSTRING( p_box->data.p_urn->psz_location ); 
+   
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"urn\" name %s location %s",
+                      p_box->data.p_urn->psz_name,
+                      p_box->data.p_urn->psz_location );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+
+
+int MP4_ReadBox_dref( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_dref_t );
+    
+    MP4_GETVERSIONFLAGS( p_box->data.p_dref );
+
+    MP4_GET4BYTES( p_box->data.p_dref->i_entry_count );
+   
+    MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 8 );
+    MP4_ReadBoxContainerRaw( p_stream, p_box );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"dref\" entry-count %d",
+                      p_box->data.p_dref->i_entry_count );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_stts( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+    MP4_READBOX_ENTER( MP4_Box_data_stts_t ); 
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_stts );
+    MP4_GET4BYTES( p_box->data.p_stts->i_entry_count );
+
+    p_box->data.p_stts->i_sample_count = 
+        calloc( sizeof( u32 ), p_box->data.p_stts->i_entry_count );
+    p_box->data.p_stts->i_sample_delta =
+        calloc( sizeof( u32 ), p_box->data.p_stts->i_entry_count );
+    
+    for( i = 0; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_stts->i_sample_count[i] );
+        MP4_GET4BYTES( p_box->data.p_stts->i_sample_delta[i] );
+    }
+    
+    
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"stts\" entry-count %d",
+                      p_box->data.p_stts->i_entry_count );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_ctts( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+    MP4_READBOX_ENTER( MP4_Box_data_ctts_t );
+    
+    MP4_GETVERSIONFLAGS( p_box->data.p_ctts );
+    MP4_GET4BYTES( p_box->data.p_ctts->i_entry_count );
+
+    p_box->data.p_ctts->i_sample_count = 
+        calloc( sizeof( u32 ), p_box->data.p_ctts->i_entry_count );
+    p_box->data.p_ctts->i_sample_offset =
+        calloc( sizeof( u32 ), p_box->data.p_ctts->i_entry_count );
+    
+    for( i = 0; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_ctts->i_sample_count[i] );
+        MP4_GET4BYTES( p_box->data.p_ctts->i_sample_offset[i] );
+    }
+    
+    
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"ctts\" entry-count %d",
+                      p_box->data.p_ctts->i_entry_count );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+static inline int MP4_ReadLengthDescriptor( u8 **pp_peek, s64 *i_read )
+{
+    int i_b;
+    int i_len = 0;
+    do
+    {
+        i_b = **pp_peek;
+
+        (*pp_peek)++;
+        (*i_read)--;
+        i_len = ( i_len << 7 ) + ( i_b&0x7f );
+    } while( i_b&0x80 );
+    return( i_len );    
+}
+
+int MP4_ReadBox_esds( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+#define es_descriptor p_box->data.p_esds->es_descriptor
+    int i_len;
+    int i_flags;
+    int i_type;
+
+    MP4_READBOX_ENTER( MP4_Box_data_esds_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_esds );
+
+
+    MP4_GET1BYTE( i_type );
+    if( i_type == 0x03 ) /* MP4ESDescrTag */
+    {
+        i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
+
+        MP4_GET2BYTES( es_descriptor.i_ES_ID );
+        MP4_GET1BYTE( i_flags );
+        es_descriptor.b_stream_dependence = ( (i_flags&0x80) != 0);
+        es_descriptor.b_url = ( (i_flags&0x40) != 0);
+        es_descriptor.b_OCRstream = ( (i_flags&0x20) != 0);
+
+        es_descriptor.i_stream_priority = i_flags&0x1f;
+        if( es_descriptor.b_stream_dependence )
+        {
+            MP4_GET2BYTES( es_descriptor.i_depend_on_ES_ID );
+        }
+        if( es_descriptor.b_url )
+        {
+            int i_len;
+        
+            MP4_GET1BYTE( i_len );
+            es_descriptor.psz_URL = calloc( sizeof(char), i_len + 1 );
+            memcpy( es_descriptor.psz_URL, p_peek, i_len );
+            es_descriptor.psz_URL[i_len] = 0;
+        }
+        else
+        {
+            es_descriptor.psz_URL = NULL;
+        }
+        if( es_descriptor.b_OCRstream )
+        {
+            MP4_GET2BYTES( es_descriptor.i_OCR_ES_ID );
+        }
+        MP4_GET1BYTE( i_type ); /* get next type */
+    }
+    if( i_type != 0x04)/* MP4DecConfigDescrTag */
+    {
+        MP4_READBOX_EXIT( 1 ); /* rest isn't interesting up to now */
+    }
+
+    i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
+    es_descriptor.p_decConfigDescr = 
+            malloc( sizeof( MP4_descriptor_decoder_config_t ));
+
+    MP4_GET1BYTE( es_descriptor.p_decConfigDescr->i_objectTypeIndication );
+    MP4_GET1BYTE( i_flags );
+    es_descriptor.p_decConfigDescr->i_streamType = i_flags >> 2;
+    es_descriptor.p_decConfigDescr->b_upStream = ( i_flags >> 1 )&0x01;
+    MP4_GET3BYTES( es_descriptor.p_decConfigDescr->i_buffer_sizeDB );
+    MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_max_bitrate );
+    MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_avg_bitrate );
+    MP4_GET1BYTE( i_type );
+    if( i_type !=  0x05 )/* MP4DecSpecificDescrTag */
+    {
+        MP4_READBOX_EXIT( 1 );
+    }
+   
+    i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
+    es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = i_len;
+    es_descriptor.p_decConfigDescr->p_decoder_specific_info = malloc( i_len );
+    memcpy( es_descriptor.p_decConfigDescr->p_decoder_specific_info, 
+            p_peek, i_len );
+
+    MP4_READBOX_EXIT( 1 );
+
+#undef es_descriptor
+}
+
+int MP4_ReadBox_sample_soun( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;    
+    
+    MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t );
+
+    for( i = 0; i < 6 ; i++ )
+    {
+        MP4_GET1BYTE( p_box->data.p_sample_soun->i_reserved1[i] );
+    }
+
+    MP4_GET2BYTES( p_box->data.p_sample_soun->i_data_reference_index );
+    
+    for( i = 0; i < 2 ; i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_sample_soun->i_reserved2[i] );
+    }
+   
+    MP4_GET2BYTES( p_box->data.p_sample_soun->i_channelcount );
+    MP4_GET2BYTES( p_box->data.p_sample_soun->i_samplesize );
+    MP4_GET2BYTES( p_box->data.p_sample_soun->i_predefined );
+    MP4_GET2BYTES( p_box->data.p_sample_soun->i_reserved3 );
+    MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratehi );
+    MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratelo );
+    
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"soun\" in stsd channel %d sample size %d sampl rate %f",
+                      p_box->data.p_sample_soun->i_channelcount,
+                      p_box->data.p_sample_soun->i_samplesize,
+                      (float)p_box->data.p_sample_soun->i_sampleratehi + 
+                    (float)p_box->data.p_sample_soun->i_sampleratelo / 65536 );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_sample_mp4a( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;    
+
+    MP4_READBOX_ENTER( MP4_Box_data_sample_mp4a_t );
+    
+    for( i = 0; i < 6 ; i++ )
+    {
+        MP4_GET1BYTE( p_box->data.p_sample_mp4a->i_reserved1[i] );
+    }
+
+    MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_data_reference_index );
+    
+    for( i = 0; i < 2 ; i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_sample_mp4a->i_reserved2[i] );
+    }
+   
+    MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_channelcount );
+    MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_samplesize );
+    MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_predefined );
+    MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_reserved3 );
+    MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_sampleratehi );
+    MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_sampleratelo );
+    
+    MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 28 );
+    MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"mp4a\" in stsd channel %d sample size %d sampl rate %f",
+                      p_box->data.p_sample_mp4a->i_channelcount,
+                      p_box->data.p_sample_mp4a->i_samplesize,
+                      (float)p_box->data.p_sample_mp4a->i_sampleratehi + 
+                        (float)p_box->data.p_sample_mp4a->i_sampleratelo / 65536 );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_sample_vide( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;    
+
+    MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t );
+
+    for( i = 0; i < 6 ; i++ )
+    {
+        MP4_GET1BYTE( p_box->data.p_sample_vide->i_reserved1[i] );
+    }
+
+    MP4_GET2BYTES( p_box->data.p_sample_vide->i_data_reference_index );
+
+    MP4_GET2BYTES( p_box->data.p_sample_vide->i_predefined1 );
+    MP4_GET2BYTES( p_box->data.p_sample_vide->i_reserved2 );
+
+    for( i = 0; i < 3 ; i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_sample_vide->i_predefined2[i] );
+    }
+
+    MP4_GET2BYTES( p_box->data.p_sample_vide->i_width );
+    MP4_GET2BYTES( p_box->data.p_sample_vide->i_height );
+    
+    MP4_GET4BYTES( p_box->data.p_sample_vide->i_horizresolution );
+    MP4_GET4BYTES( p_box->data.p_sample_vide->i_vertresolution );
+
+    MP4_GET4BYTES( p_box->data.p_sample_vide->i_reserved3 );
+    MP4_GET2BYTES( p_box->data.p_sample_vide->i_predefined3 );
+
+    memcpy( &p_box->data.p_sample_vide->i_compressorname, p_peek, 32 );
+    p_peek += 32; i_read -= 32;
+
+    MP4_GET2BYTES( p_box->data.p_sample_vide->i_depth );
+    MP4_GET2BYTES( p_box->data.p_sample_vide->i_predefined4 );
+    
+    
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"vide\" in stsd %dx%d depth %d",
+                      p_box->data.p_sample_vide->i_width,
+                      p_box->data.p_sample_vide->i_height,
+                      p_box->data.p_sample_vide->i_depth );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_sample_mp4v( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;    
+
+    MP4_READBOX_ENTER( MP4_Box_data_sample_mp4v_t );
+    
+    for( i = 0; i < 6 ; i++ )
+    {
+        MP4_GET1BYTE( p_box->data.p_sample_mp4v->i_reserved1[i] );
+    }
+
+    MP4_GET2BYTES( p_box->data.p_sample_mp4v->i_data_reference_index );
+
+    MP4_GET2BYTES( p_box->data.p_sample_mp4v->i_predefined1 );
+    MP4_GET2BYTES( p_box->data.p_sample_mp4v->i_reserved2 );
+
+    for( i = 0; i < 3 ; i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_sample_mp4v->i_predefined2[i] );
+    }
+
+    MP4_GET2BYTES( p_box->data.p_sample_mp4v->i_width );
+    MP4_GET2BYTES( p_box->data.p_sample_mp4v->i_height );
+    
+    MP4_GET4BYTES( p_box->data.p_sample_mp4v->i_horizresolution );
+    MP4_GET4BYTES( p_box->data.p_sample_mp4v->i_vertresolution );
+
+    MP4_GET4BYTES( p_box->data.p_sample_mp4v->i_reserved3 );
+    MP4_GET2BYTES( p_box->data.p_sample_mp4v->i_predefined3 );
+
+    /* This is a pascal string, padded to 32 bytes */
+    memcpy( &p_box->data.p_sample_mp4v->i_compressorname, p_peek+1, 31 );
+    p_box->data.p_sample_mp4v->i_compressorname[*p_peek] = 0;
+    p_peek += 32; i_read -= 32;
+
+    MP4_GET2BYTES( p_box->data.p_sample_mp4v->i_depth );
+    MP4_GET2BYTES( p_box->data.p_sample_mp4v->i_predefined4 );
+
+
+    MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 78);
+    MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */
+    
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"mp4v\" in stsd %dx%d depth %d compressor %s",
+                      p_box->data.p_sample_mp4v->i_width,
+                      p_box->data.p_sample_mp4v->i_height,
+                      p_box->data.p_sample_mp4v->i_depth,
+                      p_box->data.p_sample_mp4v->i_compressorname );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+
+
+int MP4_ReadBox_stsd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_Box_t *p_sample;
+
+    MP4_READBOX_ENTER( MP4_Box_data_stsd_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_stsd );
+
+    MP4_GET4BYTES( p_box->data.p_stsd->i_entry_count );
+
+    MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 8 ); 
+
+
+    do
+    {
+        p_sample = malloc( sizeof( MP4_Box_t ) );
+        if( MP4_ReadBoxCommon( p_stream, p_sample ) )
+        {
+            switch( p_sample->i_type )
+            {
+                case( FOURCC_soun ):
+                case( FOURCC__mp3 ):
+                    MP4_ReadBox_sample_soun( p_stream, p_sample );
+                    break;
+                case( FOURCC_mp4a ):
+                    MP4_ReadBox_sample_mp4a( p_stream, p_sample );
+                    break;
+                case( FOURCC_DIVX ):
+                case( FOURCC_SVQ1 ):
+                case( FOURCC_vide ):
+                case( FOURCC_3IV1 ):
+                case( FOURCC_h263 ):
+                    MP4_ReadBox_sample_vide( p_stream, p_sample );
+                    break;
+                case( FOURCC_mp4v ):
+                    MP4_ReadBox_sample_mp4v( p_stream, p_sample );
+                    break;
+
+                case( FOURCC_mp4s ):
+                case( FOURCC_hint ):
+                default:
+                    msg_Warn( p_stream->p_input, "Unknown SampleEntry type %c%c%c%c (uncompletetly loaded)",
+                                       ( p_sample->i_type >> 24 )&0xff,
+                                       ( p_sample->i_type >> 16 )&0xff,
+                                       ( p_sample->i_type >>  8 )&0xff,
+                                       ( p_sample->i_type )&0xff );
+                    break;
+            }
+            
+            MP4_GotoBox( p_stream, p_sample );    
+            /* chain this box with the father and the other at same level */
+            if( !p_box->p_first )
+            {
+                p_box->p_first = p_sample;
+                p_box->p_last = p_sample;
+            }
+            else
+            {
+                p_box->p_last->p_next = p_sample;
+                p_box->p_last = p_sample;
+            }
+            p_sample->p_father = p_box;
+        }
+        else
+        {
+            /* free memory */
+            free( p_sample );
+        }
+        
+    }while( MP4_NextBox( p_stream, p_sample ) == 1 );
+    
+    
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"stsd\" entry-count %d",
+                      p_box->data.p_stsd->i_entry_count );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+
+int MP4_ReadBox_stsz( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+
+    MP4_READBOX_ENTER( MP4_Box_data_stsz_t );
+    
+    MP4_GETVERSIONFLAGS( p_box->data.p_stsz );
+    
+    MP4_GET4BYTES( p_box->data.p_stsz->i_sample_size );
+
+    MP4_GET4BYTES( p_box->data.p_stsz->i_sample_count );
+
+    p_box->data.p_stsz->i_entry_size = 
+        calloc( sizeof( u32 ), p_box->data.p_stsz->i_sample_count );
+    
+    if( !p_box->data.p_stsz->i_sample_size )
+    {
+        for( i=0; (i<p_box->data.p_stsz->i_sample_count)&&(i_read >= 4 ); i++ )
+        {
+            MP4_GET4BYTES( p_box->data.p_stsz->i_entry_size[i] );
+        }
+    }
+    
+    
+#ifdef MP4_VERBOSE 
+    msg_Dbg( p_stream->p_input, "Read Box: \"stsz\" sample-size %d sample-count %d",
+                      p_box->data.p_stsz->i_sample_size,
+                      p_box->data.p_stsz->i_sample_count );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_stsc( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+    
+    MP4_READBOX_ENTER( MP4_Box_data_stsc_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_stsc );
+    
+    MP4_GET4BYTES( p_box->data.p_stsc->i_entry_count );
+
+    p_box->data.p_stsc->i_first_chunk = 
+        calloc( sizeof( u32 ), p_box->data.p_stsc->i_entry_count );
+    p_box->data.p_stsc->i_samples_per_chunk = 
+        calloc( sizeof( u32 ), p_box->data.p_stsc->i_entry_count );
+    p_box->data.p_stsc->i_sample_description_index = 
+        calloc( sizeof( u32 ), p_box->data.p_stsc->i_entry_count );
+
+    for( i = 0; (i < p_box->data.p_stsc->i_entry_count )&&( i_read >= 12 );i++ )
+    {
+        MP4_GET4BYTES( p_box->data.p_stsc->i_first_chunk[i] );
+        MP4_GET4BYTES( p_box->data.p_stsc->i_samples_per_chunk[i] );
+        MP4_GET4BYTES( p_box->data.p_stsc->i_sample_description_index[i] );
+    }
+    
+    
+#ifdef MP4_VERBOSE 
+    msg_Dbg( p_stream->p_input, "Read Box: \"stsc\" entry-count %d",
+                      p_box->data.p_stsc->i_entry_count );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_stco_co64( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+    
+    MP4_READBOX_ENTER( MP4_Box_data_co64_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_co64 );
+
+    MP4_GET4BYTES( p_box->data.p_co64->i_entry_count );
+
+    p_box->data.p_co64->i_chunk_offset = 
+        calloc( sizeof( u64 ), p_box->data.p_co64->i_entry_count );
+
+    for( i = 0; (i < p_box->data.p_co64->i_entry_count )&&( i_read >= 8 ); i++ )
+    {
+        if( p_box->i_type == FOURCC_stco )
+        {
+            MP4_GET4BYTES( p_box->data.p_co64->i_chunk_offset[i] );
+        }
+        else
+        {
+            MP4_GET8BYTES( p_box->data.p_co64->i_chunk_offset[i] );
+        }
+    }
+    
+    
+#ifdef MP4_VERBOSE 
+    msg_Dbg( p_stream->p_input, "Read Box: \"co64\" entry-count %d",
+                      p_box->data.p_co64->i_entry_count );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_stss( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+    
+    MP4_READBOX_ENTER( MP4_Box_data_stss_t ); 
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_stss );
+
+    MP4_GET4BYTES( p_box->data.p_stss->i_entry_count );
+
+    p_box->data.p_stss->i_sample_number = 
+        calloc( sizeof( u32 ), p_box->data.p_stss->i_entry_count );
+
+    for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 4 ); i++ )
+    {
+
+        MP4_GET4BYTES( p_box->data.p_stss->i_sample_number[i] );
+    }
+    
+    
+#ifdef MP4_VERBOSE 
+    msg_Dbg( p_stream->p_input, "Read Box: \"stss\" entry-count %d",
+                      p_box->data.p_stss->i_entry_count );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_stsh( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+    
+    MP4_READBOX_ENTER( MP4_Box_data_stsh_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_stsh );
+
+
+    MP4_GET4BYTES( p_box->data.p_stsh->i_entry_count );
+
+    p_box->data.p_stsh->i_shadowed_sample_number = 
+        calloc( sizeof( u32 ), p_box->data.p_stsh->i_entry_count );
+
+    p_box->data.p_stsh->i_sync_sample_number = 
+        calloc( sizeof( u32 ), p_box->data.p_stsh->i_entry_count );
+
+
+    for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 8 ); i++ )
+    {
+
+        MP4_GET4BYTES( p_box->data.p_stsh->i_shadowed_sample_number[i] );
+        MP4_GET4BYTES( p_box->data.p_stsh->i_sync_sample_number[i] );
+    }
+    
+    
+#ifdef MP4_VERBOSE 
+    msg_Dbg( p_stream->p_input, "Read Box: \"stsh\" entry-count %d",
+                      p_box->data.p_stsh->i_entry_count );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_stdp( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+   
+    MP4_READBOX_ENTER( MP4_Box_data_stdp_t ); 
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_stdp );
+
+    p_box->data.p_stdp->i_priority = 
+        calloc( sizeof( u16 ), i_read / 2 );
+
+    for( i = 0; i < i_read / 2 ; i++ )
+    {
+
+        MP4_GET2BYTES( p_box->data.p_stdp->i_priority[i] );
+    }
+    
+    
+#ifdef MP4_VERBOSE 
+    msg_Dbg( p_stream->p_input, "Read Box: \"stdp\" entry-count %d",
+                      i_read / 2 );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_padb( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+    
+    MP4_READBOX_ENTER( MP4_Box_data_padb_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_padb );
+
+
+    MP4_GET4BYTES( p_box->data.p_padb->i_sample_count );
+
+    p_box->data.p_padb->i_reserved1 = 
+        calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
+    p_box->data.p_padb->i_pad2 = 
+        calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
+    p_box->data.p_padb->i_reserved2 = 
+        calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
+    p_box->data.p_padb->i_pad1 = 
+        calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
+
+
+    for( i = 0; i < i_read / 2 ; i++ )
+    {
+        p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 7 )&0x01;
+        p_box->data.p_padb->i_pad2[i] = ( (*p_peek) >> 4 )&0x07;
+        p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 3 )&0x01;
+        p_box->data.p_padb->i_pad1[i] = ( (*p_peek) )&0x07;
+
+        p_peek += 1; i_read -= 1;
+    }
+    
+    
+#ifdef MP4_VERBOSE 
+    msg_Dbg( p_stream->p_input, "Read Box: \"stdp\" entry-count %d",
+                      i_read / 2 );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_elst( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i;
+    
+    MP4_READBOX_ENTER( MP4_Box_data_padb_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_elst );
+
+
+    MP4_GET4BYTES( p_box->data.p_elst->i_entry_count );
+
+    p_box->data.p_elst->i_segment_duration =
+        calloc( sizeof( u64 ), p_box->data.p_elst->i_entry_count );
+    p_box->data.p_elst->i_media_time =
+        calloc( sizeof( u64 ), p_box->data.p_elst->i_entry_count );
+    p_box->data.p_elst->i_media_rate_integer =
+        calloc( sizeof( u16 ), p_box->data.p_elst->i_entry_count );
+    p_box->data.p_elst->i_media_rate_fraction= 
+        calloc( sizeof( u16 ), p_box->data.p_elst->i_entry_count );
+
+
+    for( i = 0; i < p_box->data.p_elst->i_entry_count; i++ )
+    {
+        if( p_box->data.p_elst->i_version == 1 )
+        {
+
+            MP4_GET8BYTES( p_box->data.p_elst->i_segment_duration[i] );
+
+            MP4_GET8BYTES( p_box->data.p_elst->i_media_time[i] );
+        }
+        else
+        {
+
+            MP4_GET4BYTES( p_box->data.p_elst->i_segment_duration[i] );
+
+            MP4_GET4BYTES( p_box->data.p_elst->i_media_time[i] );
+        }
+
+        MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_integer[i] );
+        MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_fraction[i] );
+    }
+    
+    
+#ifdef MP4_VERBOSE 
+    msg_Dbg( p_stream->p_input, "Read Box: \"elst\" entry-count %d",
+                      i_read / 2 );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_cprt( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    int i_language;
+    int i;
+    
+    MP4_READBOX_ENTER( MP4_Box_data_cprt_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_cprt );
+
+    i_language = GetWBE( p_peek ); 
+    for( i = 0; i < 3; i++ )
+    {
+        p_box->data.p_cprt->i_language[i] = 
+            ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
+    }
+    p_peek += 2; i_read -= 2;  
+    MP4_GETSTRING( p_box->data.p_cprt->psz_notice );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"cprt\" language %c%c%c notivce %s",
+                      p_box->data.p_cprt->i_language[0],
+                      p_box->data.p_cprt->i_language[1],
+                      p_box->data.p_cprt->i_language[2],
+                      p_box->data.p_cprt->psz_notice );
+
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_hnti( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_Box_t *p_ref;
+//    MP4_Box_t *p_rtp;
+
+    if( p_box->i_size < MP4_BOX_HEADERSIZE(p_box ) + 8 )
+    {
+        /* container is empty, 8 stand for the first header in this box */
+        return( 1 );
+    }
+   
+    if( !MP4_SeekStream( p_stream,p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) ) )
+    {
+        return( 0 );
+    }
+      
+    do
+    {
+        p_ref = malloc( sizeof( MP4_Box_t ) );
+        if( MP4_ReadBoxCommon( p_stream, p_ref ) )
+        {
+            switch( p_ref->i_type )
+            {
+                case( FOURCC_rtp ):
+                default:
+                    msg_Warn( p_stream->p_input, "Unknown moviehintinformation %c%c%c%c (uncompletetly loaded)",
+                                       ( p_ref->i_type >> 24 )&0xff,
+                                       ( p_ref->i_type >> 16 )&0xff,
+                                       ( p_ref->i_type >>  8 )&0xff,
+                                       ( p_ref->i_type )&0xff );
+                    break;
+            }
+            /* chain this box with the father and the other at same level */
+            if( !p_box->p_first )
+            {
+                p_box->p_first = p_ref;
+                p_box->p_last = p_ref;
+            }
+            else
+            {
+                p_box->p_last->p_next = p_ref;
+                p_box->p_last = p_ref;
+            }
+            p_ref->p_father = p_box;
+        }
+        else
+        {
+            /* free memory */
+            free( p_ref );
+        }
+        
+        
+    }while( MP4_NextBox( p_stream, p_ref ) == 1 );
+    
+    
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"hnti\" " );
+
+#endif
+    return( 1 );
+}
+
+int MP4_ReadBox_dcom( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_dcom_t );
+    
+    MP4_GET4BYTES( p_box->data.p_dcom->i_algorithm );
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, 
+             "Read Box: \"dcom\" compression algorithm : %c%c%c%c",
+                      ( p_box->data.p_dcom->i_algorithm >> 24 )&0xff,
+                      ( p_box->data.p_dcom->i_algorithm >> 16 )&0xff,
+                      ( p_box->data.p_dcom->i_algorithm >>  8 )&0xff,
+                      ( p_box->data.p_dcom->i_algorithm  )&0xff );
+#endif 
+    
+    MP4_READBOX_EXIT( 1 );
+}
+
+int MP4_ReadBox_cmvd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_cmvd_t );
+
+    
+    MP4_GET4BYTES( p_box->data.p_cmvd->i_uncompressed_size );
+
+    p_box->data.p_cmvd->i_compressed_size = i_read;
+    
+    if( !( p_box->data.p_cmvd->p_data = malloc( i_read ) ) )
+    {
+        msg_Dbg( p_stream->p_input, "Read Box: \"cmvd\" not enough memory to load data" );
+        return( 1 );
+    }
+    
+    /* now copy compressed data */
+    memcpy( p_box->data.p_cmvd->p_data,
+            p_peek,
+            i_read);
+    
+    p_box->data.p_cmvd->b_compressed = 1;
+     
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, "Read Box: \"cmvd\" compressed data size %d",
+                      p_box->data.p_cmvd->i_compressed_size );
+#endif 
+    
+    MP4_READBOX_EXIT( 1 );
+}   
+
+int MP4_ReadBox_cmov( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_Stream_t *p_stream_memory;
+    MP4_Box_t *p_umov;
+    
+    MP4_Box_t *p_dcom;
+    MP4_Box_t *p_cmvd;
+    z_stream  z_data;
+    u8 *p_data;
+    
+    int i_result;
+
+    if( !( p_box->data.p_cmov = malloc( sizeof( MP4_Box_data_cmov_t ) ) ) )
+    {
+        msg_Err( p_stream->p_input, "out of memory" );
+        return( 0 );
+    }
+    memset( p_box->data.p_cmov, 0, sizeof( MP4_Box_data_cmov_t ) );
+    
+    if( !( p_box->p_father )||
+        ( p_box->p_father->i_type != FOURCC_moov ) )
+    {
+        msg_Warn( p_stream->p_input, "Read box: \"cmov\" box alone" );
+        return( 1 );
+    }
+
+    if( !(i_result = MP4_ReadBoxContainer( p_stream, p_box ) ) )
+    {
+        return( 0 );
+    }
+    
+    if( !( p_dcom = MP4_FindBox( p_box, FOURCC_dcom ) )||
+        !( p_cmvd = MP4_FindBox( p_box, FOURCC_cmvd ) )||
+        !( p_cmvd->data.p_cmvd->p_data ) )
+    {
+        msg_Warn( p_stream->p_input, "Read Box: \"cmov\" incomplete" );
+        return( 1 );
+    }
+
+    if( p_dcom->data.p_dcom->i_algorithm != FOURCC_zlib )
+    {
+        msg_Dbg( p_stream->p_input, "Read Box: \"cmov\" compression algorithm : %c%c%c%c not supported",
+                    ( p_dcom->data.p_dcom->i_algorithm >> 24 )&0xff,
+                    ( p_dcom->data.p_dcom->i_algorithm >> 16 )&0xff,
+                    ( p_dcom->data.p_dcom->i_algorithm >>  8 )&0xff,
+                    ( p_dcom->data.p_dcom->i_algorithm  )&0xff );
+        return( 1 );
+    }
+    
+    /* decompress data */
+    /* allocate a new buffer */
+    if( !( p_data = malloc( p_cmvd->data.p_cmvd->i_uncompressed_size ) ) )
+    {
+        msg_Err( p_stream->p_input, 
+                 "Read Box: \"cmov\" not enough memory to uncompress data" );
+        return( 1 );
+    }
+    /* init default structures */
+    z_data.next_in   = p_cmvd->data.p_cmvd->p_data;
+    z_data.avail_in  = p_cmvd->data.p_cmvd->i_compressed_size;
+    z_data.next_out  = p_data;
+    z_data.avail_out = p_cmvd->data.p_cmvd->i_uncompressed_size;
+    z_data.zalloc    = (alloc_func)Z_NULL;
+    z_data.zfree     = (free_func)Z_NULL;
+    z_data.opaque    = (voidpf)Z_NULL;
+
+    /* init zlib */
+    if( ( i_result = inflateInit( &z_data ) ) != Z_OK )
+    {
+        msg_Err( p_stream->p_input, 
+                 "Read Box: \"cmov\" error while uncompressing data" );
+        free( p_data );
+        return( 1 );
+    }
+
+    /* uncompress */
+    i_result = inflate( &z_data, Z_NO_FLUSH );
+    if( ( i_result != Z_OK )&&( i_result != Z_STREAM_END ) )
+    {
+        msg_Err( p_stream->p_input, 
+                 "Read Box: \"cmov\" error while uncompressing data" );
+        free( p_data );
+        return( 1 );
+    }
+
+    if( p_cmvd->data.p_cmvd->i_uncompressed_size != z_data.total_out )
+    {
+        msg_Warn( p_stream->p_input, 
+                  "Read Box: \"cmov\" uncompressing data size mismatch" );
+    }
+    p_cmvd->data.p_cmvd->i_uncompressed_size = z_data.total_out;
+
+    /* close zlib */ 
+    i_result = inflateEnd( &z_data );
+    if( i_result != Z_OK )
+    {
+        msg_Warn( p_stream->p_input, 
+           "Read Box: \"cmov\" error while uncompressing data (ignored)" );
+    }
+
+
+    free( p_cmvd->data.p_cmvd->p_data );
+    p_cmvd->data.p_cmvd->p_data = p_data;
+    p_cmvd->data.p_cmvd->b_compressed = 0;
+
+    msg_Dbg( p_stream->p_input, 
+             "Read Box: \"cmov\" box succesfully uncompressed" );
+
+    /* now create a memory stream */
+    p_stream_memory = MP4_MemoryStream( p_stream->p_input, 
+                                        p_cmvd->data.p_cmvd->i_uncompressed_size,
+                                        p_cmvd->data.p_cmvd->p_data );
+
+    /* and read uncompressd moov */
+    p_umov = malloc( sizeof( MP4_Box_t ) );
+    
+    i_result = MP4_ReadBox( p_stream_memory, p_umov, NULL );
+  
+    p_box->data.p_cmov->p_moov = p_umov;
+    free( p_stream_memory );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream->p_input, 
+             "Read Box: \"cmov\" compressed movie header completed" );
+#endif
+    return( i_result );
+}
+
+
+/**** ------------------------------------------------------------------- ****/
+/****                   "Higher level" Functions                          ****/
+/**** ------------------------------------------------------------------- ****/
+
+static struct 
+{
+    u32 i_type;
+    int  (*MP4_ReadBox_function )( MP4_Stream_t *p_stream, MP4_Box_t *p_box ); 
+    void (*MP4_FreeBox_function )( input_thread_t *p_input, MP4_Box_t *p_box );
+} MP4_Box_Function [] =
+{
+    /* Containers */
+    { FOURCC_moov,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
+    { FOURCC_trak,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
+    { FOURCC_mdia,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
+    { FOURCC_moof,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
+    { FOURCC_minf,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
+    { FOURCC_stbl,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
+    { FOURCC_dinf,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
+    { FOURCC_edts,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
+    { FOURCC_udta,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
+    { FOURCC_nmhd,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
+
+    /* specific sbox */
+    { FOURCC_ftyp,  MP4_ReadBox_ftyp,       NULL },
+    { FOURCC_cmov,  MP4_ReadBox_cmov,       NULL },
+    { FOURCC_mvhd,  MP4_ReadBox_mvhd,       NULL },
+    { FOURCC_tkhd,  MP4_ReadBox_tkhd,       NULL },
+    { FOURCC_tref,  MP4_ReadBox_tref,       NULL },
+    { FOURCC_mdhd,  MP4_ReadBox_mdhd,       NULL },
+    { FOURCC_hdlr,  MP4_ReadBox_hdlr,       NULL },
+    { FOURCC_vmhd,  MP4_ReadBox_vmhd,       NULL },
+    { FOURCC_smhd,  MP4_ReadBox_smhd,       NULL },
+    { FOURCC_hmhd,  MP4_ReadBox_hmhd,       NULL },
+    { FOURCC_url,   MP4_ReadBox_url,        NULL },
+    { FOURCC_urn,   MP4_ReadBox_urn,        NULL },
+    { FOURCC_dref,  MP4_ReadBox_dref,       NULL },
+    { FOURCC_stts,  MP4_ReadBox_stts,       NULL },
+    { FOURCC_ctts,  MP4_ReadBox_ctts,       NULL },
+    { FOURCC_stsd,  MP4_ReadBox_stsd,       NULL },
+    { FOURCC_stsz,  MP4_ReadBox_stsz,       NULL },
+    { FOURCC_stsc,  MP4_ReadBox_stsc,       NULL },
+    { FOURCC_stco,  MP4_ReadBox_stco_co64,  NULL },
+    { FOURCC_co64,  MP4_ReadBox_stco_co64,  NULL },
+    { FOURCC_stss,  MP4_ReadBox_stss,       NULL },
+    { FOURCC_stsh,  MP4_ReadBox_stsh,       NULL },
+    { FOURCC_stdp,  MP4_ReadBox_stdp,       NULL },
+    { FOURCC_padb,  MP4_ReadBox_padb,       NULL },
+    { FOURCC_elst,  MP4_ReadBox_elst,       NULL },
+    { FOURCC_cprt,  MP4_ReadBox_cprt,       NULL },
+    { FOURCC_hnti,  MP4_ReadBox_hnti,       NULL },
+    { FOURCC_esds,  MP4_ReadBox_esds,       NULL },
+    { FOURCC_dcom,  MP4_ReadBox_dcom,       NULL },
+    { FOURCC_cmvd,  MP4_ReadBox_cmvd,       NULL },
+
+    /* Nothing to do with this box */
+    { FOURCC_mdat,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
+    { FOURCC_skip,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
+    { FOURCC_free,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
+    { FOURCC_wide,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
+    
+    /* Last entry */
+    { 0,            NULL,                   NULL }
+};
+
+
+
+/*****************************************************************************
+ * MP4_ReadBox : parse the actual box and the children 
+ *  XXX : Do not go to the next box
+ *****************************************************************************/
+int MP4_ReadBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box, MP4_Box_t *p_father )
+{
+    int i_result;
+    int i_index;
+    
+    if( !MP4_ReadBoxCommon( p_stream, p_box ) )
+    {
+        msg_Err( p_stream->p_input, "Cannot read one box" );
+        return( 0 );
+    }
+    if( !p_box->i_size )
+    {
+        msg_Dbg( p_stream->p_input, "Found an empty box (null size)" );
+        return( 0 );
+    }
+    p_box->p_father = p_father;
+
+    /* Now search function to call */
+    for( i_index = 0; ; i_index++ )
+    {
+        if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
+            ( MP4_Box_Function[i_index].i_type == 0 ) )
+        {
+            break;
+        }
+    }
+    if( MP4_Box_Function[i_index].MP4_ReadBox_function == NULL )
+    {
+        msg_Warn( p_stream->p_input,
+                  "Unknown box type %c%c%c%c (uncompletetly loaded)",
+                  (p_box->i_type>>24)&0xff, 
+                  (p_box->i_type>>16)&0xff,
+                  (p_box->i_type>>8)&0xff,
+                  (p_box->i_type)&0xff );
+        return( 1 );
+    }
+    else
+    {
+        i_result = 
+           (MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box );
+    }
+
+    if( !MP4_GotoBox( p_stream, p_box ) )
+    {
+        return( 0 );
+    }
+    return( i_result );
+}
+
+/*****************************************************************************
+ * MP4_FreeBox : free memory after read with MP4_ReadBox and all 
+ * the children
+ *****************************************************************************/
+void MP4_FreeBox( input_thread_t *p_input, MP4_Box_t *p_box )
+{
+#define FREE( p ) \
+    if( p ) \
+    { \
+        free( p ); \
+    }
+    int i_index;
+
+    MP4_Box_t *p_child;
+    MP4_Box_t *p_next;
+
+    if( !p_box )
+    {
+        return; /* hehe */
+    }
+    p_child = p_box->p_first;
+    while( p_child )
+    {
+        p_next = p_child->p_next;
+        MP4_FreeBox( p_input, p_child );
+        /* MP4_FreeBoxChildren have free all data expect p_child itself */
+        free( p_child );
+        p_child = p_next; 
+    }
+
+#if 0
+    /* Now search function to call */
+    if( p_box->data.p_data )
+    {
+        for( i_index = 0; ; i_index++ )
+        {
+            if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
+                ( MP4_Box_Function[i_index].i_type == 0 ) )
+            {
+                break;
+            }
+        }
+        if( MP4_Box_Function[i_index].MP4_FreeBox_function == NULL )
+        {
+            msg_Warn( p_input, 
+                      "cannot free box %c%c%c%c, type unknown",
+                      (p_box->i_type >> 24)&0xff,
+                      (p_box->i_type >> 16)&0xff, 
+                      (p_box->i_type >>  8)&0xff, 
+                      (p_box->i_type )&0xff );
+        }
+        else
+        {
+            MP4_Box_Function[i_index].MP4_FreeBox_function( p_input, p_box );
+        }
+
+    }
+
+    p_box->data.p_data = NULL;
+    p_box->p_first = NULL;
+    p_box->p_last = NULL;
+#endif   
+    
+    if( p_box->data.p_data )
+    {
+        switch( p_box->i_type )
+        {
+            case( FOURCC_ftyp):
+                FREE(p_box->data.p_ftyp->i_compatible_brands );
+                break;
+            case( FOURCC_hdlr ):
+                FREE( p_box->data.p_hdlr->psz_name );
+                break;
+            case( FOURCC_url ):
+                FREE( p_box->data.p_url->psz_location );
+                break;
+            case( FOURCC_urn ):
+                FREE( p_box->data.p_urn->psz_name );
+                FREE( p_box->data.p_urn->psz_location );
+                break;
+            case( FOURCC_stts ):
+                FREE( p_box->data.p_stts->i_sample_count );
+                FREE( p_box->data.p_stts->i_sample_delta );
+                break;
+            case( FOURCC_ctts ):
+                FREE( p_box->data.p_ctts->i_sample_count );
+                FREE( p_box->data.p_ctts->i_sample_offset );
+                break;
+            case( FOURCC_stsz ):
+                FREE( p_box->data.p_stsz->i_entry_size );
+                break;
+            case( FOURCC_stz2 ):
+                FREE( p_box->data.p_stz2->i_entry_size );
+                break;
+            case( FOURCC_stsc ):
+                FREE( p_box->data.p_stsc->i_first_chunk );
+                FREE( p_box->data.p_stsc->i_samples_per_chunk );
+                FREE( p_box->data.p_stsc->i_sample_description_index );
+                break;
+            case( FOURCC_stco ):
+            case( FOURCC_co64 ):
+                FREE( p_box->data.p_co64->i_chunk_offset );
+                break;
+            case( FOURCC_stss ):
+                FREE( p_box->data.p_stss->i_sample_number );
+                break;
+            case( FOURCC_stsh ):
+                FREE( p_box->data.p_stsh->i_shadowed_sample_number );
+                FREE( p_box->data.p_stsh->i_sync_sample_number );
+                break;
+            case( FOURCC_stdp ):
+                FREE( p_box->data.p_stdp->i_priority );
+                break;
+            case( FOURCC_padb ):
+                FREE( p_box->data.p_padb->i_reserved1 );
+                FREE( p_box->data.p_padb->i_pad2 );
+                FREE( p_box->data.p_padb->i_reserved2 );
+                FREE( p_box->data.p_padb->i_pad1 );
+                break;
+            case( FOURCC_elst ):
+                FREE( p_box->data.p_elst->i_segment_duration );
+                FREE( p_box->data.p_elst->i_media_time );
+                FREE( p_box->data.p_elst->i_media_rate_integer );
+                FREE( p_box->data.p_elst->i_media_rate_fraction );
+                break;
+            case( FOURCC_cprt ):
+                FREE( p_box->data.p_cprt->psz_notice );
+                break;
+            case( FOURCC_cmvd ):
+                FREE( p_box->data.p_cmvd->p_data );
+                break;
+            case( FOURCC_moov ): /* theses are containers for others boxes */
+            case( FOURCC_trak ):
+            case( FOURCC_mdia ):
+            case( FOURCC_moof ):
+            case( FOURCC_minf ):
+            case( FOURCC_stbl ):
+            case( FOURCC_dinf ):
+            case( FOURCC_edts ):
+            case( FOURCC_udta ):
+            case( FOURCC_nmhd ):
+            case( FOURCC_mvhd ): /* nothing to free */
+            case( FOURCC_tkhd ):
+            case( FOURCC_mdhd ):
+            case( FOURCC_vmhd ):
+            case( FOURCC_smhd ):
+            case( FOURCC_hmhd ):
+            case( FOURCC_dref ):
+            case( FOURCC_soun ):
+            case( FOURCC_vide ):
+            case( FOURCC_SVQ1 ):
+            case( FOURCC_mp4s ):
+            case( FOURCC_mp4a ):
+            case( FOURCC_mp4v ):
+            case( FOURCC_dcom ):
+            case( FOURCC_stsd ):
+            case( FOURCC_cmov ):
+            case( FOURCC_DIVX ):
+            case( FOURCC_3IV1 ):
+            case( FOURCC_h263 ):
+                break;
+            default:
+                msg_Warn( p_input, "cannot free box %c%c%c%c, type unknown",
+                          (p_box->i_type >> 24)&0xff,
+                          (p_box->i_type >> 16)&0xff, 
+                          (p_box->i_type >>  8)&0xff, 
+                          (p_box->i_type )&0xff );
+                break;
+        }
+        free( p_box->data.p_data ); 
+    }
+    p_box->data.p_data = NULL;
+    p_box->p_first = NULL;
+    p_box->p_last = NULL;
+#undef FREE
+}
+
+/*****************************************************************************
+ * MP4_ReadRoot : Parse the entire file, and create all boxes in memory
+ *****************************************************************************
+ *  The first box is a virtual box "root" and is the father for all first 
+ *  level boxes for the file, a sort of virtual contener
+ *****************************************************************************/
+int MP4_ReadBoxRoot( input_thread_t *p_input, MP4_Box_t *p_root )
+{
+    
+    MP4_Stream_t *p_stream;
+    int i_result;
+    
+    MP4_SeekAbsolute( p_input, 0 );     /* Go to the begining */
+    p_root->i_pos = 0;
+    p_root->i_type = MP4_FOURCC( 'r', 'o', 'o', 't' );
+    p_root->i_shortsize = 1;
+    p_root->i_size = p_input->stream.p_selected_area->i_size;
+    CreateUUID( &p_root->i_uuid, p_root->i_type );
+
+    p_root->data.p_data = NULL;
+    p_root->p_father = NULL;
+    p_root->p_first  = NULL;
+    p_root->p_last  = NULL;
+    p_root->p_next   = NULL;
+    
+    p_stream = MP4_InputStream( p_input );
+    
+    i_result = MP4_ReadBoxContainerRaw( p_stream, p_root );
+
+    free( p_stream );
+    
+    if( i_result )
+    {
+        MP4_Box_t *p_child; 
+        MP4_Box_t *p_moov;
+        MP4_Box_t *p_cmov;
+
+        /* check if there is a cmov, if so replace 
+          compressed moov by  uncompressed one */
+        if( ( p_moov = MP4_FindBox( p_root, FOURCC_moov ) )&&
+            ( p_cmov = MP4_FindBox( p_moov, FOURCC_cmov ) ) )
+        {
+            /* rename the compressed moov as a box to skip */
+            p_moov->i_type = FOURCC_skip;
+                
+            /* get uncompressed p_moov */
+            p_moov = p_cmov->data.p_cmov->p_moov;
+            p_cmov->data.p_cmov->p_moov = NULL;
+
+            /* make p_root father of this new moov */
+            p_moov->p_father = p_root;
+
+            /* insert this new moov box as first child of p_root */
+            p_moov->p_next = p_child = p_root->p_first;
+            p_root->p_first = p_moov;
+        }
+    }
+    return( i_result );
+}
+
+
+static void __MP4_DumpBoxStructure( input_thread_t *p_input,
+                                    MP4_Box_t *p_box, int i_level )
+{
+    MP4_Box_t *p_child;
+
+    if( !i_level )
+    {
+        msg_Dbg( p_input, "Dumping root Box \"%c%c%c%c \"",
+                          (p_box->i_type>>24 ) &0xff,
+                          (p_box->i_type>>16 ) &0xff,
+                          (p_box->i_type>> 8 ) &0xff,
+                          (p_box->i_type ) &0xff );
+    }
+    else
+    {
+        char str[512];
+        int i;
+        memset( str, (u8)' ', 512 );
+        for( i = 0; i < i_level; i++ )
+        {
+            str[i*5] = '|';
+        }
+        sprintf( str + i_level * 5, "+ %c%c%c%c size %d",
+                      (p_box->i_type>>24 ) &0xff,
+                      (p_box->i_type>>16 ) &0xff,
+                      (p_box->i_type>> 8 ) &0xff,
+                      (p_box->i_type ) &0xff,
+                      (u32)p_box->i_size );
+        
+        msg_Dbg( p_input, "%s", str );
+    }
+    p_child = p_box->p_first;
+    while( p_child )
+    {
+        __MP4_DumpBoxStructure( p_input, p_child, i_level + 1 );
+        p_child = p_child->p_next;
+    }
+    
+}
+
+void MP4_DumpBoxStructure( input_thread_t *p_input, MP4_Box_t *p_box )
+{
+    __MP4_DumpBoxStructure( p_input, p_box, 0 );
+}
+
+
+/*****************************************************************************
+ * MP4_CountBox: given a box, count how many child have the requested type 
+ * FIXME : support GUUID 
+ *****************************************************************************/
+int MP4_CountBox( MP4_Box_t *p_box, u32 i_type )
+{
+    int i_count;
+    MP4_Box_t *p_child;
+    
+    if( !p_box )
+    {
+        return( 0 );
+    }
+
+    i_count = 0;
+    p_child = p_box->p_first;
+    while( p_child )
+    {
+        if( p_child->i_type == i_type )
+        {   
+            i_count++;
+        }
+        p_child = p_child->p_next;
+    }
+    
+    return( i_count );
+}
+
+
+/*****************************************************************************
+ * MP4_FindBox:  find first box with i_type child of p_box
+ *      return NULL if not found
+ *****************************************************************************/
+
+MP4_Box_t *MP4_FindBox( MP4_Box_t *p_box, u32 i_type )
+{
+    MP4_Box_t *p_child;
+    
+    if( !p_box )
+    {
+        return( NULL );
+    }
+
+    p_child = p_box->p_first;
+    while( p_child )
+    {
+        if( p_child->i_type == i_type )
+        {   
+            return( p_child );
+        }
+        p_child = p_child->p_next;
+    }
+    
+    return( NULL );
+}
+
+
+/*****************************************************************************
+ * MP4_FindNextBox:  find next box with thesame type and at the same level 
+ *                  than p_box
+ *****************************************************************************/
+MP4_Box_t *MP4_FindNextBox( MP4_Box_t *p_box )
+{
+    MP4_Box_t *p_next;
+    
+    if( !p_box )
+    {
+        return( NULL );
+    }
+
+    p_next = p_box->p_next;
+    while( p_next )
+    {
+        if( p_next->i_type == p_box->i_type )
+        {
+            return( p_next );
+        }
+        p_next = p_next->p_next;
+    }
+    return( NULL );
+}
+
+/*****************************************************************************
+ * MP4_FindNbBox:  find the box i_number
+ *****************************************************************************/
+MP4_Box_t *MP4_FindNbBox( MP4_Box_t *p_box, u32 i_number )
+{
+    MP4_Box_t *p_child = p_box->p_first;
+    
+    if( !p_child )
+    {
+        return( NULL );
+    }
+
+    while( i_number )
+    {
+        if( !( p_child = p_child->p_next ) )
+        {
+            return( NULL );
+        }
+        i_number--;
+    }
+    return( p_child );
+}
+
+
+
+
diff --git a/plugins/mp4/libmp4.h b/plugins/mp4/libmp4.h
new file mode 100644 (file)
index 0000000..19ddd80
--- /dev/null
@@ -0,0 +1,851 @@
+/*****************************************************************************
+ * libmp4.h : LibMP4 library for mp4 module for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: libmp4.h,v 1.1 2002/07/17 21:37:27 fenrir Exp $
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+/* XXX It's not the same than VLC_FOURCC */
+#define MP4_FOURCC( a, b, c, d ) \
+    ( ((u32)d) | ( ((u32)c) << 8 ) | ( ((u32)b) << 16 ) | ( ((u32)a) << 24 ) )
+        
+
+#define FOURCC_uuid MP4_FOURCC( 'u', 'u', 'i', 'd' )
+
+#define FOURCC_ftyp MP4_FOURCC( 'f', 't', 'y', 'p' )
+#define FOURCC_moov MP4_FOURCC( 'm', 'o', 'o', 'v' )
+#define FOURCC_cmov MP4_FOURCC( 'c', 'm', 'o', 'v' )
+#define FOURCC_dcom MP4_FOURCC( 'd', 'c', 'o', 'm' )
+#define FOURCC_cmvd MP4_FOURCC( 'c', 'm', 'v', 'd' )
+    
+#define FOURCC_moof MP4_FOURCC( 'm', 'o', 'o', 'f' )
+#define FOURCC_mdat MP4_FOURCC( 'm', 'd', 'a', 't' )
+#define FOURCC_skip MP4_FOURCC( 's', 'k', 'i', 'p' )
+#define FOURCC_free MP4_FOURCC( 'f', 'r', 'e', 'e' )
+#define FOURCC_udta MP4_FOURCC( 'u', 'd', 't', 'a' )
+#define FOURCC_wide MP4_FOURCC( 'w', 'i', 'd', 'e' )
+
+#define FOURCC_trak MP4_FOURCC( 't', 'r', 'a', 'k' )
+#define FOURCC_mvhd MP4_FOURCC( 'm', 'v', 'h', 'd' )
+#define FOURCC_tkhd MP4_FOURCC( 't', 'k', 'h', 'd' )
+#define FOURCC_tref MP4_FOURCC( 't', 'r', 'e', 'f' )
+#define FOURCC_mdia MP4_FOURCC( 'm', 'd', 'i', 'a' )
+#define FOURCC_mdhd MP4_FOURCC( 'm', 'd', 'h', 'd' )
+#define FOURCC_hdlr MP4_FOURCC( 'h', 'd', 'l', 'r' )
+#define FOURCC_minf MP4_FOURCC( 'm', 'i', 'n', 'f' )
+#define FOURCC_vmhd MP4_FOURCC( 'v', 'm', 'h', 'd' )
+#define FOURCC_smhd MP4_FOURCC( 's', 'm', 'h', 'd' )
+#define FOURCC_hmhd MP4_FOURCC( 'h', 'm', 'h', 'd' )
+#define FOURCC_dinf MP4_FOURCC( 'd', 'i', 'n', 'f' )
+#define FOURCC_url  MP4_FOURCC( 'u', 'r', 'l', ' ' )
+#define FOURCC_urn  MP4_FOURCC( 'u', 'r', 'n', ' ' )
+#define FOURCC_dref MP4_FOURCC( 'd', 'r', 'e', 'f' )
+#define FOURCC_stbl MP4_FOURCC( 's', 't', 'b', 'l' )
+#define FOURCC_stts MP4_FOURCC( 's', 't', 't', 's' )
+#define FOURCC_ctts MP4_FOURCC( 'c', 't', 't', 's' )
+#define FOURCC_stsd MP4_FOURCC( 's', 't', 's', 'd' )
+#define FOURCC_stsz MP4_FOURCC( 's', 't', 's', 'z' )
+#define FOURCC_stz2 MP4_FOURCC( 's', 't', 'z', '2' )
+#define FOURCC_stsc MP4_FOURCC( 's', 't', 's', 'c' )
+#define FOURCC_stco MP4_FOURCC( 's', 't', 'c', 'o' )
+#define FOURCC_co64 MP4_FOURCC( 'c', 'o', '6', '4' )
+#define FOURCC_stss MP4_FOURCC( 's', 't', 's', 's' )
+#define FOURCC_stsh MP4_FOURCC( 's', 't', 's', 'h' )
+#define FOURCC_stdp MP4_FOURCC( 's', 't', 'd', 'p' )
+#define FOURCC_padb MP4_FOURCC( 'p', 'a', 'd', 'b' )
+#define FOURCC_edts MP4_FOURCC( 'e', 'd', 't', 's' )
+#define FOURCC_elst MP4_FOURCC( 'e', 'l', 's', 't' )
+#define FOURCC_udta MP4_FOURCC( 'u', 'd', 't', 'a' )
+#define FOURCC_mvex MP4_FOURCC( 'm', 'v', 'e', 'x' )
+#define FOURCC_trex MP4_FOURCC( 't', 'r', 'e', 'x' )
+#define FOURCC_mfhd MP4_FOURCC( 'm', 'f', 'h', 'd' )
+#define FOURCC_traf MP4_FOURCC( 't', 'r', 'a', 'f' )
+#define FOURCC_tfhd MP4_FOURCC( 't', 'f', 'h', 'd' )
+#define FOURCC_trun MP4_FOURCC( 't', 'r', 'u', 'n' )
+#define FOURCC_cprt MP4_FOURCC( 'c', 'p', 'r', 't' )
+#define FOURCC_iods MP4_FOURCC( 'i', 'o', 'd', 's' )
+
+#define FOURCC_nmhd MP4_FOURCC( 'n', 'm', 'h', 'd' )
+#define FOURCC_mp4v MP4_FOURCC( 'm', 'p', '4', 'v' )
+#define FOURCC_mp4a MP4_FOURCC( 'm', 'p', '4', 'a' )
+#define FOURCC_mp4s MP4_FOURCC( 'm', 'p', '4', 's' )
+#define FOURCC_vide MP4_FOURCC( 'v', 'i', 'd', 'e' )
+#define FOURCC_soun MP4_FOURCC( 's', 'o', 'u', 'n' )
+#define FOURCC_hint MP4_FOURCC( 'h', 'i', 'n', 't' )
+    
+#define FOURCC_dpnd MP4_FOURCC( 'd', 'p', 'n', 'd' )
+#define FOURCC_ipir MP4_FOURCC( 'i', 'p', 'i', 'r' )
+#define FOURCC_mpod MP4_FOURCC( 'm', 'p', 'o', 'd' )
+#define FOURCC_hnti MP4_FOURCC( 'h', 'n', 't', 'i' )
+#define FOURCC_rtp  MP4_FOURCC( 'r', 't', 'p', ' ' )
+
+#define FOURCC_isom MP4_FOURCC( 'i', 's', 'o', 'm' )
+#define FOURCC_esds MP4_FOURCC( 'e', 's', 'd', 's' )
+
+#define FOURCC_zlib MP4_FOURCC( 'z', 'l', 'i', 'b' )
+#define FOURCC_SVQ1 MP4_FOURCC( 'S', 'V', 'Q', '1' )
+#define FOURCC__mp3 MP4_FOURCC( '.', 'm', 'p', '3' )
+#define FOURCC_3IV1 MP4_FOURCC( '3', 'I', 'V', '1' )
+#define FOURCC_h263 MP4_FOURCC( 'h', '2', '6', '3' )
+#define FOURCC_DIVX MP4_FOURCC( 'D', 'I', 'V', 'X' )
+
+    
+/*
+#define FOURCC_  MP4_FOURCC( '', '', '', '' )
+*/    
+/* Do you want some debug information on all read boxes ? */
+#define MP4_VERBOSE  1
+
+/* memory stream and file stream object */
+
+typedef struct MP4_Stream_s
+{
+    int b_memory;   /* do we uses a memory buffer */
+
+    input_thread_t *p_input;
+    
+    off_t i_start; /* in the buffer position for memory stream */
+    off_t i_stop;
+    u8  *p_buffer;
+
+} MP4_Stream_t;
+    
+struct MP4_Box_s;
+
+
+/* uuid Universal Unique IDentifiers */
+typedef struct UUID_s 
+{
+    u8 b[16];
+} UUID_t;
+
+/* specific structure for all boxes */
+
+typedef struct MP4_Box_data_ftyp_s
+{
+    u32 i_major_brand;
+    u32 i_minor_version;
+
+    u32 i_compatible_brands_count;
+    u32 *i_compatible_brands;
+
+} MP4_Box_data_ftyp_t;
+
+typedef struct MP4_Box_data_mvhd_s
+{
+    u8  i_version;
+    u32 i_flags;
+        
+    u64 i_creation_time;
+    u64 i_modification_time;
+    u32 i_timescale;
+    u64 i_duration;
+
+    s32 i_rate;
+    s16 i_volume;
+    s16 i_reserved1;
+    u32 i_reserved2[2];
+    s32 i_matrix[9];
+    u32 i_predefined[6];
+    u32 i_next_track_id;
+
+} MP4_Box_data_mvhd_t;
+
+#define MP4_TRACK_ENABLED    0x000001
+#define MP4_TRACK_IN_MOVIE   0x000002
+#define MP4_TRACK_IN_PREVIEW 0x000004
+typedef struct MP4_Box_data_tkhd_s
+{
+    u8  i_version;
+    u32 i_flags;
+        
+    u64 i_creation_time;
+    u64 i_modification_time;
+    u32 i_track_ID;
+    u32 i_reserved;
+    u64 i_duration;
+    
+    u32 i_reserved2[2];
+    s16 i_layer;
+    s16 i_predefined;
+    
+    s16 i_volume;
+    u16 i_reserved3;
+    s32 i_matrix[9];
+    s32 i_width;
+    s32 i_height;
+    
+} MP4_Box_data_tkhd_t;
+
+typedef struct MP4_Box_data_mdhd_s
+{
+    u8  i_version;
+    u32 i_flags;
+        
+    u64 i_creation_time;
+    u64 i_modification_time;
+    u32 i_timescale;
+    u64 i_duration;
+
+    /* one bit for pad */
+    /* unsigned int(5)[3] language difference with 0x60*/
+    unsigned char i_language[3]; 
+    u16 i_predefined;
+
+} MP4_Box_data_mdhd_t;
+
+typedef struct MP4_Box_data_hdlr_s
+{
+    u8  i_version;
+    u32 i_flags;
+    
+    u32 i_predefined;
+    u32 i_handler_type; /* "vide" "soun" "hint" "odsm" 
+                           "crsm" "sdsm" "m7sm" "ocsm" 
+                           "ipsm" "mjsm" */
+    
+    unsigned char *psz_name; /* in UTF-8 */
+
+} MP4_Box_data_hdlr_t;
+
+typedef struct MP4_Box_data_vmhd_s
+{
+    u8  i_version;
+    u32 i_flags;
+    
+    s16 i_graphics_mode;
+    s16 i_opcolor[3];    
+
+} MP4_Box_data_vmhd_t;
+
+typedef struct MP4_Box_data_smhd_s
+{
+    u8  i_version;
+    u32 i_flags;
+    
+    s16 i_balance;
+    s16 i_reserved;
+
+} MP4_Box_data_smhd_t;
+
+typedef struct MP4_Box_data_hmhd_s
+{
+    u8  i_version;
+    u32 i_flags;
+       
+    u16 i_max_PDU_size;
+    u16 i_avg_PDU_size;
+    u32 i_max_bitrate;
+    u32 i_avg_bitrate;
+    u32 i_reserved;
+
+} MP4_Box_data_hmhd_t;
+
+typedef struct MP4_Box_data_url_s
+{
+    u8  i_version;
+    u32 i_flags;
+    
+    unsigned char *psz_location;
+    
+} MP4_Box_data_url_t;
+
+typedef struct MP4_Box_data_urn_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    unsigned char *psz_name;
+    unsigned char *psz_location;
+    
+} MP4_Box_data_urn_t;
+
+typedef struct MP4_Box_data_dref_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    u32 i_entry_count;
+/* XXX it's also a container with i_entry_count entry */
+} MP4_Box_data_dref_t;
+
+typedef struct MP4_Box_data_stts_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    u32 i_entry_count;
+    u32 *i_sample_count; /* these are array */
+    s32 *i_sample_delta;
+
+} MP4_Box_data_stts_t;
+
+typedef struct MP4_Box_data_ctts_s
+{
+    u8  i_version;
+    u32 i_flags;
+    
+    u32 i_entry_count;
+
+    u32 *i_sample_count; /* these are array */
+    s32 *i_sample_offset;
+
+} MP4_Box_data_ctts_t;
+
+
+typedef struct MP4_Box_data_sample_soun_s
+{
+    u8  i_reserved1[6];
+    u16 i_data_reference_index;
+
+    u32 i_reserved2[2];
+    u16 i_channelcount;
+    u16 i_samplesize;
+    u16 i_predefined;
+    u16 i_reserved3;
+    u16 i_sampleratehi; /* timescale of track */
+    u16 i_sampleratelo;
+    
+} MP4_Box_data_sample_soun_t;
+
+typedef struct MP4_Box_data_sample_mp4a_s
+{
+    u8  i_reserved1[6];
+    u16 i_data_reference_index;
+
+    u32 i_reserved2[2];
+    u16 i_channelcount;
+    u16 i_samplesize;
+    u16 i_predefined;
+    u16 i_reserved3;
+    u16 i_sampleratehi; /* timescale of track */
+    u16 i_sampleratelo;
+    
+} MP4_Box_data_sample_mp4a_t;
+
+
+typedef struct MP4_Box_data_sample_vide_s
+{
+    u8  i_reserved1[6];
+    u16 i_data_reference_index;
+
+    u16 i_predefined1;
+    u16 i_reserved2;
+    u32 i_predefined2[3];
+
+    s16 i_width;
+    s16 i_height;
+
+    u32 i_horizresolution;
+    u32 i_vertresolution;
+
+    u32 i_reserved3;
+    u16 i_predefined3;
+    
+    u8  i_compressorname[32];
+    s16 i_depth;
+
+    s16 i_predefined4;
+    
+} MP4_Box_data_sample_vide_t;
+
+typedef struct MP4_Box_data_sample_mp4v_s
+{
+    u8  i_reserved1[6];
+    u16 i_data_reference_index;
+
+    u16 i_predefined1;
+    u16 i_reserved2;
+    u32 i_predefined2[3];
+
+    s16 i_width;
+    s16 i_height;
+
+    u32 i_horizresolution;
+    u32 i_vertresolution;
+
+    u32 i_reserved3;
+    u16 i_predefined3;
+    
+    u8  i_compressorname[32];
+    s16 i_depth;
+
+    s16 i_predefined4;
+    
+} MP4_Box_data_sample_mp4v_t;
+
+
+
+typedef struct MP4_Box_data_sample_hint_s
+{
+    u8  i_reserved1[6];
+    u16 i_data_reference_index;
+
+    u8 *p_data;
+
+} MP4_Box_data_sample_hint_t;
+
+typedef struct MP4_Box_data_moviehintinformation_rtp_s
+{
+    u32 i_description_format;
+    unsigned char *psz_text;
+
+} MP4_Box_data_moviehintinformation_rtp_t;
+
+
+
+typedef struct MP4_Box_data_stsd_s
+{
+    u8  i_version;
+    u32 i_flags;
+    
+    u32 i_entry_count;
+
+    /* it contains SampleEntry handled as if it was Box */
+    
+} MP4_Box_data_stsd_t;
+
+
+typedef struct MP4_Box_data_stsz_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    u32 i_sample_size;
+    u32 i_sample_count;
+   
+    u32 *i_entry_size; /* array , empty if i_sample_size != 0 */
+
+} MP4_Box_data_stsz_t;
+
+typedef struct MP4_Box_data_stz2_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    u32 i_sample_size; /* 24 bits */
+    u8  i_field_size;
+    u32 i_sample_count;
+
+    u32 *i_entry_size; /* array: unsigned int(i_field_size) entry_size */
+
+} MP4_Box_data_stz2_t;
+
+typedef struct MP4_Box_data_stsc_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    u32 i_entry_count;
+
+    u32 *i_first_chunk; /* theses are arrays */
+    u32 *i_samples_per_chunk;
+    u32 *i_sample_description_index;
+    
+} MP4_Box_data_stsc_t;
+
+
+typedef struct MP4_Box_data_co64_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    u32 i_entry_count;
+    
+    u64 *i_chunk_offset;
+
+} MP4_Box_data_co64_t;
+
+
+typedef struct MP4_Box_data_stss_s
+{
+    u8  i_version;
+    u32 i_flags;
+    
+    u32 i_entry_count;
+    
+    u32 *i_sample_number;
+    
+} MP4_Box_data_stss_t;
+
+typedef struct MP4_Box_data_stsh_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    u32 i_entry_count;
+    
+    u32 *i_shadowed_sample_number;
+    u32 *i_sync_sample_number;
+
+} MP4_Box_data_stsh_t;
+
+typedef struct MP4_Box_data_stdp_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    u16 *i_priority;
+
+} MP4_Box_data_stdp_t;
+
+typedef struct MP4_Box_data_padb_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    u32 i_sample_count;
+
+    u16 *i_reserved1;   /* 1bit  */
+    u16 *i_pad2;        /* 3bits */
+    u16 *i_reserved2;   /* 1bit  */
+    u16 *i_pad1;        /* 3bits */
+    
+
+} MP4_Box_data_padb_t;
+
+
+typedef struct MP4_Box_data_elst_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+    u32 i_entry_count;
+
+    u64 *i_segment_duration;
+    s64 *i_media_time;
+    u16 *i_media_rate_integer;
+    u16 *i_media_rate_fraction;
+
+    
+} MP4_Box_data_elst_t;
+
+typedef struct MP4_Box_data_cprt_s
+{
+    u8  i_version;
+    u32 i_flags;
+    /* 1 pad bit */
+    unsigned char i_language[3];
+    
+    unsigned char *psz_notice;
+} MP4_Box_data_cprt_t;
+
+
+/* DecoderConfigDescriptor */
+typedef struct MP4_descriptor_decoder_config_s
+{
+    u8  i_objectTypeIndication;
+    u8  i_streamType;
+    int b_upStream;
+    int i_buffer_sizeDB;
+    int i_max_bitrate;
+    int i_avg_bitrate;
+    
+    int i_decoder_specific_info_len;
+    u8  *p_decoder_specific_info;
+    /* some other stuff */
+    
+} MP4_descriptor_decoder_config_t;
+
+typedef struct MP4_descriptor_SL_config_s
+{
+    
+} MP4_descriptor_SL_config_t;
+
+
+typedef struct MP4_descriptor_ES_s
+{
+    u16 i_ES_ID;
+    int b_stream_dependence;
+    int b_url;
+    int b_OCRstream;
+    int i_stream_priority;
+
+    int i_depend_on_ES_ID; /* if b_stream_dependence set */
+
+    unsigned char *psz_URL;
+
+    u16 i_OCR_ES_ID;       /* if b_OCRstream */
+    MP4_descriptor_decoder_config_t *p_decConfigDescr;
+    
+    MP4_descriptor_SL_config_t *p_slConfigDescr;
+
+    /* some other stuff ... */
+
+} MP4_descriptor_ES_t;
+
+/* ES descriptor */
+typedef struct MP4_Box_data_esds_s
+{
+    u8  i_version;
+    u32 i_flags;
+    
+    MP4_descriptor_ES_t es_descriptor;
+    
+} MP4_Box_data_esds_t;
+
+
+typedef struct MP4_Box_data_dcom_s
+{
+    u32 i_algorithm; /* fourcc */
+    
+} MP4_Box_data_dcom_t;
+
+typedef struct MP4_Box_data_cmvd_s
+{
+    u32 i_uncompressed_size;
+    u32 i_compressed_size;
+
+    int b_compressed; /* Set to 1 if compressed data, 0 if uncompressed */
+    u8 *p_data;
+
+} MP4_Box_data_cmvd_t;
+
+typedef struct MP4_Box_data_cmov_s
+{
+    struct MP4_Box_s *p_moov; /* uncompressed moov */
+    
+} MP4_Box_data_cmov_t;
+
+/*
+typedef struct MP4_Box_data_cmov_s
+{
+    u8  i_version;
+    u32 i_flags;
+
+} MP4_Box_data__t;
+
+*/
+
+typedef union MP4_Box_data_s
+{
+    MP4_Box_data_ftyp_t *p_ftyp;
+    MP4_Box_data_mvhd_t *p_mvhd;
+    MP4_Box_data_tkhd_t *p_tkhd;
+    MP4_Box_data_mdhd_t *p_mdhd;
+    MP4_Box_data_hdlr_t *p_hdlr;
+    MP4_Box_data_vmhd_t *p_vmhd;
+    MP4_Box_data_smhd_t *p_smhd;
+    MP4_Box_data_hmhd_t *p_hmhd;
+    MP4_Box_data_url_t  *p_url;
+    MP4_Box_data_urn_t  *p_urn;
+    MP4_Box_data_dref_t *p_dref;
+    MP4_Box_data_stts_t *p_stts;
+    MP4_Box_data_ctts_t *p_ctts;
+    MP4_Box_data_stsd_t *p_stsd;
+        MP4_Box_data_sample_vide_t *p_sample_vide;
+        MP4_Box_data_sample_vide_t *p_sample_mp4v;
+        MP4_Box_data_sample_soun_t *p_sample_soun;
+        MP4_Box_data_sample_soun_t *p_sample_mp4a;
+        MP4_Box_data_sample_hint_t *p_sample_hint;
+
+        MP4_Box_data_esds_t *p_esds;
+
+    MP4_Box_data_stsz_t *p_stsz;
+    MP4_Box_data_stz2_t *p_stz2;
+    MP4_Box_data_stsc_t *p_stsc;
+    MP4_Box_data_co64_t *p_co64;
+    MP4_Box_data_stss_t *p_stss;
+    MP4_Box_data_stsh_t *p_stsh;
+    MP4_Box_data_stdp_t *p_stdp;
+    MP4_Box_data_padb_t *p_padb;
+    MP4_Box_data_elst_t *p_elst;
+    MP4_Box_data_cprt_t *p_cprt;
+
+    MP4_Box_data_dcom_t *p_dcom;
+    MP4_Box_data_cmvd_t *p_cmvd;
+    MP4_Box_data_cmov_t *p_cmov;
+
+    MP4_Box_data_moviehintinformation_rtp_t p_moviehintinformation_rtp;
+    
+    void                *p_data; /* for unknow type */
+} MP4_Box_data_t;
+
+
+
+/* the most basic structure */
+typedef struct MP4_Box_s
+{
+    off_t   i_pos;      /* absolute position */
+    
+    u32     i_type;
+    u32     i_shortsize;
+
+    UUID_t  i_uuid;  /* Set if i_type == "uuid" */
+    
+    u64     i_size; /* always set so use it */
+
+    MP4_Box_data_t   data;   /* union of pointers on extended data depending on i_type (or i_usertype) */
+
+    struct MP4_Box_s *p_father; /* pointer on the father Box */
+
+    struct MP4_Box_s *p_first;  /* pointer on the first child Box */
+    struct MP4_Box_s *p_last;
+
+    struct MP4_Box_s *p_next;   /* pointer on the next boxes at the same level */
+
+} MP4_Box_t;
+
+/*---------------------------------------------------------------------------*/
+/****----------------------- High level functions ------------------------****/
+/*---------------------------------------------------------------------------*/
+
+/*****************************************************************************
+ * Function for manipulate stream easily
+ *****************************************************************************/
+
+off_t MP4_TellAbsolute( input_thread_t *p_input );
+int   MP4_SeekAbsolute( input_thread_t *p_input, off_t i_pos);
+int   MP4_ReadData( input_thread_t *p_input, u8 *p_buff, int i_size );
+
+/*****************************************************************************
+ * MP4_ReadRoot : Parse the entire file, and create all boxes in memory
+ *****************************************************************************
+ *  The first box is a virtual box "root" and is the father for all first 
+ *  level boxes 
+ *
+ *  RETURN : 1 if succes and 0 if it failed
+ *****************************************************************************/
+int MP4_ReadBoxRoot( input_thread_t *p_input, MP4_Box_t *p_root );
+
+/*****************************************************************************
+ * MP4_FreeBox : free memory allocated after read with MP4_ReadBox
+ *               this, means also children boxes
+ * XXX : all children have to be allocated by a malloc !! and 
+ *         p_box isn't freeing  
+ *****************************************************************************/
+void MP4_FreeBox( input_thread_t *p_input, MP4_Box_t *p_box );
+
+/*****************************************************************************
+ * MP4_DumpBoxStructure: print the structure of the p_box
+ *****************************************************************************/
+void MP4_DumpBoxStructure( input_thread_t *p_input, MP4_Box_t *p_box );
+
+/*****************************************************************************
+ * MP4_CountBox: given a box, count how many child have the requested type 
+ * FIXME : support GUUID 
+ *****************************************************************************/
+int MP4_CountBox( MP4_Box_t *p_box, u32 i_type );
+    
+/*****************************************************************************
+ * MP4_FindBox:  find first box with i_type child of p_box
+ *      return NULL if not found
+ *****************************************************************************/
+MP4_Box_t *MP4_FindBox( MP4_Box_t *p_box, u32 i_type );
+
+/*****************************************************************************
+ * MP4_FindNextBox:  find next box with thesame type and at the same level 
+ *                  than p_box
+ *****************************************************************************/
+MP4_Box_t *MP4_FindNextBox( MP4_Box_t *p_box );
+
+/*****************************************************************************
+ * MP4_FindNbBox:  find the box i_number 
+ *****************************************************************************/
+MP4_Box_t *MP4_FindNbBox( MP4_Box_t *p_box, u32 i_number );
+   
+
+/*---------------------------------------------------------------------------*/
+/****----------------------- Lower level functions -----------------------****/
+/****                                                                     ****/
+/****------Use them only when you known what they really do and need------****/  
+/****                                                                     ****/
+/****---------------------------------------------------------------------****/
+/*---------------------------------------------------------------------------*/
+
+
+/****  ------- First some function to make abstract from input --------  */
+
+/****************************************************************************
+ * MP4_InputStream create an stram with an input
+ *
+ ****************************************************************************/
+MP4_Stream_t *MP4_InputStream( input_thread_t *p_input );
+
+/****************************************************************************
+ * MP4_MemoryStream create a memory stream
+ * if p_buffer == NULL, will allocate a buffer of i_size, else 
+ *     it uses p_buffer XXX you have to unallocate yourself !
+ *
+ ****************************************************************************/
+MP4_Stream_t *MP4_MemoryStream( input_thread_t *p_input,
+                                int i_size, u8 *p_buffer );
+
+/****************************************************************************
+ * MP4_ReadStream read from a MP4_Stream_t
+ *
+ ****************************************************************************/
+int MP4_ReadStream( MP4_Stream_t *p_stream, u8 *p_buff, int i_size );
+
+/****************************************************************************
+ * MP4_PeekStream guess it ;)
+ *
+ ****************************************************************************/
+int MP4_PeekStream( MP4_Stream_t *p_stream, u8 **pp_peek, int i_size );
+    
+/****************************************************************************
+ * MP4_TellStream give absolute position in the stream
+ * XXX for a memory stream give position from begining of the buffer
+ ****************************************************************************/
+off_t MP4_TellStream( MP4_Stream_t *p_stream );
+
+/****************************************************************************
+ * MP4_SeekStream seek in a MP4_Stream_t
+ *
+ ****************************************************************************/
+int MP4_SeekStream( MP4_Stream_t *p_stream, off_t i_pos);
+
+
+
+/*****************************************************************************
+ * MP4_ReadBox : parse the actual box and the children if they exist
+ *  
+ *  RETURN : 1 if succes and 0 if it failed
+ *****************************************************************************/
+int MP4_ReadBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box, MP4_Box_t *p_father );
+
+
+/*****************************************************************************
+ * MP4_ReadBoxCommon : Load only common parameters for all boxes 
+ *****************************************************************************
+ * p_box need to be an already allocated MP4_Box_t, and all data 
+ *  will only be peek not read
+ *
+ * RETURN : 0 if it fail, 1 otherwise
+ *****************************************************************************/
+int MP4_ReadBoxCommon( MP4_Stream_t *p_stream, MP4_Box_t *p_box );
+
+
+/*****************************************************************************
+ * MP4_MP4_GotoBox : Go to this particular box 
+ *****************************************************************************
+ * RETURN : 0 if it fail, 1 otherwise
+ *****************************************************************************/
+int MP4_GotoBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box );
+
+    
+/*****************************************************************************
+ * MP4_MP4_NextBox : Go to the next box wiithin p_box->p_father 
+ *****************************************************************************
+ * if p_box == NULL, go to the next box in witch we are( at the begining ).
+ *****************************************************************************/
+int MP4_NextBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box );
+
+
diff --git a/plugins/mp4/mp4.c b/plugins/mp4/mp4.c
new file mode 100644 (file)
index 0000000..1f378e1
--- /dev/null
@@ -0,0 +1,1052 @@
+/*****************************************************************************
+ * mp4.c : MP4 file input module for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: mp4.c,v 1.1 2002/07/17 21:37:27 fenrir Exp $
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>                                      /* malloc(), free() */
+#include <string.h>                                              /* strdup() */
+#include <errno.h>
+#include <sys/types.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include "libmp4.h"
+#include "mp4.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static void input_getfunctions( function_list_t * );
+static int  MP4Demux         ( input_thread_t * );
+static int  MP4Init          ( input_thread_t * );
+static void MP4End           ( input_thread_t * );
+
+/*****************************************************************************
+ * Build configuration tree.
+ *****************************************************************************/
+MODULE_CONFIG_START
+MODULE_CONFIG_STOP
+
+MODULE_INIT_START
+    SET_DESCRIPTION( "MP4 file input" )
+    ADD_CAPABILITY( DEMUX, 242 )
+MODULE_INIT_STOP
+
+MODULE_ACTIVATE_START
+    input_getfunctions( &p_module->p_functions->demux );
+MODULE_ACTIVATE_STOP
+
+MODULE_DEACTIVATE_START
+MODULE_DEACTIVATE_STOP
+
+/*****************************************************************************
+ * Functions exported as capabilities. They are declared as static so that
+ * we don't pollute the namespace too much.
+ *****************************************************************************/
+static void input_getfunctions( function_list_t * p_function_list )
+{
+#define input p_function_list->functions.demux
+    input.pf_init             = MP4Init;
+    input.pf_end              = MP4End;
+    input.pf_demux            = MP4Demux;
+    input.pf_rewind           = NULL;
+#undef input
+}
+
+/*****************************************************************************
+ * Declaration of local function 
+ *****************************************************************************/
+static void MP4_ParseTrack();
+
+static int MP4_CreateChunksIndex();
+static int MP4_CreateSamplesIndex();
+
+static void MP4_StartDecoder();
+static void MP4_StopDecoder();
+
+static int  MP4_ReadSample();
+static int  MP4_DecodeSample();
+
+#define MP4_Set4BytesLE( p, dw ) \
+    *((u8*)p) = ( dw&0xff ); \
+    *((u8*)p+1) = ( ((dw)>> 8)&0xff ); \
+    *((u8*)p+2) = ( ((dw)>>16)&0xff ); \
+    *((u8*)p+3) = ( ((dw)>>24)&0xff )
+
+#define MP4_Set2BytesLE( p, dw ) \
+    *((u8*)p) = ( (dw)&0xff ); \
+    *((u8*)p+1) = ( ((dw)>> 8)&0xff )
+
+    
+/*****************************************************************************
+ * MP4Init: check file and initializes MP4 structures
+ *****************************************************************************/
+static int MP4Init( input_thread_t *p_input )
+{
+    u8  *p_peek;
+    u32 i_type;
+    
+    demux_data_mp4_t *p_demux;
+    
+    MP4_Box_t *p_moov;    
+    MP4_Box_t *p_ftyp;
+
+
+    MP4_Box_t *p_mvhd;
+    MP4_Box_t *p_trak;
+
+    int i;
+    /* I need to seek */
+    if( !p_input->stream.b_seekable )
+    {
+        msg_Warn( p_input, "MP4 plugin discarded (unseekable)" );
+        return( -1 );
+            
+    } 
+    /* Initialize access plug-in structures. */
+    if( p_input->i_mtu == 0 )
+    {
+        /* Improve speed. */
+        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
+    }
+
+    /* a little test to see if it could be a mp4 */
+    if( input_Peek( p_input, &p_peek, 8 ) < 8 )
+    {
+        msg_Warn( p_input, "MP4 plugin discarded (cannot peek)" );
+        return( -1 );
+    }
+    i_type = ( p_peek[4] << 24 ) + ( p_peek[5] << 16 ) +
+                ( p_peek[6] << 8 ) + ( p_peek[7] );
+    switch( i_type )
+    {
+        case( FOURCC_ftyp ):
+        case( FOURCC_moov ):
+        case( FOURCC_moof ):
+        case( FOURCC_mdat ):
+        case( FOURCC_udta ): /* should never match but ... */
+        case( FOURCC_free ):
+        case( FOURCC_skip ):
+        case( FOURCC_wide ): /* not mp4 compliant but ... */
+            break;
+         default:
+            msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
+            return( -1 );
+    }
+
+    /* create our structure that will contains all data */
+    if( !( p_input->p_demux_data = 
+                p_demux = malloc( sizeof( demux_data_mp4_t ) ) ) )
+    {
+        msg_Err( p_input, "out of memory" );
+        return( -1 );
+    }
+    memset( p_demux, 0, sizeof( demux_data_mp4_t ) );
+    p_input->p_demux_data = p_demux;
+       
+
+    /* Now load all boxes ( except raw data ) */
+    if( !MP4_ReadBoxRoot( p_input, &p_demux->box_root ) )
+    {
+        msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" );
+        return( -1 );
+    }
+
+    MP4_DumpBoxStructure( p_input, &p_demux->box_root );
+
+    if( ( p_ftyp = MP4_FindBox( &p_demux->box_root, FOURCC_ftyp ) ) )
+    {
+        switch( p_ftyp->data.p_ftyp->i_major_brand )
+        {
+            case( FOURCC_isom ):
+                msg_Info( p_input, 
+                          "ISO Media file (isom) version %d.",
+                          p_ftyp->data.p_ftyp->i_minor_version );
+                break;
+            default:
+                msg_Info( p_input,
+                          "Unrecognize major file specification." );
+                break;
+        }
+    }
+    else
+    {
+        msg_Info( p_input, "File Type box missing(assume ISO Media file)" );
+    }
+
+    /* the file need to have one moov box */
+    if( !( p_moov = MP4_FindBox( &p_demux->box_root, FOURCC_moov ) ) )
+    {
+        msg_Warn( p_input, "MP4 plugin discarded (missing moov box)" );
+        MP4End( p_input );
+        return( -1 );
+    }
+
+    if( MP4_CountBox( &p_demux->box_root, FOURCC_moov ) != 1 )
+    {
+        msg_Warn( p_input, "more than one \"moov\" box (continuying anyway)" );
+    }
+
+    if( !(p_mvhd = MP4_FindBox( p_moov, FOURCC_mvhd ) ) )
+    {
+        msg_Err( p_input, "cannot find \"mvhd\" box" );
+        MP4End( p_input );
+        return( -1 );
+    }
+    else
+    {
+        p_demux->i_timescale = p_mvhd->data.p_mvhd->i_timescale;
+    }
+    
+    p_demux->i_tracks = MP4_CountBox( p_moov, FOURCC_trak );
+    msg_Dbg( p_input, "find %d track%c",
+                        p_demux->i_tracks,
+                        p_demux->i_tracks ? 's':' ' );
+
+    if( !( p_trak = MP4_FindBox( p_moov, FOURCC_trak ) ) )
+    {
+        msg_Err( p_input, "cannot find /moov/trak !" );
+        MP4End( p_input );
+        return( -1 );
+    }
+
+    /* allocate memory */
+    p_demux->track = calloc( p_demux->i_tracks, sizeof( track_data_mp4_t ) );
+
+    /* now process each track and extract all usefull informations */
+    for( i = 0; i < p_demux->i_tracks; i++ )
+    {
+        MP4_ParseTrack( p_input, &p_demux->track[i], p_trak );
+
+        if( p_demux->track[i].b_ok )
+        {
+            char *psz_cat;
+            switch( p_demux->track[i].i_cat )
+            {
+                case( VIDEO_ES ):
+                    psz_cat = "video";
+                    break;
+                case( AUDIO_ES ):
+                    psz_cat = "audio";
+                    break;
+                default:
+                    psz_cat = "";
+                    break;
+            }
+            
+            msg_Dbg( p_input, "adding track(%d) %s (%s) language %c%c%c",
+                            i,
+                            psz_cat,
+                            p_demux->track[i].b_enable ? "enable":"disable",
+                            p_demux->track[i].i_language[0],
+                            p_demux->track[i].i_language[1], 
+                            p_demux->track[i].i_language[2] );
+        }
+        else
+        {
+            msg_Dbg( p_input, "ignoring track(%d)", i );
+        }
+
+        p_trak = MP4_FindNextBox( p_trak );
+    }
+  
+    /*  create one program */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( input_InitStream( p_input, 0 ) == -1)
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        msg_Err( p_input, "cannot init stream" );
+        MP4End( p_input );
+        return( -1 );
+    }
+    if( input_AddProgram( p_input, 0, 0) == NULL )
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        msg_Err( p_input, "cannot add program" );
+        MP4End( p_input );
+        return( -1 );
+    }
+    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
+    p_input->stream.i_mux_rate = 0 ; /* FIXME */
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+   
+    
+    for( i = 0; i < p_demux->i_tracks; i++ )
+    {
+        /* start decoder for this track if enable by default*/
+        if( p_demux->track[i].b_enable )
+        {
+            MP4_StartDecoder( p_input, &p_demux->track[i] );
+        }
+    }
+
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    p_input->stream.p_selected_program->b_is_ok = 1;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+        
+    return( 0 );    
+
+}
+
+/*****************************************************************************
+ * MP4Demux: read packet and send them to decoders 
+ *****************************************************************************/
+static int MP4Demux( input_thread_t *p_input )
+{
+    demux_data_mp4_t *p_demux = p_input->p_demux_data;
+    int i_track;
+
+    /* first wait for the good time to read a packet */
+
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_demux->i_pcr );
+
+
+    /* update pcr XXX in mpeg scale so in 90000 unit/s */
+    p_demux->i_pcr = MP4_GetMoviePTS( p_demux ) * 9 / 100;
+    
+
+    /* we will read 100ms for each stream so ...*/
+    p_demux->i_time += __MAX( p_demux->i_timescale / 10 , 1 );
+    
+
+    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
+    {
+        if( ( !p_demux->track[i_track].b_ok )||
+            ( !p_demux->track[i_track].p_es )||
+            ( !p_demux->track[i_track].p_es->p_decoder_fifo )||
+            ( MP4_GetTrackPTS( &p_demux->track[i_track] ) >=
+                        MP4_GetMoviePTS( p_demux ) ) )
+        {
+            continue; /* no need to read something */
+        }
+
+        while( MP4_GetTrackPTS( &p_demux->track[i_track] ) <
+                        MP4_GetMoviePTS( p_demux ) )
+        {
+
+            pes_packet_t *p_pes;
+
+            /* read a sample */
+            if( !MP4_ReadSample( p_input ,
+                                 &p_demux->track[i_track],
+                                 &p_pes ) )
+            {
+                break;
+            }
+
+            /* send it to decoder and update time of this track 
+                 it also launch a new decoder if needed */
+            MP4_DecodeSample( p_input ,
+                              &p_demux->track[i_track],
+                              p_pes );
+        }
+
+    }
+    
+    /* now check if all tracks are finished or unhandled*/
+    
+    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
+    {
+        if( ( p_demux->track[i_track].b_ok )&&
+            ( p_demux->track[i_track].i_sample < p_demux->track[i_track].i_sample_count )&&
+            ( p_demux->track[i_track].p_es )&&
+            ( p_demux->track[i_track].p_es->p_decoder_fifo ) )
+        {
+            return( 1 );
+        }
+    }
+
+    return( 0 ); /* EOF */
+}
+
+/*****************************************************************************
+ * MP4End: frees unused data
+ *****************************************************************************/
+static void MP4End( input_thread_t *p_input )
+{   
+#define FREE( p ) \
+    if( p ) { free( p ); } 
+    int i_track;
+    demux_data_mp4_t *p_demux = p_input->p_demux_data;
+    
+    msg_Dbg( p_input, "Freeing all memory" );
+    MP4_FreeBox( p_input, &p_demux->box_root );
+    for( i_track = 0; i_track < p_demux->i_tracks; i_track++ )
+    {
+        int i_chunk;
+        for( i_chunk = 0; 
+                i_chunk < p_demux->track[i_track].i_chunk_count; i_chunk++ )
+        {
+            if( p_demux->track[i_track].chunk )
+            {
+               FREE(p_demux->track[i_track].chunk[i_chunk].p_sample_count_dts);
+               FREE(p_demux->track[i_track].chunk[i_chunk].p_sample_delta_dts );
+            }
+        }
+        if( p_demux->track->p_data_init )
+        {
+            input_DeletePacket( p_input->p_method_data, 
+                                p_demux->track->p_data_init );
+        }
+        if( !p_demux->track[i_track].i_sample_size )
+        {
+            FREE( p_demux->track[i_track].p_sample_size );
+        }
+    }
+    FREE( p_demux->track );
+#undef FREE
+}
+
+
+/****************************************************************************
+ * Local functions, specific to vlc
+ ****************************************************************************/
+
+/****************************************************************************
+ * Parse track information and create all needed data to run a track
+ * If it succeed b_ok is set to 1 else to 0
+ ****************************************************************************/
+static void MP4_ParseTrack( input_thread_t *p_input,
+                     track_data_mp4_t *p_demux_track,
+                     MP4_Box_t  * p_trak )
+{
+    int i;
+
+    MP4_Box_t *p_tkhd = MP4_FindBox( p_trak, FOURCC_tkhd );
+    MP4_Box_t *p_tref = MP4_FindBox( p_trak, FOURCC_tref );
+    MP4_Box_t *p_edts = MP4_FindBox( p_trak, FOURCC_edts );
+    MP4_Box_t *p_mdia = MP4_FindBox( p_trak, FOURCC_mdia );
+
+    MP4_Box_t *p_mdhd;
+    MP4_Box_t *p_hdlr;
+    MP4_Box_t *p_minf;
+
+    MP4_Box_t *p_vmhd;
+    MP4_Box_t *p_smhd; 
+
+    /* hint track unsuported */
+
+    /* by default, track isn't usable */
+    p_demux_track->b_ok = 0;
+
+    /* by default, we don't known the categorie */
+    p_demux_track->i_cat = UNKNOWN_ES;
+    
+    if( ( !p_tkhd )||( !p_mdia ) )
+    {
+        return;
+    }
+
+    /* do we launch this track by default ? */
+    p_demux_track->b_enable = ( ( p_tkhd->data.p_tkhd->i_flags&MP4_TRACK_ENABLED ) != 0 );
+
+    p_demux_track->i_track_ID = p_tkhd->data.p_tkhd->i_track_ID;
+    p_demux_track->i_width = p_tkhd->data.p_tkhd->i_width / 65536;
+    p_demux_track->i_height = p_tkhd->data.p_tkhd->i_height / 65536;
+    
+    if( !p_edts )
+    {
+//        msg_Warn( p_input, "Unhandled box: edts --> FIXME" );
+    }
+
+    if( !p_tref )
+    {
+//        msg_Warn( p_input, "Unhandled box: tref --> FIXME" );
+    } 
+
+    p_mdhd = MP4_FindBox( p_mdia, FOURCC_mdhd );
+    p_hdlr = MP4_FindBox( p_mdia, FOURCC_hdlr );
+    p_minf = MP4_FindBox( p_mdia, FOURCC_minf );
+    
+    if( ( !p_mdhd )||( !p_hdlr )||( !p_minf ) )
+    {
+        return;
+    }
+
+    p_demux_track->i_timescale = p_mdhd->data.p_mdhd->i_timescale;
+
+    for( i = 0; i < 3; i++ ) 
+    {
+        p_demux_track->i_language[i] = p_mdhd->data.p_mdhd->i_language[i];
+    }
+    
+    switch( p_hdlr->data.p_hdlr->i_handler_type )
+    {
+        case( FOURCC_soun ):
+            if( !( p_smhd = MP4_FindBox( p_minf, FOURCC_smhd ) ) )
+            {
+                return;
+            }
+            p_demux_track->i_cat = AUDIO_ES;
+            break;
+
+        case( FOURCC_vide ):
+            if( !( p_vmhd = MP4_FindBox( p_minf, FOURCC_vmhd ) ) )
+            {
+                return;
+            }
+            p_demux_track->i_cat = VIDEO_ES;
+            break;
+            
+        default:
+            return;
+    }
+/*  FIXME
+    add support to:
+    p_dinf = MP4_FindBox( p_minf, FOURCC_dinf );
+*/
+    if( !( p_demux_track->p_stbl = MP4_FindBox( p_minf, FOURCC_stbl ) ) )
+    {
+        return;
+    }
+    
+    if( !( p_demux_track->p_stsd = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stsd ) ) )
+    {
+        return;
+    }
+    
+    /* Create chunk  index table */
+    if( !MP4_CreateChunksIndex( p_input,p_demux_track  ) )
+    {
+        return; /* cannot create chunks index */
+    }
+    
+    /* create sample index table needed for reading and seeking */
+    if( !MP4_CreateSamplesIndex( p_input, p_demux_track ) )
+    {
+        return; /* cannot create samples index */
+    }
+     
+    p_demux_track->b_ok = 1;        
+}
+                     
+
+
+/* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */
+static int MP4_CreateChunksIndex( input_thread_t *p_input,
+                                   track_data_mp4_t *p_demux_track )
+{
+    MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
+    MP4_Box_t *p_stsc;
+
+    int i_chunk;
+    int i_index, i_last;
+   
+
+    if( ( !(p_co64 = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stco ) )&&
+                 !(p_co64 = MP4_FindBox( p_demux_track->p_stbl, FOURCC_co64 ) ) )|| 
+        ( !(p_stsc = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stsc ) ) ))
+    {
+        return( 0 );
+    }
+     
+    p_demux_track->i_chunk_count = p_co64->data.p_co64->i_entry_count;
+    if( !p_demux_track->i_chunk_count )
+    {
+        msg_Warn( p_input, "No chunk defined" );
+        return( 0 );
+    }
+    p_demux_track->chunk = calloc( p_demux_track->i_chunk_count, 
+                                   sizeof( chunk_data_mp4_t ) );
+
+    /* first we read chunk offset */
+    for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
+    {
+        p_demux_track->chunk[i_chunk].i_offset = 
+                p_co64->data.p_co64->i_chunk_offset[i_chunk];
+    }
+
+    /* now we read index for SampleEntry( soun vide mp4a mp4v ...) 
+        to be used for the sample XXX begin to 1 
+        We construct it begining at the end */
+    i_last = p_demux_track->i_chunk_count; /* last chunk proceded */
+    i_index = p_stsc->data.p_stsc->i_entry_count;
+    if( !i_index )
+    {
+        msg_Warn( p_input, "cannot read chunk table or table empty" );
+        return( 0 );
+    }
+
+    while( i_index )
+    {
+        i_index--;
+        for( i_chunk = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;
+                i_chunk < i_last; i_chunk++ )
+        {
+            p_demux_track->chunk[i_chunk].i_sample_description_index = 
+                    p_stsc->data.p_stsc->i_sample_description_index[i_index];
+            p_demux_track->chunk[i_chunk].i_sample_count =
+                    p_stsc->data.p_stsc->i_samples_per_chunk[i_index];
+        }
+        i_last = p_stsc->data.p_stsc->i_first_chunk[i_index] - 1;
+    }
+
+    p_demux_track->chunk[i_chunk].i_sample_first = 0;
+    for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
+    {
+        p_demux_track->chunk[i_chunk].i_sample_first =
+            p_demux_track->chunk[i_chunk-1].i_sample_first + 
+                p_demux_track->chunk[i_chunk-1].i_sample_count;
+        
+    }
+    
+    msg_Dbg( p_input, "read %d chunk", p_demux_track->i_chunk_count );
+    return( 1 );
+
+}
+
+
+
+static int MP4_CreateSamplesIndex( input_thread_t *p_input,
+                                   track_data_mp4_t *p_demux_track )
+{
+    MP4_Box_t *p_stts; /* makes mapping between sample and decoding time,
+                          ctts make same mapping but for composition time, 
+                          not yet used and probably not usefull */
+    MP4_Box_t *p_stsz; /* gives sample size of each samples, there is also stz2 
+                          that uses a compressed form FIXME make them in libmp4 
+                          as a unique type */
+    /* TODO use also stss and stsh table for seeking */
+    /* FIXME use edit table */
+    int i_sample;
+    int i_chunk;
+
+    int i_index;
+    int i_index_sample_used;
+
+    u64 i_last_dts; 
+    
+    p_stts = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stts );
+    p_stsz = MP4_FindBox( p_demux_track->p_stbl, FOURCC_stsz ); /* FIXME and stz2 */
+
+    
+    if( ( !p_stts )||( !p_stsz ) )
+    {
+        msg_Warn( p_input, "cannot read sample table" );
+        return( 0 ); 
+    }
+        
+    p_demux_track->i_sample_count = p_stsz->data.p_stsz->i_sample_count;
+
+
+    /* for sample size, there are 2 case */
+    if( p_stsz->data.p_stsz->i_sample_size )
+    {
+        /* 1: all sample have the same size, so no need to construct a table */
+        p_demux_track->i_sample_size = p_stsz->data.p_stsz->i_sample_size;
+        p_demux_track->p_sample_size = NULL;
+    }
+    else
+    {
+        /* 2: each sample can have a different size */
+        p_demux_track->i_sample_size = 0;
+        p_demux_track->p_sample_size = 
+            calloc( p_demux_track->i_sample_count, sizeof( u32 ) );
+        
+        for( i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
+        {
+            p_demux_track->p_sample_size[i_sample] = 
+                    p_stsz->data.p_stsz->i_entry_size[i_sample];
+        }
+    }
+    /* we have extract all information from stsz,
+        now use stts */
+
+    /* if we don't want to waste too much memory, we can't expand
+       the box !, so each chunk will contain an "extract" of this table 
+       for fast research */
+        
+    i_last_dts = 0;
+    i_index = 0; i_index_sample_used =0;
+    /* create and init last data for each chunk */
+    for(i_chunk = 0 ; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
+    {
+
+        int i_entry, i_sample_count, i;
+        /* save last dts */
+        p_demux_track->chunk[i_chunk].i_first_dts = i_last_dts;
+    /* count how many entries needed for this chunk 
+       for p_sample_delta_dts and p_sample_count_dts */
+
+        i_entry = 0;
+        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
+        while( i_sample_count > 0 )
+        {
+            i_sample_count -= p_stts->data.p_stts->i_sample_count[i_index+i_entry];
+            if( i_entry == 0 )
+            {
+                i_sample_count += i_index_sample_used; /* don't count already used sample 
+                                                   int this entry */
+            }
+            i_entry++;
+        }
+        /* allocate them */
+        p_demux_track->chunk[i_chunk].p_sample_count_dts = 
+            calloc( i_entry, sizeof( u32 ) );
+        p_demux_track->chunk[i_chunk].p_sample_delta_dts =
+            calloc( i_entry, sizeof( u32 ) );
+
+        /* now copy */
+        i_sample_count = p_demux_track->chunk[i_chunk].i_sample_count;
+        for( i = 0; i < i_entry; i++ )
+        {
+            int i_used;
+            int i_rest;
+            
+            i_rest = p_stts->data.p_stts->i_sample_count[i_index] - i_index_sample_used;
+
+            i_used = __MIN( i_rest, i_sample_count );
+
+            i_index_sample_used += i_used;
+
+            p_demux_track->chunk[i_chunk].p_sample_count_dts[i] = i_used;
+
+            p_demux_track->chunk[i_chunk].p_sample_delta_dts[i] =
+                        p_stts->data.p_stts->i_sample_delta[i_index];
+            
+            i_last_dts += i_used * 
+                    p_demux_track->chunk[i_chunk].p_sample_delta_dts[i];
+
+            if( i_index_sample_used >=
+                             p_stts->data.p_stts->i_sample_count[i_index] )
+            {
+                i_index++;
+                i_index_sample_used = 0;
+            }
+        }
+        
+    }
+
+    msg_Dbg( p_input, "read %d samples", p_demux_track->i_sample_count );
+
+    return( 1 );
+}
+
+static void MP4_StartDecoder( input_thread_t *p_input,
+                                 track_data_mp4_t *p_demux_track )
+{
+    MP4_Box_t *p_sample;
+    int i;
+    int i_chunk;
+    u8  *p_bmih;
+    int i_codec;
+    char *psz_name;
+    
+    MP4_Box_t *p_esds;
+
+    
+    if( (!p_demux_track->b_ok )||( p_demux_track->i_cat == UNKNOWN_ES ) )
+    {
+        return;
+    }
+    
+    msg_Dbg( p_input, "Starting decoder (track ID 0x%x)",
+                      p_demux_track->i_track_ID );
+
+    /* launch decoder according in chunk we are */
+    i_chunk = p_demux_track->i_chunk;
+
+    if( !p_demux_track->chunk[i_chunk].i_sample_description_index )
+    {
+        msg_Warn( p_input, "invalid SampleEntry index for this track i_cat %d" );
+        return;
+    } 
+    
+    p_sample = MP4_FindNbBox( p_demux_track->p_stsd,
+                              p_demux_track->chunk[i_chunk].i_sample_description_index - 1);
+
+    if( !p_sample )
+    {
+        msg_Warn( p_input, "cannot find SampleEntry for this track" );
+        return;
+    }
+
+    
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    p_demux_track->p_es = input_AddES( p_input,
+                                       p_input->stream.p_selected_program, 
+                                       p_demux_track->i_track_ID,
+                                       0 );
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+    /* Initialise ES, first language as description */
+    for( i = 0; i < 3; i++ )
+    {
+        p_demux_track->p_es->psz_desc[i] = p_demux_track->i_language[i];
+    }
+    p_demux_track->p_es->psz_desc[4] = 0;
+    
+    p_demux_track->p_es->i_stream_id = p_demux_track->i_track_ID;
+
+    p_demux_track->p_es->i_type = UNKNOWN_ES;
+    p_demux_track->p_es->i_cat = p_demux_track->i_cat;
+
+    /* search for the codec */
+    if( !MP4_GetCodec( p_sample->i_type, &i_codec, &psz_name ) )
+    {
+        msg_Warn( p_input, "%s (%c%c%c%c) unsupported", 
+                  psz_name,
+                  (p_sample->i_type >> 24)&0xff,
+                  (p_sample->i_type >> 16)&0xff,
+                  (p_sample->i_type >> 8)&0xff,
+                  (p_sample->i_type )&0xff);
+        p_demux_track->b_ok = 0;
+        return;
+    }
+    else
+    {
+        p_demux_track->p_es->i_type = i_codec;
+        msg_Info( p_input, "%s supported", psz_name );
+    }
+
+    switch( p_demux_track->i_cat )
+    {
+        case( VIDEO_ES ):    
+            p_demux_track->p_es->b_audio = 0;
+
+            /* now create a bitmapinfoheader_t for decoder */
+            p_bmih = malloc( 40 );
+            memset( p_bmih, 0, 40);
+            MP4_Set4BytesLE( p_bmih, 40 );
+            if( p_sample->data.p_sample_mp4v->i_width )
+            {
+                MP4_Set4BytesLE( p_bmih + 4, p_sample->data.p_sample_mp4v->i_width );
+            }
+            else
+            {
+                /* use display size */
+                MP4_Set4BytesLE( p_bmih + 4, p_demux_track->i_width );
+            }
+            if( p_sample->data.p_sample_mp4v->i_height )
+            {
+                MP4_Set4BytesLE( p_bmih + 8, p_sample->data.p_sample_mp4v->i_height );
+            }
+            else
+            {
+                MP4_Set4BytesLE( p_bmih + 8, p_demux_track->i_height );
+            }
+
+            p_demux_track->p_es->p_demux_data = p_bmih;
+            break;
+        case( AUDIO_ES ):
+            p_demux_track->p_es->b_audio = 1;
+            break;
+        default:
+            break;
+    }
+
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    input_SelectES( p_input, p_demux_track->p_es );
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+    
+
+    p_demux_track->b_ok = 1;
+
+    /* now see if esds is present and i so create a data packet 
+        with decoder_specific_info  */
+    if( ( p_esds = MP4_FindBox( p_sample, FOURCC_esds ) )&&
+        ( p_esds->data.p_esds->es_descriptor.p_decConfigDescr )&&
+        ( p_esds->data.p_esds->es_descriptor.p_decConfigDescr->i_decoder_specific_info_len ) )
+    {
+        data_packet_t *p_data;
+        int i_size = p_esds->data.p_esds->es_descriptor.p_decConfigDescr->i_decoder_specific_info_len;
+
+        /* data packet for the data */
+        if( !(p_data = input_NewPacket( p_input->p_method_data, i_size ) ) )
+        {
+            return;
+        }
+
+        /* initialisation of all the field */
+        memcpy( p_data->p_payload_start,
+                p_esds->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info,
+                i_size ); 
+        p_demux_track->p_data_init = p_data;
+    }
+                           
+    
+    return;
+}
+
+
+static void MP4_StopDecoder( input_thread_t *p_input,
+                             track_data_mp4_t *p_demux_track )
+{
+    msg_Dbg( p_input, "Stopping decoder (track ID 0x%x)",
+                      p_demux_track->i_track_ID );
+
+    input_UnselectES( p_input, p_demux_track->p_es );
+    p_demux_track->p_es = NULL;
+    if( p_demux_track->p_data_init )
+    {
+        input_DeletePacket( p_input->p_method_data, 
+                            p_demux_track->p_data_init );
+        p_demux_track->p_data_init = NULL;
+    }
+    
+}
+
+static int  MP4_ReadSample( input_thread_t *p_input,
+                            track_data_mp4_t *p_demux_track,
+                            pes_packet_t **pp_pes )
+{
+    int i_size;
+    off_t i_pos;
+
+    data_packet_t *p_data;
+
+
+    /* this track have already reach the end */
+    if( p_demux_track->i_sample >= p_demux_track->i_sample_count )
+    {
+        *pp_pes = NULL;
+        return( 0 );
+    }
+    /* caculate size and position for this sample */
+    i_size = p_demux_track->i_sample_size ? 
+        p_demux_track->i_sample_size : p_demux_track->p_sample_size[p_demux_track->i_sample];
+    /* TODO */
+    i_pos  = MP4_GetTrackPos( p_demux_track );
+
+    /* go,go go ! */
+    if( ! MP4_SeekAbsolute( p_input, i_pos ) )
+    {
+        return( 0 );
+    }
+
+    /* now create a pes */
+    if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) )
+    {
+        return( 0 );
+    }
+    /* and a data packet for the data */
+    if( !(p_data = input_NewPacket( p_input->p_method_data, i_size ) ) )
+    {
+        input_DeletePES( p_input->p_method_data, *pp_pes );
+        *pp_pes = NULL;
+        return( 0 );
+    }
+    
+    /* initialisation of all the field */
+    (*pp_pes)->i_dts =
+        (*pp_pes)->i_pts = MP4_GetTrackPTS( p_demux_track );
+    (*pp_pes)->p_first = (*pp_pes)->p_last  = p_data;
+    (*pp_pes)->i_nb_data = 1;
+    (*pp_pes)->i_pes_size = i_size;
+
+    if( !i_size )    
+    {
+        return( 1 );
+    }
+    
+//    msg_Dbg( p_input, "will read %d bytes", i_size );
+    if( !MP4_ReadData( p_input, p_data->p_payload_start, i_size ) )
+    {
+        input_DeletePES( p_input->p_method_data, *pp_pes );
+        input_DeletePacket( p_input->p_method_data, p_data );
+        return( 0 );
+    }
+
+       return( 1 );
+}
+
+
+static int  MP4_DecodeSample( input_thread_t *p_input,
+                              track_data_mp4_t *p_demux_track,
+                              pes_packet_t *p_pes )
+{
+
+    if( !p_pes )
+    {
+        return( 0 );
+    }
+
+    /* don't forget to convert in mpeg clock */
+    /* FIXME correct ffmpeg to use dts instead of pts that it incorrect 
+       and, set it here ( and correct avi demux ) */
+    p_pes->i_dts =
+        p_pes->i_pts = input_ClockGetTS( p_input,
+                                         p_input->stream.p_selected_program,
+                                         p_pes->i_pts * 9/100);
+
+    
+    if( p_demux_track->p_data_init )
+    {
+        pes_packet_t *p_pes_init;
+        /* create a pes packet containing decoder initialisation 
+           with the one we will send to decoder */
+        if( !(p_pes_init = input_NewPES( p_input->p_method_data ) ) )
+        {
+            msg_Err( p_input, "out of memory" );
+            return( 0 );
+        }
+        
+        p_pes_init->p_first = 
+            p_pes_init->p_last = p_demux_track->p_data_init;
+
+        p_pes_init->i_pes_size = p_demux_track->p_data_init->p_payload_end - 
+                                   p_demux_track->p_data_init->p_payload_start;
+        p_pes_init->i_nb_data = 1;
+
+        input_DecodePES( p_demux_track->p_es->p_decoder_fifo, p_pes_init );
+        p_demux_track->p_data_init = NULL;
+    }
+
+    input_DecodePES( p_demux_track->p_es->p_decoder_fifo, p_pes );
+    
+    /* now update sample position */
+    p_demux_track->i_sample++; /* easy ;) */
+    if( p_demux_track->i_sample >= p_demux_track->i_sample_count )
+    {
+        /* we have reach end of the track so free decoder stuff */
+        MP4_StopDecoder( p_input, p_demux_track );
+        return( 1 );
+    }
+    /* Have we changed chunk ? */
+    if( p_demux_track->i_sample >=
+            p_demux_track->chunk[p_demux_track->i_chunk].i_sample_first +
+                p_demux_track->chunk[p_demux_track->i_chunk].i_sample_count )
+    {
+        /* we haven't reached the end of the track, so see if we 
+           have to change the decoder for the next frame because 
+           i_sample_description_index have changed */
+
+        p_demux_track->i_chunk++;
+        if( p_demux_track->chunk[p_demux_track->i_chunk-1].i_sample_description_index 
+              != p_demux_track->chunk[p_demux_track->i_chunk].i_sample_description_index  )
+        {
+            /* FIXME */
+            msg_Err( p_input, "I need to change the decoder but not yet implemented" );
+            return( 0 );
+        }
+    }
+
+    
+    return( 1 );
+}
+
+
+
diff --git a/plugins/mp4/mp4.h b/plugins/mp4/mp4.h
new file mode 100644 (file)
index 0000000..9746868
--- /dev/null
@@ -0,0 +1,249 @@
+/*****************************************************************************
+ * mp4.h : MP4 file input module for vlc
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: mp4.h,v 1.1 2002/07/17 21:37:27 fenrir Exp $
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+/*****************************************************************************
+ * Structure needed for ffmpeg decoder
+ *****************************************************************************/
+
+typedef struct bitmapinfoheader_s
+{
+    u32 i_size; /* size of header */
+    u32 i_width;
+    u32 i_height;
+    u16 i_planes;
+    u16 i_bitcount;
+    u32 i_compression;
+    u32 i_sizeimage;
+    u32 i_xpelspermeter;
+    u32 i_ypelspermeter;
+    u32 i_clrused;
+    u32 i_clrimportant;
+} bitmapinfoheader_t;
+
+
+
+/*****************************************************************************
+ * Contain all information about a chunk
+ *****************************************************************************/
+typedef struct chunk_data_mp4_s
+{
+    u64     i_offset; /* absolute position of this chunk in the file */
+    u32     i_sample_description_index; /* index for SampleEntry to use */
+    u32     i_sample_count; /* how many samples in this chunk */
+    u32     i_sample_first; /* index of the first sample in this chunk */
+
+    /* now provide way to calculate pts, dts, and offset without to 
+        much memory and with fast acces */
+
+    /* with this we can calculate dts/pts without waste memory */
+    u64     i_first_dts;
+    u32     *p_sample_count_dts;
+    u32     *p_sample_delta_dts; /* dts delta */
+
+    /* TODO if needed add pts 
+        but quickly *add* support for edts and seeking */
+    
+} chunk_data_mp4_t;
+
+
+/*****************************************************************************
+ * Contain all needed information for read all track with vlc
+ *****************************************************************************/
+typedef struct track_data_mp4_s
+{
+    int b_ok;           /* The track is usable */
+    int i_track_ID;     /* this should be unique */
+    int b_enable;       /* is the trak enable by default */
+
+    int i_cat;          /* Type of the track, VIDEO_ES, AUDIO_ES, UNKNOWN_ES  ... */
+    char        i_language[3];
+
+    /* display size only ! */
+    int         i_width;
+    int         i_height;
+    /* more internal data */    
+    u64         i_timescale;  /* time scale for this track only */
+
+    /* give the next sample to read, i_chunk is to find quickly where 
+      the sample is located */
+    u32         i_sample;       /* next sample to read */
+    u32         i_chunk;        /* chunk where next sample is stored */
+    /* total count of chunk and sample */
+    u32         i_chunk_count;  
+    u32         i_sample_count;
+    
+    chunk_data_mp4_t    *chunk; /* always defined  for each chunk */
+    
+    /* sample size, p_sample_size defined only if i_sample_size == 0 
+        else i_sample_size is size for all sample */
+    u32         i_sample_size;
+    u32         *p_sample_size; /* XXX perhaps add file offset if take 
+                                    too much time to do sumations each time*/
+    
+    es_descriptor_t *p_es; /* vlc es for this track */
+    data_packet_t   *p_data_init; /* send this with the first packet, 
+                                        and then discarded it*/
+
+    MP4_Box_t *p_stbl;  /* will contain all timing information */
+    MP4_Box_t *p_stsd;  /* will contain all data to initialize decoder */
+    
+    MP4_Box_t *p_sample; /* actual SampleEntry to make life simpler */
+} track_data_mp4_t;
+
+
+/*****************************************************************************
+ *
+ *****************************************************************************/
+typedef struct demux_data_mp4_s
+{
+
+    MP4_Box_t   box_root;       /* container for the hole file */
+
+    mtime_t     i_pcr;
+    
+    u64         i_time;         /* time position of the presentation in movie timescale */
+    u64         i_timescale;    /* movie time scale */
+    
+    int i_tracks;               /* number of track */  
+    track_data_mp4_t *track; /* array of track */
+    
+  
+} demux_data_mp4_t;
+
+static inline u64 MP4_GetTrackPos( track_data_mp4_t *p_track )
+{
+    int i_sample;
+    u64 i_pos;
+
+
+    i_pos = p_track->chunk[p_track->i_chunk].i_offset;
+
+    if( p_track->i_sample_size )
+    {
+        i_pos += ( p_track->i_sample - 
+                        p_track->chunk[p_track->i_chunk].i_sample_first ) *
+                                p_track->i_sample_size;
+    }
+    else
+    {
+        for( i_sample = p_track->chunk[p_track->i_chunk].i_sample_first; 
+                i_sample < p_track->i_sample; i_sample++ )
+        {
+            i_pos += p_track->p_sample_size[i_sample];
+        }
+
+    }
+    return( i_pos );
+}
+
+/* Return time in ┬Ás of a track */
+static inline mtime_t MP4_GetTrackPTS( track_data_mp4_t *p_track )
+{
+    int i_sample;
+    int i_index;
+    u64 i_dts;
+    
+    i_sample = p_track->i_sample - p_track->chunk[p_track->i_chunk].i_sample_first;
+    i_dts = p_track->chunk[p_track->i_chunk].i_first_dts;
+    i_index = 0;
+    while( i_sample > 0 )
+    {
+        if( i_sample > p_track->chunk[p_track->i_chunk].p_sample_count_dts[i_index] )
+        {
+            i_dts += p_track->chunk[p_track->i_chunk].p_sample_count_dts[i_index] * 
+                        p_track->chunk[p_track->i_chunk].p_sample_delta_dts[i_index];
+            i_sample -= p_track->chunk[p_track->i_chunk].p_sample_count_dts[i_index];
+            i_index++;
+        }
+        else
+        {
+            i_dts += i_sample * 
+                        p_track->chunk[p_track->i_chunk].p_sample_delta_dts[i_index];
+            i_sample = 0;
+            break;
+        }
+    }
+    return( (mtime_t)( 
+                (mtime_t)1000000 *
+                (mtime_t)i_dts / 
+                (mtime_t)p_track->i_timescale ) );
+}
+
+static inline mtime_t MP4_GetMoviePTS(demux_data_mp4_t *p_demux )
+{
+    return( (mtime_t)(
+                (mtime_t)1000000 *
+                (mtime_t)p_demux->i_time /
+                (mtime_t)p_demux->i_timescale )
+          );
+}
+    
+static struct
+{
+    u32 i_fourcc;
+    int i_codec;
+    char *psz_name;
+} MP4_Codecs [] = {
+    /* Video codec */
+    { FOURCC_vide,  UNKNOWN_ES,     "Generic VisualSampleEntry" },
+    { FOURCC_DIVX,  MPEG4_VIDEO_ES, "DIVX SampleEntry (MPEG-4)" },
+    { FOURCC_h263,  H263_VIDEO_ES,  "H263 SampleEntry" },
+    { FOURCC_SVQ1,  SVQ1_VIDEO_ES,  "SVQ1 SampleEntry (Sorenson Video v1" },
+    { FOURCC_mp4v,  MPEG4_VIDEO_ES, "MP4VisualSampleEntry (MPEG-4)" },
+    { FOURCC_3IV1,  UNKNOWN_ES,     "3IV1 SampleEntry" },
+
+    /* Audio codec */
+    { FOURCC_soun,  UNKNOWN_ES,     "Generic AudioSampleEntry" },
+    { FOURCC_mp4a,  UNKNOWN_ES,     "MP4AudioSampleEntry (AAC)" },
+    { FOURCC__mp3,  MPEG2_AUDIO_ES, ".mp3 SampleEntry (MPEG-I/II layer 3)" },
+    
+    /* Last entry with fourcc == 0 */
+    { 0,            UNKNOWN_ES,     "Unknown SampleEntry" }
+};
+
+static int MP4_GetCodec( u32  i_fourcc,
+                         int  *pi_codec,
+                         char **ppsz_name )
+{
+   int i;
+
+    for( i = 0; ; i++ )
+    {
+        if( ( MP4_Codecs[i].i_fourcc == i_fourcc )||
+            ( MP4_Codecs[i].i_fourcc == 0) )
+        {
+            break;
+        }
+    }
+
+    if( pi_codec )
+        *pi_codec = MP4_Codecs[i].i_codec;
+    
+    if( ppsz_name )
+        *ppsz_name = MP4_Codecs[i].psz_name;
+
+    return( MP4_Codecs[i].i_codec == UNKNOWN_ES ? 0 : 1 );
+}
+