]> git.sesse.net Git - vlc/blob - modules/demux/mp4/libmp4.c
Implemented GPAC chapter support (but not apple ones).
[vlc] / modules / demux / mp4 / libmp4.c
1 /*****************************************************************************
2  * libmp4.c : LibMP4 library for mp4 module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001-2004 the VideoLAN team
5  * $Id$
6  *
7  * Author: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23 #include <vlc/vlc.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>                                      /* malloc(), free() */
27
28 #include <vlc_demux.h>
29
30 #ifdef HAVE_ZLIB_H
31 #   include <zlib.h>                                  /* for compressed moov */
32 #endif
33
34 #include "libmp4.h"
35 #include "drms.h"
36
37 /*****************************************************************************
38  * Here are defined some macro to make life simpler but before using it
39  *  *look* at the code.
40  *
41  *****************************************************************************/
42 #define MP4_BOX_HEADERSIZE( p_box )             \
43   ( 8 + ( p_box->i_shortsize == 1 ? 8 : 0 )     \
44       + ( p_box->i_type == FOURCC_uuid ? 16 : 0 ) )
45
46 #define MP4_GETX_PRIVATE(dst, code, size) do { \
47     if( (i_read) >= (size) ) { dst = (code); p_peek += (size); } \
48     else { dst = 0; }   \
49     i_read -= (size);   \
50   } while(0)
51
52 #define MP4_GET1BYTE( dst )  MP4_GETX_PRIVATE( dst, *p_peek, 1 )
53 #define MP4_GET2BYTES( dst ) MP4_GETX_PRIVATE( dst, GetWBE(p_peek), 2 )
54 #define MP4_GET3BYTES( dst ) MP4_GETX_PRIVATE( dst, Get24bBE(p_peek), 3 )
55 #define MP4_GET4BYTES( dst ) MP4_GETX_PRIVATE( dst, GetDWBE(p_peek), 4 )
56 #define MP4_GET8BYTES( dst ) MP4_GETX_PRIVATE( dst, GetQWBE(p_peek), 8 )
57 #define MP4_GETFOURCC( dst ) MP4_GETX_PRIVATE( dst, \
58                 VLC_FOURCC(p_peek[0],p_peek[1],p_peek[2],p_peek[3]), 4)
59
60 #define MP4_GETVERSIONFLAGS( p_void ) \
61     MP4_GET1BYTE( p_void->i_version ); \
62     MP4_GET3BYTES( p_void->i_flags )
63
64 #define MP4_GETSTRINGZ( p_str )         \
65     if( (i_read > 0) && (p_peek[0]) )   \
66     {       \
67         const int __i_copy__ = strnlen( (char*)p_peek, i_read-1 );  \
68         p_str = calloc( sizeof(char), __i_copy__+1 );               \
69         if( __i_copy__ > 0 ) memcpy( p_str, p_peek, __i_copy__ );   \
70         p_str[__i_copy__] = 0;      \
71         p_peek += __i_copy__ + 1;   \
72         i_read -= __i_copy__ + 1;   \
73     }       \
74     else    \
75     {       \
76         p_str = NULL; \
77     }
78
79
80 #define MP4_READBOX_ENTER( MP4_Box_data_TYPE_t ) \
81     int64_t  i_read = p_box->i_size; \
82     uint8_t *p_peek, *p_buff; \
83     int i_actually_read; \
84     if( !( p_peek = p_buff = malloc( i_read ) ) ) \
85     { \
86         return( 0 ); \
87     } \
88     i_actually_read = stream_Read( p_stream, p_peek, i_read ); \
89     if( i_actually_read < 0 || (int64_t)i_actually_read < i_read )\
90     { \
91         free( p_buff ); \
92         return( 0 ); \
93     } \
94     p_peek += MP4_BOX_HEADERSIZE( p_box ); \
95     i_read -= MP4_BOX_HEADERSIZE( p_box ); \
96     if( !( p_box->data.p_data = malloc( sizeof( MP4_Box_data_TYPE_t ) ) ) ) \
97     { \
98       free( p_buff ); \
99       return( 0 ); \
100     }
101
102 #define MP4_READBOX_EXIT( i_code ) \
103     free( p_buff ); \
104     if( i_read < 0 ) \
105     { \
106         msg_Warn( p_stream, "Not enough data" ); \
107     } \
108     return( i_code )
109
110
111 /* Some assumptions:
112         * The input method HAVE to be seekable
113
114 */
115
116 static uint32_t Get24bBE( uint8_t *p )
117 {
118     return( ( p[0] <<16 ) + ( p[1] <<8 ) + p[2] );
119 }
120
121 static void GetUUID( UUID_t *p_uuid, uint8_t *p_buff )
122 {
123     memcpy( p_uuid, p_buff, 16 );
124 }
125
126 static void CreateUUID( UUID_t *p_uuid, uint32_t i_fourcc )
127 {
128     /* made by 0xXXXXXXXX-0011-0010-8000-00aa00389b71
129             where XXXXXXXX is the fourcc */
130     /* FIXME implement this */
131 }
132
133 /* some functions for mp4 encoding of variables */
134
135 static void MP4_ConvertDate2Str( char *psz, uint64_t i_date )
136 {
137     int i_day;
138     int i_hour;
139     int i_min;
140     int i_sec;
141
142     /* date begin at 1 jan 1904 */
143     i_date += ((I64C(1904) * 365) + 17) * 24 * 60 * 60;
144
145     i_day = i_date / ( 60*60*24);
146     i_hour = ( i_date /( 60*60 ) ) % 60;
147     i_min  = ( i_date / 60 ) % 60;
148     i_sec =  i_date % 60;
149     sprintf( psz, "%dd-%2.2dh:%2.2dm:%2.2ds", i_day, i_hour, i_min, i_sec );
150 }
151
152 /*****************************************************************************
153  * Some prototypes.
154  *****************************************************************************/
155 static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father );
156
157
158 /*****************************************************************************
159  * MP4_ReadBoxCommon : Load only common parameters for all boxes
160  *****************************************************************************
161  * p_box need to be an already allocated MP4_Box_t, and all data
162  *  will only be peek not read
163  *
164  * RETURN : 0 if it fail, 1 otherwise
165  *****************************************************************************/
166 int MP4_ReadBoxCommon( stream_t *p_stream, MP4_Box_t *p_box )
167 {
168     int      i_read;
169     uint8_t  *p_peek;
170
171     if( ( ( i_read = stream_Peek( p_stream, &p_peek, 32 ) ) < 8 ) )
172     {
173         return 0;
174     }
175     p_box->i_pos = stream_Tell( p_stream );
176
177     p_box->data.p_data = NULL;
178     p_box->p_father = NULL;
179     p_box->p_first  = NULL;
180     p_box->p_last  = NULL;
181     p_box->p_next   = NULL;
182
183     MP4_GET4BYTES( p_box->i_shortsize );
184     MP4_GETFOURCC( p_box->i_type );
185
186     /* Now special case */
187
188     if( p_box->i_shortsize == 1 )
189     {
190         /* get the true size on 64 bits */
191         MP4_GET8BYTES( p_box->i_size );
192     }
193     else
194     {
195         p_box->i_size = p_box->i_shortsize;
196         /* XXX size of 0 means that the box extends to end of file */
197     }
198
199     if( p_box->i_type == FOURCC_uuid )
200     {
201         /* get extented type on 16 bytes */
202         GetUUID( &p_box->i_uuid, p_peek );
203         p_peek += 16; i_read -= 16;
204     }
205     else
206     {
207         CreateUUID( &p_box->i_uuid, p_box->i_type );
208     }
209 #ifdef MP4_VERBOSE
210     if( p_box->i_size )
211     {
212         msg_Dbg( p_stream, "found Box: %4.4s size "I64Fd,
213                  (char*)&p_box->i_type, p_box->i_size );
214     }
215 #endif
216
217     return 1;
218 }
219
220 /*****************************************************************************
221  * MP4_NextBox : Go to the next box
222  *****************************************************************************
223  * if p_box == NULL, go to the next box in which we are( at the begining ).
224  *****************************************************************************/
225 static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
226 {
227     MP4_Box_t box;
228
229     if( !p_box )
230     {
231         MP4_ReadBoxCommon( p_stream, &box );
232         p_box = &box;
233     }
234
235     if( !p_box->i_size )
236     {
237         return 2; /* Box with infinite size */
238     }
239
240     if( p_box->p_father )
241     {
242         /* check if it's within p-father */
243         if( p_box->i_size + p_box->i_pos >=
244             p_box->p_father->i_size + p_box->p_father->i_pos )
245         {
246             msg_Dbg( p_stream, "out of bound child" );
247             return 0; /* out of bound */
248         }
249     }
250     if( stream_Seek( p_stream, p_box->i_size + p_box->i_pos ) )
251     {
252         return 0;
253     }
254
255     return 1;
256 }
257
258 /*****************************************************************************
259  * For all known box a loader is given,
260  *  XXX: all common struct have to be already read by MP4_ReadBoxCommon
261  *       after called one of theses functions, file position is unknown
262  *       you need to call MP4_GotoBox to go where you want
263  *****************************************************************************/
264 static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container )
265 {
266     MP4_Box_t *p_box;
267
268     if( stream_Tell( p_stream ) + 8 >
269         (off_t)(p_container->i_pos + p_container->i_size) )
270     {
271         /* there is no box to load */
272         return 0;
273     }
274
275     do
276     {
277         if( ( p_box = MP4_ReadBox( p_stream, p_container ) ) == NULL ) break;
278
279         /* chain this box with the father and the other at same level */
280         if( !p_container->p_first ) p_container->p_first = p_box;
281         else p_container->p_last->p_next = p_box;
282         p_container->p_last = p_box;
283
284     } while( MP4_NextBox( p_stream, p_box ) == 1 );
285
286     return 1;
287 }
288
289 static int MP4_ReadBoxContainer( stream_t *p_stream, MP4_Box_t *p_container )
290 {
291     if( p_container->i_size <= (size_t)MP4_BOX_HEADERSIZE(p_container ) + 8 )
292     {
293         /* container is empty, 8 stand for the first header in this box */
294         return 1;
295     }
296
297     /* enter box */
298     stream_Seek( p_stream, p_container->i_pos +
299                  MP4_BOX_HEADERSIZE( p_container ) );
300
301     return MP4_ReadBoxContainerRaw( p_stream, p_container );
302 }
303
304 static void MP4_FreeBox_Common( MP4_Box_t *p_box )
305 {
306     /* Up to now do nothing */
307 }
308
309 static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box )
310 {
311     /* XXX sometime moov is hiden in a free box */
312     if( p_box->p_father &&
313         p_box->p_father->i_type == VLC_FOURCC( 'r', 'o', 'o', 't' ) &&
314         p_box->i_type == FOURCC_free )
315     {
316         uint8_t *p_peek;
317         int     i_read;
318         vlc_fourcc_t i_fcc;
319
320         i_read  = stream_Peek( p_stream, &p_peek, 44 );
321
322         p_peek += MP4_BOX_HEADERSIZE( p_box ) + 4;
323         i_read -= MP4_BOX_HEADERSIZE( p_box ) + 4;
324
325         if( i_read >= 8 )
326         {
327             i_fcc = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
328
329             if( i_fcc == FOURCC_cmov || i_fcc == FOURCC_mvhd )
330             {
331                 msg_Warn( p_stream, "detected moov hidden in a free box ..." );
332
333                 p_box->i_type = FOURCC_foov;
334                 return MP4_ReadBoxContainer( p_stream, p_box );
335             }
336         }
337     }
338
339     /* Nothing to do */
340 #ifdef MP4_VERBOSE
341     msg_Dbg( p_stream, "skip box: \"%4.4s\"", (char*)&p_box->i_type );
342 #endif
343     return 1;
344 }
345
346 static int MP4_ReadBox_ftyp( stream_t *p_stream, MP4_Box_t *p_box )
347 {
348     MP4_READBOX_ENTER( MP4_Box_data_ftyp_t );
349
350     MP4_GETFOURCC( p_box->data.p_ftyp->i_major_brand );
351     MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version );
352
353     if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) )
354     {
355         unsigned int i;
356         p_box->data.p_ftyp->i_compatible_brands =
357             calloc( p_box->data.p_ftyp->i_compatible_brands_count, sizeof(uint32_t));
358
359         for( i =0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )
360         {
361             MP4_GETFOURCC( p_box->data.p_ftyp->i_compatible_brands[i] );
362         }
363     }
364     else
365     {
366         p_box->data.p_ftyp->i_compatible_brands = NULL;
367     }
368
369     MP4_READBOX_EXIT( 1 );
370 }
371
372 static void MP4_FreeBox_ftyp( MP4_Box_t *p_box )
373 {
374     FREENULL( p_box->data.p_ftyp->i_compatible_brands );
375 }
376
377
378 static int MP4_ReadBox_mvhd(  stream_t *p_stream, MP4_Box_t *p_box )
379 {
380     unsigned int i;
381 #ifdef MP4_VERBOSE
382     char s_creation_time[128];
383     char s_modification_time[128];
384     char s_duration[128];
385 #endif
386     MP4_READBOX_ENTER( MP4_Box_data_mvhd_t );
387
388     MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );
389
390     if( p_box->data.p_mvhd->i_version )
391     {
392         MP4_GET8BYTES( p_box->data.p_mvhd->i_creation_time );
393         MP4_GET8BYTES( p_box->data.p_mvhd->i_modification_time );
394         MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
395         MP4_GET8BYTES( p_box->data.p_mvhd->i_duration );
396     }
397     else
398     {
399         MP4_GET4BYTES( p_box->data.p_mvhd->i_creation_time );
400         MP4_GET4BYTES( p_box->data.p_mvhd->i_modification_time );
401         MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
402         MP4_GET4BYTES( p_box->data.p_mvhd->i_duration );
403     }
404     MP4_GET4BYTES( p_box->data.p_mvhd->i_rate );
405     MP4_GET2BYTES( p_box->data.p_mvhd->i_volume );
406     MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 );
407
408
409     for( i = 0; i < 2; i++ )
410     {
411         MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] );
412     }
413     for( i = 0; i < 9; i++ )
414     {
415         MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] );
416     }
417     for( i = 0; i < 6; i++ )
418     {
419         MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] );
420     }
421
422     MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id );
423
424
425 #ifdef MP4_VERBOSE
426     MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
427     MP4_ConvertDate2Str( s_modification_time,
428                          p_box->data.p_mvhd->i_modification_time );
429     if( p_box->data.p_mvhd->i_rate )
430     {
431         MP4_ConvertDate2Str( s_duration,
432                  p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate );
433     }
434     else
435     {
436         s_duration[0] = 0;
437     }
438     msg_Dbg( p_stream, "read box: \"mvhd\" creation %s modification %s time scale %d duration %s rate %f volume %f next track id %d",
439                   s_creation_time,
440                   s_modification_time,
441                   (uint32_t)p_box->data.p_mvhd->i_timescale,
442                   s_duration,
443                   (float)p_box->data.p_mvhd->i_rate / (1<<16 ),
444                   (float)p_box->data.p_mvhd->i_volume / 256 ,
445                   (uint32_t)p_box->data.p_mvhd->i_next_track_id );
446 #endif
447     MP4_READBOX_EXIT( 1 );
448 }
449
450 static int MP4_ReadBox_tkhd(  stream_t *p_stream, MP4_Box_t *p_box )
451 {
452     unsigned int i;
453 #ifdef MP4_VERBOSE
454     char s_creation_time[128];
455     char s_modification_time[128];
456     char s_duration[128];
457 #endif
458     MP4_READBOX_ENTER( MP4_Box_data_tkhd_t );
459
460     MP4_GETVERSIONFLAGS( p_box->data.p_tkhd );
461
462     if( p_box->data.p_tkhd->i_version )
463     {
464         MP4_GET8BYTES( p_box->data.p_tkhd->i_creation_time );
465         MP4_GET8BYTES( p_box->data.p_tkhd->i_modification_time );
466         MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
467         MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
468         MP4_GET8BYTES( p_box->data.p_tkhd->i_duration );
469     }
470     else
471     {
472         MP4_GET4BYTES( p_box->data.p_tkhd->i_creation_time );
473         MP4_GET4BYTES( p_box->data.p_tkhd->i_modification_time );
474         MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
475         MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
476         MP4_GET4BYTES( p_box->data.p_tkhd->i_duration );
477     }
478
479     for( i = 0; i < 2; i++ )
480     {
481         MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved2[i] );
482     }
483     MP4_GET2BYTES( p_box->data.p_tkhd->i_layer );
484     MP4_GET2BYTES( p_box->data.p_tkhd->i_predefined );
485     MP4_GET2BYTES( p_box->data.p_tkhd->i_volume );
486     MP4_GET2BYTES( p_box->data.p_tkhd->i_reserved3 );
487
488     for( i = 0; i < 9; i++ )
489     {
490         MP4_GET4BYTES( p_box->data.p_tkhd->i_matrix[i] );
491     }
492     MP4_GET4BYTES( p_box->data.p_tkhd->i_width );
493     MP4_GET4BYTES( p_box->data.p_tkhd->i_height );
494
495 #ifdef MP4_VERBOSE
496     MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
497     MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time );
498     MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration );
499
500     msg_Dbg( p_stream, "read box: \"tkhd\" creation %s modification %s duration %s track ID %d layer %d volume %f width %f height %f",
501                   s_creation_time,
502                   s_modification_time,
503                   s_duration,
504                   p_box->data.p_tkhd->i_track_ID,
505                   p_box->data.p_tkhd->i_layer,
506                   (float)p_box->data.p_tkhd->i_volume / 256 ,
507                   (float)p_box->data.p_tkhd->i_width / 65536,
508                   (float)p_box->data.p_tkhd->i_height / 65536 );
509 #endif
510     MP4_READBOX_EXIT( 1 );
511 }
512
513
514 static int MP4_ReadBox_mdhd( stream_t *p_stream, MP4_Box_t *p_box )
515 {
516     unsigned int i;
517     uint16_t i_language;
518 #ifdef MP4_VERBOSE
519     char s_creation_time[128];
520     char s_modification_time[128];
521     char s_duration[128];
522 #endif
523     MP4_READBOX_ENTER( MP4_Box_data_mdhd_t );
524
525     MP4_GETVERSIONFLAGS( p_box->data.p_mdhd );
526
527     if( p_box->data.p_mdhd->i_version )
528     {
529         MP4_GET8BYTES( p_box->data.p_mdhd->i_creation_time );
530         MP4_GET8BYTES( p_box->data.p_mdhd->i_modification_time );
531         MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
532         MP4_GET8BYTES( p_box->data.p_mdhd->i_duration );
533     }
534     else
535     {
536         MP4_GET4BYTES( p_box->data.p_mdhd->i_creation_time );
537         MP4_GET4BYTES( p_box->data.p_mdhd->i_modification_time );
538         MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
539         MP4_GET4BYTES( p_box->data.p_mdhd->i_duration );
540     }
541     i_language = GetWBE( p_peek );
542     for( i = 0; i < 3; i++ )
543     {
544         p_box->data.p_mdhd->i_language[i] =
545                     ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
546     }
547
548     MP4_GET2BYTES( p_box->data.p_mdhd->i_predefined );
549
550 #ifdef MP4_VERBOSE
551     MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time );
552     MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time );
553     MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration );
554     msg_Dbg( p_stream, "read box: \"mdhd\" creation %s modification %s time scale %d duration %s language %c%c%c",
555                   s_creation_time,
556                   s_modification_time,
557                   (uint32_t)p_box->data.p_mdhd->i_timescale,
558                   s_duration,
559                   p_box->data.p_mdhd->i_language[0],
560                   p_box->data.p_mdhd->i_language[1],
561                   p_box->data.p_mdhd->i_language[2] );
562 #endif
563     MP4_READBOX_EXIT( 1 );
564 }
565
566
567 static int MP4_ReadBox_hdlr( stream_t *p_stream, MP4_Box_t *p_box )
568 {
569     int32_t i_reserved;
570
571     MP4_READBOX_ENTER( MP4_Box_data_hdlr_t );
572
573     MP4_GETVERSIONFLAGS( p_box->data.p_hdlr );
574
575     MP4_GETFOURCC( p_box->data.p_hdlr->i_predefined );
576     MP4_GETFOURCC( p_box->data.p_hdlr->i_handler_type );
577
578     MP4_GET4BYTES( i_reserved );
579     MP4_GET4BYTES( i_reserved );
580     MP4_GET4BYTES( i_reserved );
581     p_box->data.p_hdlr->psz_name = NULL;
582
583     if( i_read > 0 )
584     {
585         p_box->data.p_hdlr->psz_name = calloc( sizeof( char ), i_read + 1 );
586
587         /* Yes, I love .mp4 :( */
588         if( p_box->data.p_hdlr->i_predefined == VLC_FOURCC( 'm', 'h', 'l', 'r' ) )
589         {
590             uint8_t i_len;
591             int i_copy;
592
593             MP4_GET1BYTE( i_len );
594             i_copy = __MIN( i_read, i_len );
595
596             memcpy( p_box->data.p_hdlr->psz_name, p_peek, i_copy );
597             p_box->data.p_hdlr->psz_name[i_copy] = '\0';
598         }
599         else
600         {
601             memcpy( p_box->data.p_hdlr->psz_name, p_peek, i_read );
602             p_box->data.p_hdlr->psz_name[i_read] = '\0';
603         }
604     }
605
606 #ifdef MP4_VERBOSE
607     msg_Dbg( p_stream, "read box: \"hdlr\" handler type %4.4s name %s",
608                        (char*)&p_box->data.p_hdlr->i_handler_type,
609                        p_box->data.p_hdlr->psz_name );
610
611 #endif
612     MP4_READBOX_EXIT( 1 );
613 }
614
615 static void MP4_FreeBox_hdlr( MP4_Box_t *p_box )
616 {
617     FREENULL( p_box->data.p_hdlr->psz_name );
618 }
619
620 static int MP4_ReadBox_vmhd( stream_t *p_stream, MP4_Box_t *p_box )
621 {
622     unsigned int i;
623
624     MP4_READBOX_ENTER( MP4_Box_data_vmhd_t );
625
626     MP4_GETVERSIONFLAGS( p_box->data.p_vmhd );
627
628     MP4_GET2BYTES( p_box->data.p_vmhd->i_graphics_mode );
629     for( i = 0; i < 3; i++ )
630     {
631         MP4_GET2BYTES( p_box->data.p_vmhd->i_opcolor[i] );
632     }
633
634 #ifdef MP4_VERBOSE
635     msg_Dbg( p_stream, "read box: \"vmhd\" graphics-mode %d opcolor (%d, %d, %d)",
636                       p_box->data.p_vmhd->i_graphics_mode,
637                       p_box->data.p_vmhd->i_opcolor[0],
638                       p_box->data.p_vmhd->i_opcolor[1],
639                       p_box->data.p_vmhd->i_opcolor[2] );
640 #endif
641     MP4_READBOX_EXIT( 1 );
642 }
643
644 static int MP4_ReadBox_smhd( stream_t *p_stream, MP4_Box_t *p_box )
645 {
646     MP4_READBOX_ENTER( MP4_Box_data_smhd_t );
647
648     MP4_GETVERSIONFLAGS( p_box->data.p_smhd );
649
650
651
652     MP4_GET2BYTES( p_box->data.p_smhd->i_balance );
653
654     MP4_GET2BYTES( p_box->data.p_smhd->i_reserved );
655
656 #ifdef MP4_VERBOSE
657     msg_Dbg( p_stream, "read box: \"smhd\" balance %f",
658                       (float)p_box->data.p_smhd->i_balance / 256 );
659 #endif
660     MP4_READBOX_EXIT( 1 );
661 }
662
663
664 static int MP4_ReadBox_hmhd( stream_t *p_stream, MP4_Box_t *p_box )
665 {
666     MP4_READBOX_ENTER( MP4_Box_data_hmhd_t );
667
668     MP4_GETVERSIONFLAGS( p_box->data.p_hmhd );
669
670     MP4_GET2BYTES( p_box->data.p_hmhd->i_max_PDU_size );
671     MP4_GET2BYTES( p_box->data.p_hmhd->i_avg_PDU_size );
672
673     MP4_GET4BYTES( p_box->data.p_hmhd->i_max_bitrate );
674     MP4_GET4BYTES( p_box->data.p_hmhd->i_avg_bitrate );
675
676     MP4_GET4BYTES( p_box->data.p_hmhd->i_reserved );
677
678 #ifdef MP4_VERBOSE
679     msg_Dbg( p_stream, "read box: \"hmhd\" maxPDU-size %d avgPDU-size %d max-bitrate %d avg-bitrate %d",
680                       p_box->data.p_hmhd->i_max_PDU_size,
681                       p_box->data.p_hmhd->i_avg_PDU_size,
682                       p_box->data.p_hmhd->i_max_bitrate,
683                       p_box->data.p_hmhd->i_avg_bitrate );
684 #endif
685     MP4_READBOX_EXIT( 1 );
686 }
687
688 static int MP4_ReadBox_url( stream_t *p_stream, MP4_Box_t *p_box )
689 {
690     MP4_READBOX_ENTER( MP4_Box_data_url_t );
691
692     MP4_GETVERSIONFLAGS( p_box->data.p_url );
693     MP4_GETSTRINGZ( p_box->data.p_url->psz_location );
694
695 #ifdef MP4_VERBOSE
696     msg_Dbg( p_stream, "read box: \"url\" url: %s",
697                        p_box->data.p_url->psz_location );
698
699 #endif
700     MP4_READBOX_EXIT( 1 );
701 }
702
703
704 static void MP4_FreeBox_url( MP4_Box_t *p_box )
705 {
706     FREENULL( p_box->data.p_url->psz_location )
707 }
708
709 static int MP4_ReadBox_urn( stream_t *p_stream, MP4_Box_t *p_box )
710 {
711     MP4_READBOX_ENTER( MP4_Box_data_urn_t );
712
713     MP4_GETVERSIONFLAGS( p_box->data.p_urn );
714
715     MP4_GETSTRINGZ( p_box->data.p_urn->psz_name );
716     MP4_GETSTRINGZ( p_box->data.p_urn->psz_location );
717
718 #ifdef MP4_VERBOSE
719     msg_Dbg( p_stream, "read box: \"urn\" name %s location %s",
720                       p_box->data.p_urn->psz_name,
721                       p_box->data.p_urn->psz_location );
722 #endif
723     MP4_READBOX_EXIT( 1 );
724 }
725 static void MP4_FreeBox_urn( MP4_Box_t *p_box )
726 {
727     FREENULL( p_box->data.p_urn->psz_name );
728     FREENULL( p_box->data.p_urn->psz_location );
729 }
730
731
732 static int MP4_ReadBox_dref( stream_t *p_stream, MP4_Box_t *p_box )
733 {
734     MP4_READBOX_ENTER( MP4_Box_data_dref_t );
735
736     MP4_GETVERSIONFLAGS( p_box->data.p_dref );
737
738     MP4_GET4BYTES( p_box->data.p_dref->i_entry_count );
739
740     stream_Seek( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 8 );
741     MP4_ReadBoxContainerRaw( p_stream, p_box );
742
743 #ifdef MP4_VERBOSE
744     msg_Dbg( p_stream, "read box: \"dref\" entry-count %d",
745                       p_box->data.p_dref->i_entry_count );
746
747 #endif
748     MP4_READBOX_EXIT( 1 );
749 }
750
751
752 static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box )
753 {
754     unsigned int i;
755     MP4_READBOX_ENTER( MP4_Box_data_stts_t );
756
757     MP4_GETVERSIONFLAGS( p_box->data.p_stts );
758     MP4_GET4BYTES( p_box->data.p_stts->i_entry_count );
759
760     p_box->data.p_stts->i_sample_count =
761         calloc( sizeof( uint32_t ), p_box->data.p_stts->i_entry_count );
762     p_box->data.p_stts->i_sample_delta =
763         calloc( sizeof( uint32_t ), p_box->data.p_stts->i_entry_count );
764
765     for( i = 0; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ )
766     {
767         MP4_GET4BYTES( p_box->data.p_stts->i_sample_count[i] );
768         MP4_GET4BYTES( p_box->data.p_stts->i_sample_delta[i] );
769     }
770
771 #ifdef MP4_VERBOSE
772     msg_Dbg( p_stream, "read box: \"stts\" entry-count %d",
773                       p_box->data.p_stts->i_entry_count );
774
775 #endif
776     MP4_READBOX_EXIT( 1 );
777 }
778
779 static void MP4_FreeBox_stts( MP4_Box_t *p_box )
780 {
781     FREENULL( p_box->data.p_stts->i_sample_count );
782     FREENULL( p_box->data.p_stts->i_sample_delta );
783 }
784
785 static int MP4_ReadBox_ctts( stream_t *p_stream, MP4_Box_t *p_box )
786 {
787     unsigned int i;
788     MP4_READBOX_ENTER( MP4_Box_data_ctts_t );
789
790     MP4_GETVERSIONFLAGS( p_box->data.p_ctts );
791
792     MP4_GET4BYTES( p_box->data.p_ctts->i_entry_count );
793
794     p_box->data.p_ctts->i_sample_count =
795         calloc( sizeof( uint32_t ), p_box->data.p_ctts->i_entry_count );
796     p_box->data.p_ctts->i_sample_offset =
797         calloc( sizeof( uint32_t ), p_box->data.p_ctts->i_entry_count );
798
799     for( i = 0; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ )
800     {
801         MP4_GET4BYTES( p_box->data.p_ctts->i_sample_count[i] );
802         MP4_GET4BYTES( p_box->data.p_ctts->i_sample_offset[i] );
803     }
804
805 #ifdef MP4_VERBOSE
806     msg_Dbg( p_stream, "read box: \"ctts\" entry-count %d",
807                       p_box->data.p_ctts->i_entry_count );
808
809 #endif
810     MP4_READBOX_EXIT( 1 );
811 }
812
813 static void MP4_FreeBox_ctts( MP4_Box_t *p_box )
814 {
815     FREENULL( p_box->data.p_ctts->i_sample_count );
816     FREENULL( p_box->data.p_ctts->i_sample_offset );
817 }
818
819 static int MP4_ReadLengthDescriptor( uint8_t **pp_peek, int64_t  *i_read )
820 {
821     unsigned int i_b;
822     unsigned int i_len = 0;
823     do
824     {
825         i_b = **pp_peek;
826
827         (*pp_peek)++;
828         (*i_read)--;
829         i_len = ( i_len << 7 ) + ( i_b&0x7f );
830     } while( i_b&0x80 );
831     return( i_len );
832 }
833
834 static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
835 {
836 #define es_descriptor p_box->data.p_esds->es_descriptor
837     unsigned int i_len;
838     unsigned int i_flags;
839     unsigned int i_type;
840
841     MP4_READBOX_ENTER( MP4_Box_data_esds_t );
842
843     MP4_GETVERSIONFLAGS( p_box->data.p_esds );
844
845
846     MP4_GET1BYTE( i_type );
847     if( i_type == 0x03 ) /* MP4ESDescrTag */
848     {
849         i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
850
851 #ifdef MP4_VERBOSE
852         msg_Dbg( p_stream, "found esds MPEG4ESDescr (%dBytes)",
853                  i_len );
854 #endif
855
856         MP4_GET2BYTES( es_descriptor.i_ES_ID );
857         MP4_GET1BYTE( i_flags );
858         es_descriptor.b_stream_dependence = ( (i_flags&0x80) != 0);
859         es_descriptor.b_url = ( (i_flags&0x40) != 0);
860         es_descriptor.b_OCRstream = ( (i_flags&0x20) != 0);
861
862         es_descriptor.i_stream_priority = i_flags&0x1f;
863         if( es_descriptor.b_stream_dependence )
864         {
865             MP4_GET2BYTES( es_descriptor.i_depend_on_ES_ID );
866         }
867         if( es_descriptor.b_url )
868         {
869             unsigned int i_len;
870
871             MP4_GET1BYTE( i_len );
872             es_descriptor.psz_URL = calloc( sizeof(char), i_len + 1 );
873             memcpy( es_descriptor.psz_URL, p_peek, i_len );
874             es_descriptor.psz_URL[i_len] = 0;
875             p_peek += i_len;
876             i_read -= i_len;
877         }
878         else
879         {
880             es_descriptor.psz_URL = NULL;
881         }
882         if( es_descriptor.b_OCRstream )
883         {
884             MP4_GET2BYTES( es_descriptor.i_OCR_ES_ID );
885         }
886         MP4_GET1BYTE( i_type ); /* get next type */
887     }
888
889     if( i_type != 0x04)/* MP4DecConfigDescrTag */
890     {
891          es_descriptor.p_decConfigDescr = NULL;
892          MP4_READBOX_EXIT( 1 ); /* rest isn't interesting up to now */
893     }
894
895     i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
896
897 #ifdef MP4_VERBOSE
898         msg_Dbg( p_stream, "found esds MP4DecConfigDescr (%dBytes)",
899                  i_len );
900 #endif
901
902     es_descriptor.p_decConfigDescr =
903             malloc( sizeof( MP4_descriptor_decoder_config_t ));
904
905     MP4_GET1BYTE( es_descriptor.p_decConfigDescr->i_objectTypeIndication );
906     MP4_GET1BYTE( i_flags );
907     es_descriptor.p_decConfigDescr->i_streamType = i_flags >> 2;
908     es_descriptor.p_decConfigDescr->b_upStream = ( i_flags >> 1 )&0x01;
909     MP4_GET3BYTES( es_descriptor.p_decConfigDescr->i_buffer_sizeDB );
910     MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_max_bitrate );
911     MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_avg_bitrate );
912     MP4_GET1BYTE( i_type );
913     if( i_type !=  0x05 )/* MP4DecSpecificDescrTag */
914     {
915         es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = 0;
916         es_descriptor.p_decConfigDescr->p_decoder_specific_info  = NULL;
917         MP4_READBOX_EXIT( 1 );
918     }
919
920     i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
921
922 #ifdef MP4_VERBOSE
923         msg_Dbg( p_stream, "found esds MP4DecSpecificDescr (%dBytes)",
924                  i_len );
925 #endif
926
927     es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = i_len;
928     es_descriptor.p_decConfigDescr->p_decoder_specific_info = malloc( i_len );
929     memcpy( es_descriptor.p_decConfigDescr->p_decoder_specific_info,
930             p_peek, i_len );
931
932     MP4_READBOX_EXIT( 1 );
933
934 #undef es_descriptor
935 }
936
937 static void MP4_FreeBox_esds( MP4_Box_t *p_box )
938 {
939     FREENULL( p_box->data.p_esds->es_descriptor.psz_URL );
940     if( p_box->data.p_esds->es_descriptor.p_decConfigDescr )
941     {
942         FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info );
943     }
944     FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr );
945 }
946
947 static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box )
948 {
949     MP4_Box_data_avcC_t *p_avcC;
950     int i;
951
952     MP4_READBOX_ENTER( MP4_Box_data_avcC_t );
953     p_avcC = p_box->data.p_avcC;
954
955     p_avcC->i_avcC = i_read;
956     if( p_avcC->i_avcC > 0 )
957     {
958         p_avcC->p_avcC = malloc( p_avcC->i_avcC );
959         memcpy( p_avcC->p_avcC, p_peek, i_read );
960     }
961
962     MP4_GET1BYTE( p_avcC->i_version );
963     MP4_GET1BYTE( p_avcC->i_profile );
964     MP4_GET1BYTE( p_avcC->i_profile_compatibility );
965     MP4_GET1BYTE( p_avcC->i_level );
966     MP4_GET1BYTE( p_avcC->i_reserved1 );
967     p_avcC->i_length_size = (p_avcC->i_reserved1&0x03) + 1;
968     p_avcC->i_reserved1 >>= 2;
969
970     MP4_GET1BYTE( p_avcC->i_reserved2 );
971     p_avcC->i_sps = p_avcC->i_reserved2&0x1f;
972     p_avcC->i_reserved2 >>= 5;
973
974     if( p_avcC->i_sps > 0 )
975     {
976         p_avcC->i_sps_length = malloc( p_avcC->i_sps * sizeof( uint16_t ) );
977         p_avcC->sps = malloc( p_avcC->i_sps * sizeof( uint8_t* ) );
978
979         for( i = 0; i < p_avcC->i_sps; i++ )
980         {
981             MP4_GET2BYTES( p_avcC->i_sps_length[i] );
982             p_avcC->sps[i] = malloc( p_avcC->i_sps_length[i] );
983             memcpy( p_avcC->sps[i], p_peek, p_avcC->i_sps_length[i] );
984
985             p_peek += p_avcC->i_sps_length[i];
986             i_read -= p_avcC->i_sps_length[i];
987         }
988     }
989
990     MP4_GET1BYTE( p_avcC->i_pps );
991     if( p_avcC->i_pps > 0 )
992     {
993         p_avcC->i_pps_length = malloc( p_avcC->i_pps * sizeof( uint16_t ) );
994         p_avcC->pps = malloc( p_avcC->i_pps * sizeof( uint8_t* ) );
995
996         for( i = 0; i < p_avcC->i_pps; i++ )
997         {
998             MP4_GET2BYTES( p_avcC->i_pps_length[i] );
999             p_avcC->pps[i] = malloc( p_avcC->i_pps_length[i] );
1000             memcpy( p_avcC->pps[i], p_peek, p_avcC->i_pps_length[i] );
1001
1002             p_peek += p_avcC->i_pps_length[i];
1003             i_read -= p_avcC->i_pps_length[i];
1004         }
1005     }
1006 #ifdef MP4_VERBOSE
1007     msg_Dbg( p_stream,
1008              "read box: \"avcC\" version=%d profile=0x%x level=0x%x length size=%d sps=%d pps=%d",
1009              p_avcC->i_version, p_avcC->i_profile, p_avcC->i_level,
1010              p_avcC->i_length_size,
1011              p_avcC->i_sps, p_avcC->i_pps );
1012     for( i = 0; i < p_avcC->i_sps; i++ )
1013     {
1014         msg_Dbg( p_stream, "         - sps[%d] length=%d",
1015                  i, p_avcC->i_sps_length[i] );
1016     }
1017     for( i = 0; i < p_avcC->i_pps; i++ )
1018     {
1019         msg_Dbg( p_stream, "         - pps[%d] length=%d",
1020                  i, p_avcC->i_pps_length[i] );
1021     }
1022
1023 #endif
1024     MP4_READBOX_EXIT( 1 );
1025 }
1026
1027 static void MP4_FreeBox_avcC( MP4_Box_t *p_box )
1028 {
1029     MP4_Box_data_avcC_t *p_avcC = p_box->data.p_avcC;
1030     int i;
1031
1032     if( p_avcC->i_avcC > 0 ) FREENULL( p_avcC->p_avcC );
1033
1034     for( i = 0; i < p_avcC->i_sps; i++ )
1035     {
1036         FREENULL( p_avcC->sps[i] );
1037     }
1038     for( i = 0; i < p_avcC->i_pps; i++ )
1039     {
1040         FREENULL( p_avcC->pps[i] );
1041     }
1042     if( p_avcC->i_sps > 0 ) FREENULL( p_avcC->sps );
1043     if( p_avcC->i_sps > 0 ) FREENULL( p_avcC->i_sps_length );
1044     if( p_avcC->i_pps > 0 ) FREENULL( p_avcC->pps );
1045     if( p_avcC->i_pps > 0 ) FREENULL( p_avcC->i_pps_length );
1046 }
1047
1048 static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
1049 {
1050     unsigned int i;
1051
1052     MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t );
1053     p_box->data.p_sample_soun->p_qt_description = NULL;
1054
1055     /* Sanity check needed because the "wave" box does also contain an
1056      * "mp4a" box that we don't understand. */
1057     if( i_read < 28 )
1058     {
1059         i_read -= 30;
1060         MP4_READBOX_EXIT( 1 );
1061     }
1062
1063     for( i = 0; i < 6 ; i++ )
1064     {
1065         MP4_GET1BYTE( p_box->data.p_sample_soun->i_reserved1[i] );
1066     }
1067
1068     MP4_GET2BYTES( p_box->data.p_sample_soun->i_data_reference_index );
1069
1070     /*
1071      * XXX hack -> produce a copy of the nearly complete chunk
1072      */
1073     if( i_read > 0 )
1074     {
1075         p_box->data.p_sample_soun->i_qt_description = i_read;
1076         p_box->data.p_sample_soun->p_qt_description = malloc( i_read );
1077         memcpy( p_box->data.p_sample_soun->p_qt_description, p_peek, i_read );
1078     }
1079     else
1080     {
1081         p_box->data.p_sample_soun->i_qt_description = 0;
1082         p_box->data.p_sample_soun->p_qt_description = NULL;
1083     }
1084
1085     MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_version );
1086     MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_revision_level );
1087     MP4_GET4BYTES( p_box->data.p_sample_soun->i_qt_vendor );
1088
1089     MP4_GET2BYTES( p_box->data.p_sample_soun->i_channelcount );
1090     MP4_GET2BYTES( p_box->data.p_sample_soun->i_samplesize );
1091     MP4_GET2BYTES( p_box->data.p_sample_soun->i_predefined );
1092     MP4_GET2BYTES( p_box->data.p_sample_soun->i_reserved3 );
1093     MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratehi );
1094     MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratelo );
1095
1096     if( p_box->data.p_sample_soun->i_qt_version == 1 && i_read >= 16 )
1097     {
1098         /* SoundDescriptionV1 */
1099         MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
1100         MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_packet );
1101         MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_frame );
1102         MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_sample );
1103
1104 #ifdef MP4_VERBOSE
1105         msg_Dbg( p_stream,
1106                  "read box: \"soun\" qt3+ sample/packet=%d bytes/packet=%d "
1107                  "bytes/frame=%d bytes/sample=%d",
1108                  p_box->data.p_sample_soun->i_sample_per_packet,
1109                  p_box->data.p_sample_soun->i_bytes_per_packet,
1110                  p_box->data.p_sample_soun->i_bytes_per_frame,
1111                  p_box->data.p_sample_soun->i_bytes_per_sample );
1112 #endif
1113         stream_Seek( p_stream, p_box->i_pos +
1114                         MP4_BOX_HEADERSIZE( p_box ) + 44 );
1115     }
1116     else if( p_box->data.p_sample_soun->i_qt_version == 2 && i_read >= 36 )
1117     {
1118         /* SoundDescriptionV2 */
1119         double f_sample_rate;
1120         int64_t dummy;
1121         uint32_t i_channel;
1122
1123         MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
1124         MP4_GET8BYTES( dummy );
1125         memcpy( &f_sample_rate, &dummy, 8 );
1126
1127         msg_Dbg( p_stream, "read box: %f Hz", f_sample_rate );
1128         p_box->data.p_sample_soun->i_sampleratehi = (int)f_sample_rate % 65536;
1129         p_box->data.p_sample_soun->i_sampleratelo = f_sample_rate / 65536;
1130
1131         MP4_GET4BYTES( i_channel );
1132         p_box->data.p_sample_soun->i_channelcount = i_channel;
1133
1134 #ifdef MP4_VERBOSE
1135         msg_Dbg( p_stream, "read box: \"soun\" V2" );
1136 #endif
1137         stream_Seek( p_stream, p_box->i_pos +
1138                         MP4_BOX_HEADERSIZE( p_box ) + 28 + 36 );
1139     }
1140     else
1141     {
1142         p_box->data.p_sample_soun->i_sample_per_packet = 0;
1143         p_box->data.p_sample_soun->i_bytes_per_packet = 0;
1144         p_box->data.p_sample_soun->i_bytes_per_frame = 0;
1145         p_box->data.p_sample_soun->i_bytes_per_sample = 0;
1146
1147         msg_Dbg( p_stream, "read box: \"soun\" mp4 or qt1/2 (rest="I64Fd")",
1148                  i_read );
1149         stream_Seek( p_stream, p_box->i_pos +
1150                         MP4_BOX_HEADERSIZE( p_box ) + 28 );
1151     }
1152
1153     if( p_box->i_type == FOURCC_drms )
1154     {
1155         p_box->data.p_sample_soun->p_drms =
1156             drms_alloc( p_stream->p_libvlc->psz_homedir );
1157
1158         if( p_box->data.p_sample_soun->p_drms == NULL )
1159         {
1160             msg_Err( p_stream, "drms_alloc() failed" );
1161         }
1162     }
1163
1164     if( p_box->i_type == FOURCC_samr || p_box->i_type == FOURCC_sawb )
1165     {
1166         /* Ignore channelcount for AMR (3gpp AMRSpecificBox) */
1167         p_box->data.p_sample_soun->i_channelcount = 1;
1168     }
1169
1170     if( p_box->i_type == FOURCC_alac )
1171     {
1172         if( p_box->data.p_sample_soun->p_qt_description )
1173             free( p_box->data.p_sample_soun->p_qt_description );
1174
1175         p_box->data.p_sample_soun->p_qt_description = malloc( i_read );
1176         p_box->data.p_sample_soun->i_qt_description = i_read;
1177         memcpy( p_box->data.p_sample_soun->p_qt_description, p_peek, i_read );
1178     }
1179     else
1180     {
1181         MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */
1182     }
1183
1184 #ifdef MP4_VERBOSE
1185     msg_Dbg( p_stream, "read box: \"soun\" in stsd channel %d "
1186              "sample size %d sample rate %f",
1187              p_box->data.p_sample_soun->i_channelcount,
1188              p_box->data.p_sample_soun->i_samplesize,
1189              (float)p_box->data.p_sample_soun->i_sampleratehi +
1190              (float)p_box->data.p_sample_soun->i_sampleratelo / 65536 );
1191
1192 #endif
1193     MP4_READBOX_EXIT( 1 );
1194 }
1195
1196
1197 static void MP4_FreeBox_sample_soun( MP4_Box_t *p_box )
1198 {
1199     FREENULL( p_box->data.p_sample_soun->p_qt_description );
1200
1201     if( p_box->i_type == FOURCC_drms )
1202     {
1203         if( p_box->data.p_sample_soun->p_drms )
1204         {
1205             drms_free( p_box->data.p_sample_soun->p_drms );
1206         }
1207     }
1208 }
1209
1210
1211 int MP4_ReadBox_sample_vide( stream_t *p_stream, MP4_Box_t *p_box )
1212 {
1213     unsigned int i;
1214
1215     MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t );
1216
1217     for( i = 0; i < 6 ; i++ )
1218     {
1219         MP4_GET1BYTE( p_box->data.p_sample_vide->i_reserved1[i] );
1220     }
1221
1222     MP4_GET2BYTES( p_box->data.p_sample_vide->i_data_reference_index );
1223
1224     /*
1225      * XXX hack -> produce a copy of the nearly complete chunk
1226      */
1227     if( i_read > 0 )
1228     {
1229         p_box->data.p_sample_vide->i_qt_image_description = i_read;
1230         p_box->data.p_sample_vide->p_qt_image_description = malloc( i_read );
1231         memcpy( p_box->data.p_sample_vide->p_qt_image_description,
1232                 p_peek, i_read );
1233     }
1234     else
1235     {
1236         p_box->data.p_sample_vide->i_qt_image_description = 0;
1237         p_box->data.p_sample_vide->p_qt_image_description = NULL;
1238     }
1239
1240     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_version );
1241     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_revision_level );
1242     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_vendor );
1243
1244     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_temporal_quality );
1245     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_spatial_quality );
1246
1247     MP4_GET2BYTES( p_box->data.p_sample_vide->i_width );
1248     MP4_GET2BYTES( p_box->data.p_sample_vide->i_height );
1249
1250     MP4_GET4BYTES( p_box->data.p_sample_vide->i_horizresolution );
1251     MP4_GET4BYTES( p_box->data.p_sample_vide->i_vertresolution );
1252
1253     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_data_size );
1254     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_frame_count );
1255
1256     memcpy( &p_box->data.p_sample_vide->i_compressorname, p_peek, 32 );
1257     p_peek += 32; i_read -= 32;
1258
1259     MP4_GET2BYTES( p_box->data.p_sample_vide->i_depth );
1260     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_color_table );
1261
1262     stream_Seek( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 78);
1263     MP4_ReadBoxContainerRaw( p_stream, p_box );
1264
1265 #ifdef MP4_VERBOSE
1266     msg_Dbg( p_stream, "read box: \"vide\" in stsd %dx%d depth %d",
1267                       p_box->data.p_sample_vide->i_width,
1268                       p_box->data.p_sample_vide->i_height,
1269                       p_box->data.p_sample_vide->i_depth );
1270
1271 #endif
1272     MP4_READBOX_EXIT( 1 );
1273 }
1274
1275
1276 void MP4_FreeBox_sample_vide( MP4_Box_t *p_box )
1277 {
1278     FREENULL( p_box->data.p_sample_vide->p_qt_image_description );
1279 }
1280
1281 static int MP4_ReadBox_sample_mp4s( stream_t *p_stream, MP4_Box_t *p_box )
1282 {
1283     stream_Seek( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 8 );
1284     MP4_ReadBoxContainerRaw( p_stream, p_box );
1285     return 1;
1286 }
1287
1288 static int MP4_ReadBox_sample_text( stream_t *p_stream, MP4_Box_t *p_box )
1289 {
1290     int32_t t;
1291
1292     MP4_READBOX_ENTER( MP4_Box_data_sample_text_t );
1293
1294     MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved1 );
1295     MP4_GET2BYTES( p_box->data.p_sample_text->i_reserved2 );
1296
1297     MP4_GET2BYTES( p_box->data.p_sample_text->i_data_reference_index );
1298
1299     MP4_GET4BYTES( p_box->data.p_sample_text->i_display_flags );
1300
1301     MP4_GET4BYTES( t );
1302     switch( t )
1303     {
1304         /* FIXME search right signification */
1305         case 1: // Center
1306             p_box->data.p_sample_text->i_justification_horizontal = 1;
1307             p_box->data.p_sample_text->i_justification_vertical = 1;
1308             break;
1309         case -1:    // Flush Right
1310             p_box->data.p_sample_text->i_justification_horizontal = -1;
1311             p_box->data.p_sample_text->i_justification_vertical = -1;
1312             break;
1313         case -2:    // Flush Left
1314             p_box->data.p_sample_text->i_justification_horizontal = 0;
1315             p_box->data.p_sample_text->i_justification_vertical = 0;
1316             break;
1317         case 0: // Flush Default
1318         default:
1319             p_box->data.p_sample_text->i_justification_horizontal = 1;
1320             p_box->data.p_sample_text->i_justification_vertical = -1;
1321             break;
1322     }
1323
1324     MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[0] );
1325     MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[1] );
1326     MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[2] );
1327     p_box->data.p_sample_text->i_background_color[3] = 0;
1328
1329     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_top );
1330     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_left );
1331     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_bottom );
1332     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_right );
1333
1334 #ifdef MP4_VERBOSE
1335     msg_Dbg( p_stream, "read box: \"text\" in stsd text" );
1336 #endif
1337     MP4_READBOX_EXIT( 1 );
1338 }
1339
1340 static int MP4_ReadBox_sample_tx3g( stream_t *p_stream, MP4_Box_t *p_box )
1341 {
1342     MP4_READBOX_ENTER( MP4_Box_data_sample_text_t );
1343
1344     MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved1 );
1345     MP4_GET2BYTES( p_box->data.p_sample_text->i_reserved2 );
1346
1347     MP4_GET2BYTES( p_box->data.p_sample_text->i_data_reference_index );
1348
1349     MP4_GET4BYTES( p_box->data.p_sample_text->i_display_flags );
1350
1351     MP4_GET1BYTE ( p_box->data.p_sample_text->i_justification_horizontal );
1352     MP4_GET1BYTE ( p_box->data.p_sample_text->i_justification_vertical );
1353
1354     MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[0] );
1355     MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[1] );
1356     MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[2] );
1357     MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[3] );
1358
1359     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_top );
1360     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_left );
1361     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_bottom );
1362     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_right );
1363
1364 #ifdef MP4_VERBOSE
1365     msg_Dbg( p_stream, "read box: \"text\" in stsd text" );
1366 #endif
1367     MP4_READBOX_EXIT( 1 );
1368 }
1369
1370
1371 #if 0
1372 /* We can't easily call it, and anyway ~ 20 bytes lost isn't a real problem */
1373 static void MP4_FreeBox_sample_text( MP4_Box_t *p_box )
1374 {
1375     FREENULL( p_box->data.p_sample_text->psz_text_name );
1376 }
1377 #endif
1378
1379
1380 static int MP4_ReadBox_stsd( stream_t *p_stream, MP4_Box_t *p_box )
1381 {
1382
1383     MP4_READBOX_ENTER( MP4_Box_data_stsd_t );
1384
1385     MP4_GETVERSIONFLAGS( p_box->data.p_stsd );
1386
1387     MP4_GET4BYTES( p_box->data.p_stsd->i_entry_count );
1388
1389     stream_Seek( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 8 );
1390
1391     MP4_ReadBoxContainerRaw( p_stream, p_box );
1392
1393 #ifdef MP4_VERBOSE
1394     msg_Dbg( p_stream, "read box: \"stsd\" entry-count %d",
1395                       p_box->data.p_stsd->i_entry_count );
1396
1397 #endif
1398     MP4_READBOX_EXIT( 1 );
1399 }
1400
1401
1402 static int MP4_ReadBox_stsz( stream_t *p_stream, MP4_Box_t *p_box )
1403 {
1404     unsigned int i;
1405
1406     MP4_READBOX_ENTER( MP4_Box_data_stsz_t );
1407
1408     MP4_GETVERSIONFLAGS( p_box->data.p_stsz );
1409
1410     MP4_GET4BYTES( p_box->data.p_stsz->i_sample_size );
1411
1412     MP4_GET4BYTES( p_box->data.p_stsz->i_sample_count );
1413
1414     p_box->data.p_stsz->i_entry_size =
1415         calloc( sizeof( uint32_t ), p_box->data.p_stsz->i_sample_count );
1416
1417     if( !p_box->data.p_stsz->i_sample_size )
1418     {
1419         for( i=0; (i<p_box->data.p_stsz->i_sample_count)&&(i_read >= 4 ); i++ )
1420         {
1421             MP4_GET4BYTES( p_box->data.p_stsz->i_entry_size[i] );
1422         }
1423     }
1424
1425 #ifdef MP4_VERBOSE
1426     msg_Dbg( p_stream, "read box: \"stsz\" sample-size %d sample-count %d",
1427                       p_box->data.p_stsz->i_sample_size,
1428                       p_box->data.p_stsz->i_sample_count );
1429
1430 #endif
1431     MP4_READBOX_EXIT( 1 );
1432 }
1433
1434 static void MP4_FreeBox_stsz( MP4_Box_t *p_box )
1435 {
1436     FREENULL( p_box->data.p_stsz->i_entry_size );
1437 }
1438
1439 static int MP4_ReadBox_stsc( stream_t *p_stream, MP4_Box_t *p_box )
1440 {
1441     unsigned int i;
1442
1443     MP4_READBOX_ENTER( MP4_Box_data_stsc_t );
1444
1445     MP4_GETVERSIONFLAGS( p_box->data.p_stsc );
1446
1447     MP4_GET4BYTES( p_box->data.p_stsc->i_entry_count );
1448
1449     p_box->data.p_stsc->i_first_chunk =
1450         calloc( sizeof( uint32_t ), p_box->data.p_stsc->i_entry_count );
1451     p_box->data.p_stsc->i_samples_per_chunk =
1452         calloc( sizeof( uint32_t ), p_box->data.p_stsc->i_entry_count );
1453     p_box->data.p_stsc->i_sample_description_index =
1454         calloc( sizeof( uint32_t ), p_box->data.p_stsc->i_entry_count );
1455
1456     for( i = 0; (i < p_box->data.p_stsc->i_entry_count )&&( i_read >= 12 );i++ )
1457     {
1458         MP4_GET4BYTES( p_box->data.p_stsc->i_first_chunk[i] );
1459         MP4_GET4BYTES( p_box->data.p_stsc->i_samples_per_chunk[i] );
1460         MP4_GET4BYTES( p_box->data.p_stsc->i_sample_description_index[i] );
1461     }
1462
1463 #ifdef MP4_VERBOSE
1464     msg_Dbg( p_stream, "read box: \"stsc\" entry-count %d",
1465                       p_box->data.p_stsc->i_entry_count );
1466
1467 #endif
1468     MP4_READBOX_EXIT( 1 );
1469 }
1470
1471 static void MP4_FreeBox_stsc( MP4_Box_t *p_box )
1472 {
1473     FREENULL( p_box->data.p_stsc->i_first_chunk );
1474     FREENULL( p_box->data.p_stsc->i_samples_per_chunk );
1475     FREENULL( p_box->data.p_stsc->i_sample_description_index );
1476 }
1477
1478 static int MP4_ReadBox_stco_co64( stream_t *p_stream, MP4_Box_t *p_box )
1479 {
1480     unsigned int i;
1481
1482     MP4_READBOX_ENTER( MP4_Box_data_co64_t );
1483
1484     MP4_GETVERSIONFLAGS( p_box->data.p_co64 );
1485
1486     MP4_GET4BYTES( p_box->data.p_co64->i_entry_count );
1487
1488     p_box->data.p_co64->i_chunk_offset =
1489         calloc( sizeof( uint64_t ), p_box->data.p_co64->i_entry_count );
1490
1491     for( i = 0; i < p_box->data.p_co64->i_entry_count; i++ )
1492     {
1493         if( p_box->i_type == FOURCC_stco )
1494         {
1495             if( i_read < 4 )
1496             {
1497                 break;
1498             }
1499             MP4_GET4BYTES( p_box->data.p_co64->i_chunk_offset[i] );
1500         }
1501         else
1502         {
1503             if( i_read < 8 )
1504             {
1505                 break;
1506             }
1507             MP4_GET8BYTES( p_box->data.p_co64->i_chunk_offset[i] );
1508         }
1509     }
1510
1511 #ifdef MP4_VERBOSE
1512     msg_Dbg( p_stream, "read box: \"co64\" entry-count %d",
1513                       p_box->data.p_co64->i_entry_count );
1514
1515 #endif
1516     MP4_READBOX_EXIT( 1 );
1517 }
1518
1519 static void MP4_FreeBox_stco_co64( MP4_Box_t *p_box )
1520 {
1521     FREENULL( p_box->data.p_co64->i_chunk_offset );
1522 }
1523
1524 static int MP4_ReadBox_stss( stream_t *p_stream, MP4_Box_t *p_box )
1525 {
1526     unsigned int i;
1527
1528     MP4_READBOX_ENTER( MP4_Box_data_stss_t );
1529
1530     MP4_GETVERSIONFLAGS( p_box->data.p_stss );
1531
1532     MP4_GET4BYTES( p_box->data.p_stss->i_entry_count );
1533
1534     p_box->data.p_stss->i_sample_number =
1535         calloc( sizeof( uint32_t ), p_box->data.p_stss->i_entry_count );
1536
1537     for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 4 ); i++ )
1538     {
1539
1540         MP4_GET4BYTES( p_box->data.p_stss->i_sample_number[i] );
1541         /* XXX in libmp4 sample begin at 0 */
1542         p_box->data.p_stss->i_sample_number[i]--;
1543     }
1544
1545 #ifdef MP4_VERBOSE
1546     msg_Dbg( p_stream, "read box: \"stss\" entry-count %d",
1547                       p_box->data.p_stss->i_entry_count );
1548
1549 #endif
1550     MP4_READBOX_EXIT( 1 );
1551 }
1552
1553 static void MP4_FreeBox_stss( MP4_Box_t *p_box )
1554 {
1555     FREENULL( p_box->data.p_stss->i_sample_number )
1556 }
1557
1558 static int MP4_ReadBox_stsh( stream_t *p_stream, MP4_Box_t *p_box )
1559 {
1560     unsigned int i;
1561
1562     MP4_READBOX_ENTER( MP4_Box_data_stsh_t );
1563
1564     MP4_GETVERSIONFLAGS( p_box->data.p_stsh );
1565
1566
1567     MP4_GET4BYTES( p_box->data.p_stsh->i_entry_count );
1568
1569     p_box->data.p_stsh->i_shadowed_sample_number =
1570         calloc( sizeof( uint32_t ), p_box->data.p_stsh->i_entry_count );
1571
1572     p_box->data.p_stsh->i_sync_sample_number =
1573         calloc( sizeof( uint32_t ), p_box->data.p_stsh->i_entry_count );
1574
1575
1576     for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 8 ); i++ )
1577     {
1578
1579         MP4_GET4BYTES( p_box->data.p_stsh->i_shadowed_sample_number[i] );
1580         MP4_GET4BYTES( p_box->data.p_stsh->i_sync_sample_number[i] );
1581     }
1582
1583 #ifdef MP4_VERBOSE
1584     msg_Dbg( p_stream, "read box: \"stsh\" entry-count %d",
1585                       p_box->data.p_stsh->i_entry_count );
1586 #endif
1587     MP4_READBOX_EXIT( 1 );
1588 }
1589
1590 static void MP4_FreeBox_stsh( MP4_Box_t *p_box )
1591 {
1592     FREENULL( p_box->data.p_stsh->i_shadowed_sample_number )
1593     FREENULL( p_box->data.p_stsh->i_sync_sample_number )
1594 }
1595
1596
1597 static int MP4_ReadBox_stdp( stream_t *p_stream, MP4_Box_t *p_box )
1598 {
1599     unsigned int i;
1600
1601     MP4_READBOX_ENTER( MP4_Box_data_stdp_t );
1602
1603     MP4_GETVERSIONFLAGS( p_box->data.p_stdp );
1604
1605     p_box->data.p_stdp->i_priority =
1606         calloc( sizeof( uint16_t ), i_read / 2 );
1607
1608     for( i = 0; i < i_read / 2 ; i++ )
1609     {
1610
1611         MP4_GET2BYTES( p_box->data.p_stdp->i_priority[i] );
1612     }
1613
1614 #ifdef MP4_VERBOSE
1615     msg_Dbg( p_stream, "read box: \"stdp\" entry-count "I64Fd,
1616                       i_read / 2 );
1617
1618 #endif
1619     MP4_READBOX_EXIT( 1 );
1620 }
1621
1622 static void MP4_FreeBox_stdp( MP4_Box_t *p_box )
1623 {
1624     FREENULL( p_box->data.p_stdp->i_priority )
1625 }
1626
1627 static int MP4_ReadBox_padb( stream_t *p_stream, MP4_Box_t *p_box )
1628 {
1629     unsigned int i;
1630
1631     MP4_READBOX_ENTER( MP4_Box_data_padb_t );
1632
1633     MP4_GETVERSIONFLAGS( p_box->data.p_padb );
1634
1635
1636     MP4_GET4BYTES( p_box->data.p_padb->i_sample_count );
1637
1638     p_box->data.p_padb->i_reserved1 =
1639         calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
1640     p_box->data.p_padb->i_pad2 =
1641         calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
1642     p_box->data.p_padb->i_reserved2 =
1643         calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
1644     p_box->data.p_padb->i_pad1 =
1645         calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
1646
1647
1648     for( i = 0; i < i_read / 2 ; i++ )
1649     {
1650         p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 7 )&0x01;
1651         p_box->data.p_padb->i_pad2[i] = ( (*p_peek) >> 4 )&0x07;
1652         p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 3 )&0x01;
1653         p_box->data.p_padb->i_pad1[i] = ( (*p_peek) )&0x07;
1654
1655         p_peek += 1; i_read -= 1;
1656     }
1657
1658 #ifdef MP4_VERBOSE
1659     msg_Dbg( p_stream, "read box: \"stdp\" entry-count "I64Fd,
1660                       i_read / 2 );
1661
1662 #endif
1663     MP4_READBOX_EXIT( 1 );
1664 }
1665
1666 static void MP4_FreeBox_padb( MP4_Box_t *p_box )
1667 {
1668     FREENULL( p_box->data.p_padb->i_reserved1 );
1669     FREENULL( p_box->data.p_padb->i_pad2 );
1670     FREENULL( p_box->data.p_padb->i_reserved2 );
1671     FREENULL( p_box->data.p_padb->i_pad1 );
1672 }
1673
1674 static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box )
1675 {
1676     unsigned int i;
1677
1678     MP4_READBOX_ENTER( MP4_Box_data_elst_t );
1679
1680     MP4_GETVERSIONFLAGS( p_box->data.p_elst );
1681
1682
1683     MP4_GET4BYTES( p_box->data.p_elst->i_entry_count );
1684
1685     p_box->data.p_elst->i_segment_duration =
1686         calloc( sizeof( uint64_t ), p_box->data.p_elst->i_entry_count );
1687     p_box->data.p_elst->i_media_time =
1688         calloc( sizeof( int64_t ),  p_box->data.p_elst->i_entry_count );
1689     p_box->data.p_elst->i_media_rate_integer =
1690         calloc( sizeof( uint16_t ), p_box->data.p_elst->i_entry_count );
1691     p_box->data.p_elst->i_media_rate_fraction=
1692         calloc( sizeof( uint16_t ), p_box->data.p_elst->i_entry_count );
1693
1694
1695     for( i = 0; i < p_box->data.p_elst->i_entry_count; i++ )
1696     {
1697         if( p_box->data.p_elst->i_version == 1 )
1698         {
1699
1700             MP4_GET8BYTES( p_box->data.p_elst->i_segment_duration[i] );
1701
1702             MP4_GET8BYTES( p_box->data.p_elst->i_media_time[i] );
1703         }
1704         else
1705         {
1706
1707             MP4_GET4BYTES( p_box->data.p_elst->i_segment_duration[i] );
1708
1709             MP4_GET4BYTES( p_box->data.p_elst->i_media_time[i] );
1710             p_box->data.p_elst->i_media_time[i] = (int32_t)p_box->data.p_elst->i_media_time[i];
1711         }
1712
1713         MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_integer[i] );
1714         MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_fraction[i] );
1715     }
1716
1717 #ifdef MP4_VERBOSE
1718     msg_Dbg( p_stream, "read box: \"elst\" entry-count "I64Fd, p_box->data.p_elst->i_entry_count );
1719 #endif
1720     MP4_READBOX_EXIT( 1 );
1721 }
1722
1723 static void MP4_FreeBox_elst( MP4_Box_t *p_box )
1724 {
1725     FREENULL( p_box->data.p_elst->i_segment_duration );
1726     FREENULL( p_box->data.p_elst->i_media_time );
1727     FREENULL( p_box->data.p_elst->i_media_rate_integer );
1728     FREENULL( p_box->data.p_elst->i_media_rate_fraction );
1729 }
1730
1731 static int MP4_ReadBox_cprt( stream_t *p_stream, MP4_Box_t *p_box )
1732 {
1733     unsigned int i_language;
1734     unsigned int i;
1735
1736     MP4_READBOX_ENTER( MP4_Box_data_cprt_t );
1737
1738     MP4_GETVERSIONFLAGS( p_box->data.p_cprt );
1739
1740     i_language = GetWBE( p_peek );
1741     for( i = 0; i < 3; i++ )
1742     {
1743         p_box->data.p_cprt->i_language[i] =
1744             ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
1745     }
1746     p_peek += 2; i_read -= 2;
1747     MP4_GETSTRINGZ( p_box->data.p_cprt->psz_notice );
1748
1749 #ifdef MP4_VERBOSE
1750     msg_Dbg( p_stream, "read box: \"cprt\" language %c%c%c notice %s",
1751                       p_box->data.p_cprt->i_language[0],
1752                       p_box->data.p_cprt->i_language[1],
1753                       p_box->data.p_cprt->i_language[2],
1754                       p_box->data.p_cprt->psz_notice );
1755
1756 #endif
1757     MP4_READBOX_EXIT( 1 );
1758 }
1759
1760 static void MP4_FreeBox_cprt( MP4_Box_t *p_box )
1761 {
1762     FREENULL( p_box->data.p_cprt->psz_notice );
1763 }
1764
1765
1766 static int MP4_ReadBox_dcom( stream_t *p_stream, MP4_Box_t *p_box )
1767 {
1768     MP4_READBOX_ENTER( MP4_Box_data_dcom_t );
1769
1770     MP4_GETFOURCC( p_box->data.p_dcom->i_algorithm );
1771 #ifdef MP4_VERBOSE
1772     msg_Dbg( p_stream,
1773              "read box: \"dcom\" compression algorithm : %4.4s",
1774                       (char*)&p_box->data.p_dcom->i_algorithm );
1775 #endif
1776     MP4_READBOX_EXIT( 1 );
1777 }
1778
1779 static int MP4_ReadBox_cmvd( stream_t *p_stream, MP4_Box_t *p_box )
1780 {
1781     MP4_READBOX_ENTER( MP4_Box_data_cmvd_t );
1782
1783     MP4_GET4BYTES( p_box->data.p_cmvd->i_uncompressed_size );
1784
1785     p_box->data.p_cmvd->i_compressed_size = i_read;
1786
1787     if( !( p_box->data.p_cmvd->p_data = malloc( i_read ) ) )
1788     {
1789         msg_Dbg( p_stream, "read box: \"cmvd\" not enough memory to load data" );
1790         return( 1 );
1791     }
1792
1793     /* now copy compressed data */
1794     memcpy( p_box->data.p_cmvd->p_data,
1795             p_peek,
1796             i_read);
1797
1798     p_box->data.p_cmvd->b_compressed = 1;
1799
1800 #ifdef MP4_VERBOSE
1801     msg_Dbg( p_stream, "read box: \"cmvd\" compressed data size %d",
1802                       p_box->data.p_cmvd->i_compressed_size );
1803 #endif
1804
1805     MP4_READBOX_EXIT( 1 );
1806 }
1807 static void MP4_FreeBox_cmvd( MP4_Box_t *p_box )
1808 {
1809     FREENULL( p_box->data.p_cmvd->p_data );
1810 }
1811
1812
1813 static int MP4_ReadBox_cmov( stream_t *p_stream, MP4_Box_t *p_box )
1814 {
1815     MP4_Box_t *p_dcom;
1816     MP4_Box_t *p_cmvd;
1817
1818 #ifdef HAVE_ZLIB_H
1819     stream_t *p_stream_memory;
1820     z_stream z_data;
1821     uint8_t *p_data;
1822     int i_result;
1823 #endif
1824
1825     if( !( p_box->data.p_cmov = malloc( sizeof( MP4_Box_data_cmov_t ) ) ) )
1826     {
1827         msg_Err( p_stream, "out of memory" );
1828         return 0;
1829     }
1830     memset( p_box->data.p_cmov, 0, sizeof( MP4_Box_data_cmov_t ) );
1831
1832     if( !p_box->p_father ||
1833         ( p_box->p_father->i_type != FOURCC_moov &&
1834           p_box->p_father->i_type != FOURCC_foov ) )
1835     {
1836         msg_Warn( p_stream, "Read box: \"cmov\" box alone" );
1837         return 1;
1838     }
1839
1840     if( !MP4_ReadBoxContainer( p_stream, p_box ) )
1841     {
1842         return 0;
1843     }
1844
1845     if( ( p_dcom = MP4_BoxGet( p_box, "dcom" ) ) == NULL ||
1846         ( p_cmvd = MP4_BoxGet( p_box, "cmvd" ) ) == NULL ||
1847         p_cmvd->data.p_cmvd->p_data == NULL )
1848     {
1849         msg_Warn( p_stream, "read box: \"cmov\" incomplete" );
1850         return 1;
1851     }
1852
1853     if( p_dcom->data.p_dcom->i_algorithm != FOURCC_zlib )
1854     {
1855         msg_Dbg( p_stream, "read box: \"cmov\" compression algorithm : %4.4s "
1856                  "not supported", (char*)&p_dcom->data.p_dcom->i_algorithm );
1857         return 1;
1858     }
1859
1860 #ifndef HAVE_ZLIB_H
1861     msg_Dbg( p_stream, "read box: \"cmov\" zlib unsupported" );
1862     return 1;
1863
1864 #else
1865     /* decompress data */
1866     /* allocate a new buffer */
1867     if( !( p_data = malloc( p_cmvd->data.p_cmvd->i_uncompressed_size ) ) )
1868     {
1869         msg_Err( p_stream, "read box: \"cmov\" not enough memory to "
1870                  "uncompress data" );
1871         return 1;
1872     }
1873     /* init default structures */
1874     z_data.next_in   = p_cmvd->data.p_cmvd->p_data;
1875     z_data.avail_in  = p_cmvd->data.p_cmvd->i_compressed_size;
1876     z_data.next_out  = p_data;
1877     z_data.avail_out = p_cmvd->data.p_cmvd->i_uncompressed_size;
1878     z_data.zalloc    = (alloc_func)Z_NULL;
1879     z_data.zfree     = (free_func)Z_NULL;
1880     z_data.opaque    = (voidpf)Z_NULL;
1881
1882     /* init zlib */
1883     if( inflateInit( &z_data ) != Z_OK )
1884     {
1885         msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
1886         free( p_data );
1887         return 1;
1888     }
1889
1890     /* uncompress */
1891     i_result = inflate( &z_data, Z_NO_FLUSH );
1892     if( i_result != Z_OK && i_result != Z_STREAM_END )
1893     {
1894         msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
1895         free( p_data );
1896         return 1;
1897     }
1898
1899     if( p_cmvd->data.p_cmvd->i_uncompressed_size != z_data.total_out )
1900     {
1901         msg_Warn( p_stream, "read box: \"cmov\" uncompressing data size "
1902                   "mismatch" );
1903     }
1904     p_cmvd->data.p_cmvd->i_uncompressed_size = z_data.total_out;
1905
1906     /* close zlib */
1907     if( inflateEnd( &z_data ) != Z_OK )
1908     {
1909         msg_Warn( p_stream, "read box: \"cmov\" error while uncompressing "
1910                   "data (ignored)" );
1911     }
1912
1913     free( p_cmvd->data.p_cmvd->p_data );
1914     p_cmvd->data.p_cmvd->p_data = p_data;
1915     p_cmvd->data.p_cmvd->b_compressed = 0;
1916
1917     msg_Dbg( p_stream, "read box: \"cmov\" box succesfully uncompressed" );
1918
1919     /* now create a memory stream */
1920     p_stream_memory =
1921         stream_MemoryNew( VLC_OBJECT(p_stream), p_cmvd->data.p_cmvd->p_data,
1922                           p_cmvd->data.p_cmvd->i_uncompressed_size, VLC_TRUE );
1923
1924     /* and read uncompressd moov */
1925     p_box->data.p_cmov->p_moov = MP4_ReadBox( p_stream_memory, NULL );
1926
1927     stream_Delete( p_stream_memory );
1928
1929 #ifdef MP4_VERBOSE
1930     msg_Dbg( p_stream, "read box: \"cmov\" compressed movie header completed");
1931 #endif
1932
1933     return p_box->data.p_cmov->p_moov ? 1 : 0;
1934 #endif /* HAVE_ZLIB_H */
1935 }
1936
1937 static int MP4_ReadBox_rdrf( stream_t *p_stream, MP4_Box_t *p_box )
1938 {
1939     uint32_t i_len;
1940     MP4_READBOX_ENTER( MP4_Box_data_rdrf_t );
1941
1942     MP4_GETVERSIONFLAGS( p_box->data.p_rdrf );
1943     MP4_GETFOURCC( p_box->data.p_rdrf->i_ref_type );
1944     MP4_GET4BYTES( i_len );
1945     if( i_len > 0 )
1946     {
1947         uint32_t i;
1948         p_box->data.p_rdrf->psz_ref = malloc( i_len  + 1);
1949         for( i = 0; i < i_len; i++ )
1950         {
1951             MP4_GET1BYTE( p_box->data.p_rdrf->psz_ref[i] );
1952         }
1953         p_box->data.p_rdrf->psz_ref[i_len] = '\0';
1954     }
1955     else
1956     {
1957         p_box->data.p_rdrf->psz_ref = NULL;
1958     }
1959
1960 #ifdef MP4_VERBOSE
1961     msg_Dbg( p_stream,
1962              "read box: \"rdrf\" type:%4.4s ref %s",
1963              (char*)&p_box->data.p_rdrf->i_ref_type,
1964              p_box->data.p_rdrf->psz_ref );
1965
1966 #endif
1967     MP4_READBOX_EXIT( 1 );
1968 }
1969
1970 static void MP4_FreeBox_rdrf( MP4_Box_t *p_box )
1971 {
1972     FREENULL( p_box->data.p_rdrf->psz_ref )
1973 }
1974
1975
1976 static int MP4_ReadBox_rmdr( stream_t *p_stream, MP4_Box_t *p_box )
1977 {
1978     MP4_READBOX_ENTER( MP4_Box_data_rmdr_t );
1979
1980     MP4_GETVERSIONFLAGS( p_box->data.p_rmdr );
1981
1982     MP4_GET4BYTES( p_box->data.p_rmdr->i_rate );
1983
1984 #ifdef MP4_VERBOSE
1985     msg_Dbg( p_stream,
1986              "read box: \"rmdr\" rate:%d",
1987              p_box->data.p_rmdr->i_rate );
1988 #endif
1989     MP4_READBOX_EXIT( 1 );
1990 }
1991
1992 static int MP4_ReadBox_rmqu( stream_t *p_stream, MP4_Box_t *p_box )
1993 {
1994     MP4_READBOX_ENTER( MP4_Box_data_rmqu_t );
1995
1996     MP4_GET4BYTES( p_box->data.p_rmqu->i_quality );
1997
1998 #ifdef MP4_VERBOSE
1999     msg_Dbg( p_stream,
2000              "read box: \"rmqu\" quality:%d",
2001              p_box->data.p_rmqu->i_quality );
2002 #endif
2003     MP4_READBOX_EXIT( 1 );
2004 }
2005
2006 static int MP4_ReadBox_rmvc( stream_t *p_stream, MP4_Box_t *p_box )
2007 {
2008     MP4_READBOX_ENTER( MP4_Box_data_rmvc_t );
2009     MP4_GETVERSIONFLAGS( p_box->data.p_rmvc );
2010
2011     MP4_GETFOURCC( p_box->data.p_rmvc->i_gestaltType );
2012     MP4_GET4BYTES( p_box->data.p_rmvc->i_val1 );
2013     MP4_GET4BYTES( p_box->data.p_rmvc->i_val2 );
2014     MP4_GET2BYTES( p_box->data.p_rmvc->i_checkType );
2015
2016 #ifdef MP4_VERBOSE
2017     msg_Dbg( p_stream,
2018              "read box: \"rmvc\" gestaltType:%4.4s val1:0x%x val2:0x%x checkType:0x%x",
2019              (char*)&p_box->data.p_rmvc->i_gestaltType,
2020              p_box->data.p_rmvc->i_val1,p_box->data.p_rmvc->i_val2,
2021              p_box->data.p_rmvc->i_checkType );
2022 #endif
2023
2024     MP4_READBOX_EXIT( 1 );
2025 }
2026
2027 static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box )
2028 {
2029     MP4_Box_t *p_drms_box = p_box;
2030
2031     MP4_READBOX_ENTER( uint8_t );
2032
2033     do
2034     {
2035         p_drms_box = p_drms_box->p_father;
2036     } while( p_drms_box && p_drms_box->i_type != FOURCC_drms );
2037
2038     if( p_drms_box && p_drms_box->data.p_sample_soun->p_drms )
2039     {
2040         int i_ret;
2041         if( config_GetInt( p_stream, "france" ) )
2042         {
2043             i_ret = -7;
2044         }
2045         else
2046         {
2047             i_ret= drms_init( p_drms_box->data.p_sample_soun->p_drms,
2048                                p_box->i_type, p_peek, i_read );
2049         }
2050         if( i_ret )
2051         {
2052             const char *psz_error;
2053
2054             switch( i_ret )
2055             {
2056                 case -1: psz_error = "unimplemented"; break;
2057                 case -2: psz_error = "invalid argument"; break;
2058                 case -3: psz_error = "could not get system key"; break;
2059                 case -4: psz_error = "could not get SCI data"; break;
2060                 case -5: psz_error = "no user key found in SCI data"; break;
2061                 case -6: psz_error = "invalid user key"; break;
2062                 case -7: psz_error = "you live in France"; break;
2063                 default: psz_error = "unknown error"; break;
2064             }
2065
2066             msg_Err( p_stream, "drms_init(%4.4s) failed (%s)",
2067                      (char *)&p_box->i_type, psz_error );
2068
2069             drms_free( p_drms_box->data.p_sample_soun->p_drms );
2070             p_drms_box->data.p_sample_soun->p_drms = NULL;
2071         }
2072     }
2073
2074     MP4_READBOX_EXIT( 1 );
2075 }
2076
2077 static int MP4_ReadBox_0xa9xxx( stream_t *p_stream, MP4_Box_t *p_box )
2078 {
2079     uint16_t i_length, i_dummy;
2080
2081     MP4_READBOX_ENTER( MP4_Box_data_0xa9xxx_t );
2082
2083     p_box->data.p_0xa9xxx->psz_text = NULL;
2084
2085     MP4_GET2BYTES( i_length );
2086
2087     if( i_length > 0 )
2088     {
2089         MP4_GET2BYTES( i_dummy );
2090         if( i_length > i_read ) i_length = i_read;
2091
2092         p_box->data.p_0xa9xxx->psz_text = malloc( i_length + 1 );
2093
2094         memcpy( p_box->data.p_0xa9xxx->psz_text,
2095                 p_peek, i_length );
2096         p_box->data.p_0xa9xxx->psz_text[i_length] = '\0';
2097
2098 #ifdef MP4_VERBOSE
2099         msg_Dbg( p_stream,
2100                  "read box: \"%4.4s\" text=`%s'",
2101                  (char*)&p_box->i_type,
2102                  p_box->data.p_0xa9xxx->psz_text );
2103 #endif
2104     }
2105     else
2106     {
2107         /* try iTune/Quicktime format, rewind to start */
2108         p_peek -= 2; i_read += 2;
2109         // we are expecting a 'data' box
2110         uint32_t i_data_len;
2111         uint32_t i_data_tag;
2112
2113         MP4_GET4BYTES( i_data_len );
2114         if( i_data_len > i_read ) i_data_len = i_read;
2115         MP4_GETFOURCC( i_data_tag );
2116         if( (i_data_len > 0) && (i_data_tag == VLC_FOURCC('d', 'a', 't', 'a')) )
2117         {
2118             /* data box contains a version/flags field */
2119             uint32_t i_version;
2120             uint32_t i_reserved;
2121             MP4_GET4BYTES( i_version );
2122             MP4_GET4BYTES( i_reserved );
2123             // version should be 0, flags should be 1 for text, 0 for data
2124             if( i_version == 0x00000001 )
2125             {
2126                 // the rest is the text
2127                 i_data_len -= 12;
2128                 p_box->data.p_0xa9xxx->psz_text = malloc( i_data_len + 1 );
2129
2130                 memcpy( p_box->data.p_0xa9xxx->psz_text,
2131                         p_peek, i_data_len );
2132                 p_box->data.p_0xa9xxx->psz_text[i_data_len] = '\0';
2133 #ifdef MP4_VERBOSE
2134         msg_Dbg( p_stream,
2135                  "read box: \"%4.4s\" text=`%s'",
2136                  (char*)&p_box->i_type,
2137                  p_box->data.p_0xa9xxx->psz_text );
2138 #endif
2139             }
2140             else
2141             {
2142                 // TODO: handle data values for ID3 tag values, track num or cover art,etc...
2143             }
2144         }
2145     }
2146
2147     MP4_READBOX_EXIT( 1 );
2148 }
2149 static void MP4_FreeBox_0xa9xxx( MP4_Box_t *p_box )
2150 {
2151     FREENULL( p_box->data.p_0xa9xxx->psz_text );
2152 }
2153
2154 /* Chapter support */
2155 static int MP4_ReadBox_chpl( stream_t *p_stream, MP4_Box_t *p_box )
2156 {
2157     MP4_Box_data_chpl_t *p_chpl;
2158     uint32_t i_dummy;
2159     int i;
2160     MP4_READBOX_ENTER( MP4_Box_data_chpl_t );
2161
2162     p_chpl = p_box->data.p_chpl;
2163
2164     MP4_GETVERSIONFLAGS( p_chpl );
2165
2166     MP4_GET4BYTES( i_dummy );
2167
2168     MP4_GET1BYTE( p_chpl->i_chapter );
2169
2170     for( i = 0; i < p_chpl->i_chapter; i++ )
2171     {
2172         uint64_t i_start;
2173         uint8_t i_len;
2174         int i_copy;
2175         MP4_GET8BYTES( i_start );
2176         MP4_GET1BYTE( i_len );
2177
2178         p_chpl->chapter[i].psz_name = malloc( i_len + 1 );
2179         i_copy = __MIN( i_len, i_read );
2180         if( i_copy > 0 )
2181             memcpy( p_chpl->chapter[i].psz_name, p_peek, i_copy );
2182         p_chpl->chapter[i].psz_name[i_copy] = '\0';
2183         p_chpl->chapter[i].i_start = i_start;
2184
2185         p_peek += i_copy;
2186         i_read -= i_copy;
2187     }
2188     /* Bubble sort by increasing start date */
2189     do
2190     {
2191         for( i = 0; i < p_chpl->i_chapter - 1; i++ )
2192         {
2193             if( p_chpl->chapter[i].i_start > p_chpl->chapter[i+1].i_start )
2194             {
2195                 char *psz = p_chpl->chapter[i+1].psz_name;
2196                 int64_t i64 = p_chpl->chapter[i+1].i_start;
2197
2198                 p_chpl->chapter[i+1].psz_name = p_chpl->chapter[i].psz_name;
2199                 p_chpl->chapter[i+1].i_start = p_chpl->chapter[i].i_start;
2200
2201                 p_chpl->chapter[i].psz_name = psz;
2202                 p_chpl->chapter[i].i_start = i64;
2203
2204                 i = -1;
2205                 break;
2206             }
2207         }
2208     } while( i == -1 );
2209
2210 #ifdef MP4_VERBOSE
2211     msg_Dbg( p_stream, "read box: \"chpl\" %d chapters",
2212                        p_chpl->i_chapter );
2213 #endif
2214     MP4_READBOX_EXIT( 1 );
2215 }
2216 static void MP4_FreeBox_chpl( MP4_Box_t *p_box )
2217 {
2218     MP4_Box_data_chpl_t *p_chpl = p_box->data.p_chpl;
2219     int i;
2220     for( i = 0; i < p_chpl->i_chapter; i++ )
2221         free( p_chpl->chapter[i].psz_name );
2222 }
2223
2224 static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
2225 {
2226     uint8_t meta_data[8];
2227     int i_actually_read;
2228
2229     // skip over box header
2230     i_actually_read = stream_Read( p_stream, meta_data, 8 );
2231     if( i_actually_read < 8 )
2232         return 0;
2233
2234     /* meta content starts with a 4 byte version/flags value (should be 0) */
2235     i_actually_read = stream_Read( p_stream, meta_data, 4 );
2236     if( i_actually_read < 4 )
2237         return 0;
2238
2239     /* then it behaves like a container */
2240     return MP4_ReadBoxContainerRaw( p_stream, p_box );
2241 }
2242
2243 /* For generic */
2244 static int MP4_ReadBox_default( stream_t *p_stream, MP4_Box_t *p_box )
2245 {
2246     if( !p_box->p_father )
2247     {
2248         goto unknown;
2249     }
2250     if( p_box->p_father->i_type == FOURCC_stsd )
2251     {
2252         MP4_Box_t *p_mdia = MP4_BoxGet( p_box, "../../../.." );
2253         MP4_Box_t *p_hdlr;
2254
2255         if( p_mdia == NULL || p_mdia->i_type != FOURCC_mdia ||
2256             (p_hdlr = MP4_BoxGet( p_mdia, "hdlr" )) == NULL )
2257         {
2258             goto unknown;
2259         }
2260         switch( p_hdlr->data.p_hdlr->i_handler_type )
2261         {
2262             case FOURCC_soun:
2263                 return MP4_ReadBox_sample_soun( p_stream, p_box );
2264             case FOURCC_vide:
2265                 return MP4_ReadBox_sample_vide( p_stream, p_box );
2266             case FOURCC_text:
2267                 return MP4_ReadBox_sample_text( p_stream, p_box );
2268             case FOURCC_tx3g:
2269                 return MP4_ReadBox_sample_tx3g( p_stream, p_box );
2270             default:
2271                 msg_Warn( p_stream,
2272                           "unknown handler type in stsd (uncompletetly loaded)" );
2273                 return 1;
2274         }
2275     }
2276
2277 unknown:
2278     msg_Warn( p_stream,
2279               "unknown box type %4.4s (uncompletetly loaded)",
2280               (char*)&p_box->i_type );
2281
2282     return 1;
2283 }
2284
2285 /**** ------------------------------------------------------------------- ****/
2286 /****                   "Higher level" Functions                          ****/
2287 /**** ------------------------------------------------------------------- ****/
2288
2289 static struct
2290 {
2291     uint32_t i_type;
2292     int  (*MP4_ReadBox_function )( stream_t *p_stream, MP4_Box_t *p_box );
2293     void (*MP4_FreeBox_function )( MP4_Box_t *p_box );
2294 } MP4_Box_Function [] =
2295 {
2296     /* Containers */
2297     { FOURCC_moov,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2298     { FOURCC_trak,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2299     { FOURCC_mdia,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2300     { FOURCC_moof,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2301     { FOURCC_minf,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2302     { FOURCC_stbl,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2303     { FOURCC_dinf,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2304     { FOURCC_edts,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2305     { FOURCC_udta,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2306     { FOURCC_nmhd,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2307     { FOURCC_hnti,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2308     { FOURCC_rmra,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2309     { FOURCC_rmda,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2310     { FOURCC_tref,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2311     { FOURCC_gmhd,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2312     { FOURCC_wave,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2313     { FOURCC_ilst,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2314
2315     /* specific box */
2316     { FOURCC_ftyp,  MP4_ReadBox_ftyp,       MP4_FreeBox_ftyp },
2317     { FOURCC_cmov,  MP4_ReadBox_cmov,       MP4_FreeBox_Common },
2318     { FOURCC_mvhd,  MP4_ReadBox_mvhd,       MP4_FreeBox_Common },
2319     { FOURCC_tkhd,  MP4_ReadBox_tkhd,       MP4_FreeBox_Common },
2320     { FOURCC_mdhd,  MP4_ReadBox_mdhd,       MP4_FreeBox_Common },
2321     { FOURCC_hdlr,  MP4_ReadBox_hdlr,       MP4_FreeBox_hdlr },
2322     { FOURCC_vmhd,  MP4_ReadBox_vmhd,       MP4_FreeBox_Common },
2323     { FOURCC_smhd,  MP4_ReadBox_smhd,       MP4_FreeBox_Common },
2324     { FOURCC_hmhd,  MP4_ReadBox_hmhd,       MP4_FreeBox_Common },
2325     { FOURCC_url,   MP4_ReadBox_url,        MP4_FreeBox_url },
2326     { FOURCC_urn,   MP4_ReadBox_urn,        MP4_FreeBox_urn },
2327     { FOURCC_dref,  MP4_ReadBox_dref,       MP4_FreeBox_Common },
2328     { FOURCC_stts,  MP4_ReadBox_stts,       MP4_FreeBox_stts },
2329     { FOURCC_ctts,  MP4_ReadBox_ctts,       MP4_FreeBox_ctts },
2330     { FOURCC_stsd,  MP4_ReadBox_stsd,       MP4_FreeBox_Common },
2331     { FOURCC_stsz,  MP4_ReadBox_stsz,       MP4_FreeBox_stsz },
2332     { FOURCC_stsc,  MP4_ReadBox_stsc,       MP4_FreeBox_stsc },
2333     { FOURCC_stco,  MP4_ReadBox_stco_co64,  MP4_FreeBox_stco_co64 },
2334     { FOURCC_co64,  MP4_ReadBox_stco_co64,  MP4_FreeBox_stco_co64 },
2335     { FOURCC_stss,  MP4_ReadBox_stss,       MP4_FreeBox_stss },
2336     { FOURCC_stsh,  MP4_ReadBox_stsh,       MP4_FreeBox_stsh },
2337     { FOURCC_stdp,  MP4_ReadBox_stdp,       MP4_FreeBox_stdp },
2338     { FOURCC_padb,  MP4_ReadBox_padb,       MP4_FreeBox_padb },
2339     { FOURCC_elst,  MP4_ReadBox_elst,       MP4_FreeBox_elst },
2340     { FOURCC_cprt,  MP4_ReadBox_cprt,       MP4_FreeBox_cprt },
2341     { FOURCC_esds,  MP4_ReadBox_esds,       MP4_FreeBox_esds },
2342     { FOURCC_dcom,  MP4_ReadBox_dcom,       MP4_FreeBox_Common },
2343     { FOURCC_cmvd,  MP4_ReadBox_cmvd,       MP4_FreeBox_cmvd },
2344     { FOURCC_avcC,  MP4_ReadBox_avcC,       MP4_FreeBox_avcC },
2345
2346     /* Nothing to do with this box */
2347     { FOURCC_mdat,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2348     { FOURCC_skip,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2349     { FOURCC_free,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2350     { FOURCC_wide,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2351
2352     /* for codecs */
2353     { FOURCC_soun,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2354     { FOURCC_ms02,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2355     { FOURCC_ms11,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2356     { FOURCC_ms55,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2357     { FOURCC__mp3,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2358     { FOURCC_mp4a,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2359     { FOURCC_twos,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2360     { FOURCC_sowt,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2361     { FOURCC_QDMC,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2362     { FOURCC_QDM2,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2363     { FOURCC_ima4,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2364     { FOURCC_IMA4,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2365     { FOURCC_dvi,   MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2366     { FOURCC_alaw,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2367     { FOURCC_ulaw,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2368     { FOURCC_raw,   MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2369     { FOURCC_MAC3,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2370     { FOURCC_MAC6,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2371     { FOURCC_Qclp,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2372     { FOURCC_samr,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2373     { FOURCC_sawb,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2374     { FOURCC_OggS,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2375     { FOURCC_alac,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2376
2377     { FOURCC_vide,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2378     { FOURCC_mp4v,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2379     { FOURCC_SVQ1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2380     { FOURCC_SVQ3,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2381     { FOURCC_ZyGo,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2382     { FOURCC_DIVX,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2383     { FOURCC_XVID,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2384     { FOURCC_h263,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2385     { FOURCC_s263,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2386     { FOURCC_cvid,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2387     { FOURCC_3IV1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2388     { FOURCC_3iv1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2389     { FOURCC_3IV2,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2390     { FOURCC_3iv2,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2391     { FOURCC_3IVD,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2392     { FOURCC_3ivd,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2393     { FOURCC_3VID,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2394     { FOURCC_3vid,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2395     { FOURCC_mjpa,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2396     { FOURCC_mjpb,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2397     { FOURCC_qdrw,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2398     { FOURCC_mp2v,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2399     { FOURCC_hdv2,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2400
2401     { FOURCC_mjqt,  MP4_ReadBox_default,        NULL }, /* found in mjpa/b */
2402     { FOURCC_mjht,  MP4_ReadBox_default,        NULL },
2403
2404     { FOURCC_dvc,   MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2405     { FOURCC_dvp,   MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2406     { FOURCC_VP31,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2407     { FOURCC_vp31,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2408     { FOURCC_h264,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2409
2410     { FOURCC_jpeg,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2411     { FOURCC_avc1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2412
2413     { FOURCC_yv12,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2414     { FOURCC_yuv2,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2415
2416     { FOURCC_mp4s,  MP4_ReadBox_sample_mp4s,    MP4_FreeBox_Common },
2417
2418     /* XXX there is 2 box where we could find this entry stbl and tref*/
2419     { FOURCC_hint,  MP4_ReadBox_default,        MP4_FreeBox_Common },
2420
2421     /* found in tref box */
2422     { FOURCC_dpnd,  MP4_ReadBox_default,   NULL },
2423     { FOURCC_ipir,  MP4_ReadBox_default,   NULL },
2424     { FOURCC_mpod,  MP4_ReadBox_default,   NULL },
2425
2426     /* found in hnti */
2427     { FOURCC_rtp,   MP4_ReadBox_default,   NULL },
2428
2429     /* found in rmra */
2430     { FOURCC_rdrf,  MP4_ReadBox_rdrf,           MP4_FreeBox_rdrf   },
2431     { FOURCC_rmdr,  MP4_ReadBox_rmdr,           MP4_FreeBox_Common },
2432     { FOURCC_rmqu,  MP4_ReadBox_rmqu,           MP4_FreeBox_Common },
2433     { FOURCC_rmvc,  MP4_ReadBox_rmvc,           MP4_FreeBox_Common },
2434
2435     { FOURCC_drms,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2436     { FOURCC_sinf,  MP4_ReadBoxContainer,       MP4_FreeBox_Common },
2437     { FOURCC_schi,  MP4_ReadBoxContainer,       MP4_FreeBox_Common },
2438     { FOURCC_user,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
2439     { FOURCC_key,   MP4_ReadBox_drms,           MP4_FreeBox_Common },
2440     { FOURCC_iviv,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
2441     { FOURCC_name,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
2442     { FOURCC_priv,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
2443
2444     /* found in udta */
2445     { FOURCC_0xa9nam,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2446     { FOURCC_0xa9aut,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2447     { FOURCC_0xa9cpy,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2448     { FOURCC_0xa9swr,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2449     { FOURCC_0xa9inf,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2450     { FOURCC_0xa9ART,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2451     { FOURCC_0xa9dir,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2452     { FOURCC_0xa9cmt,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2453     { FOURCC_0xa9req,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2454     { FOURCC_0xa9day,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2455     { FOURCC_0xa9des,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2456     { FOURCC_0xa9fmt,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2457     { FOURCC_0xa9prd,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2458     { FOURCC_0xa9prf,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2459     { FOURCC_0xa9src,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2460     { FOURCC_0xa9alb,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2461     { FOURCC_0xa9dis,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2462     { FOURCC_0xa9enc,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2463     { FOURCC_0xa9gen,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2464     { FOURCC_0xa9trk,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2465     { FOURCC_0xa9dsa,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2466     { FOURCC_0xa9hst,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2467     { FOURCC_0xa9url,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2468     { FOURCC_0xa9ope,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2469     { FOURCC_0xa9com,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2470
2471     { FOURCC_chpl,   MP4_ReadBox_chpl,          MP4_FreeBox_chpl },
2472
2473     /* iTunes/Quicktime meta info */
2474     { FOURCC_meta,  MP4_ReadBox_meta,       MP4_FreeBox_Common },
2475
2476     /* Last entry */
2477     { 0,             MP4_ReadBox_default,       NULL }
2478 };
2479
2480
2481
2482 /*****************************************************************************
2483  * MP4_ReadBox : parse the actual box and the children
2484  *  XXX : Do not go to the next box
2485  *****************************************************************************/
2486 static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father )
2487 {
2488     MP4_Box_t    *p_box = malloc( sizeof( MP4_Box_t ) );
2489     unsigned int i_index;
2490
2491     if( !MP4_ReadBoxCommon( p_stream, p_box ) )
2492     {
2493         msg_Warn( p_stream, "cannot read one box" );
2494         free( p_box );
2495         return NULL;
2496     }
2497     if( !p_box->i_size )
2498     {
2499         msg_Dbg( p_stream, "found an empty box (null size)" );
2500         free( p_box );
2501         return NULL;
2502     }
2503     p_box->p_father = p_father;
2504
2505     /* Now search function to call */
2506     for( i_index = 0; ; i_index++ )
2507     {
2508         if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
2509             ( MP4_Box_Function[i_index].i_type == 0 ) )
2510         {
2511             break;
2512         }
2513     }
2514
2515     if( !(MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box ) )
2516     {
2517         free( p_box );
2518         return NULL;
2519     }
2520
2521     return p_box;
2522 }
2523
2524 /*****************************************************************************
2525  * MP4_FreeBox : free memory after read with MP4_ReadBox and all
2526  * the children
2527  *****************************************************************************/
2528 void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
2529 {
2530     unsigned int i_index;
2531     MP4_Box_t    *p_child;
2532
2533     if( !p_box )
2534     {
2535         return; /* hehe */
2536     }
2537
2538     for( p_child = p_box->p_first; p_child != NULL; )
2539     {
2540         MP4_Box_t *p_next;
2541
2542         p_next = p_child->p_next;
2543         MP4_BoxFree( s, p_child );
2544         p_child = p_next;
2545     }
2546
2547     /* Now search function to call */
2548     if( p_box->data.p_data )
2549     {
2550         for( i_index = 0; ; i_index++ )
2551         {
2552             if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
2553                 ( MP4_Box_Function[i_index].i_type == 0 ) )
2554             {
2555                 break;
2556             }
2557         }
2558         if( MP4_Box_Function[i_index].MP4_FreeBox_function == NULL )
2559         {
2560             /* Should not happen */
2561             msg_Warn( s,
2562                       "cannot free box %4.4s, type unknown",
2563                       (char*)&p_box->i_type );
2564         }
2565         else
2566         {
2567             MP4_Box_Function[i_index].MP4_FreeBox_function( p_box );
2568         }
2569
2570         free( p_box->data.p_data );
2571     }
2572
2573     free( p_box );
2574 }
2575
2576 /*****************************************************************************
2577  * MP4_BoxGetRoot : Parse the entire file, and create all boxes in memory
2578  *****************************************************************************
2579  *  The first box is a virtual box "root" and is the father for all first
2580  *  level boxes for the file, a sort of virtual contener
2581  *****************************************************************************/
2582 MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
2583 {
2584     MP4_Box_t *p_root;
2585     stream_t *p_stream;
2586     int i_result;
2587
2588     p_root = malloc( sizeof( MP4_Box_t ) );
2589     p_root->i_pos = 0;
2590     p_root->i_type = VLC_FOURCC( 'r', 'o', 'o', 't' );
2591     p_root->i_shortsize = 1;
2592     p_root->i_size = stream_Size( s );
2593     CreateUUID( &p_root->i_uuid, p_root->i_type );
2594
2595     p_root->data.p_data = NULL;
2596     p_root->p_father = NULL;
2597     p_root->p_first  = NULL;
2598     p_root->p_last  = NULL;
2599     p_root->p_next   = NULL;
2600
2601     p_stream = s;
2602
2603     i_result = MP4_ReadBoxContainerRaw( p_stream, p_root );
2604
2605     if( i_result )
2606     {
2607         MP4_Box_t *p_child;
2608         MP4_Box_t *p_moov;
2609         MP4_Box_t *p_cmov;
2610
2611         /* check if there is a cmov, if so replace
2612           compressed moov by  uncompressed one */
2613         if( ( ( p_moov = MP4_BoxGet( p_root, "moov" ) ) &&
2614               ( p_cmov = MP4_BoxGet( p_root, "moov/cmov" ) ) ) ||
2615             ( ( p_moov = MP4_BoxGet( p_root, "foov" ) ) &&
2616               ( p_cmov = MP4_BoxGet( p_root, "foov/cmov" ) ) ) )
2617         {
2618             /* rename the compressed moov as a box to skip */
2619             p_moov->i_type = FOURCC_skip;
2620
2621             /* get uncompressed p_moov */
2622             p_moov = p_cmov->data.p_cmov->p_moov;
2623             p_cmov->data.p_cmov->p_moov = NULL;
2624
2625             /* make p_root father of this new moov */
2626             p_moov->p_father = p_root;
2627
2628             /* insert this new moov box as first child of p_root */
2629             p_moov->p_next = p_child = p_root->p_first;
2630             p_root->p_first = p_moov;
2631         }
2632     }
2633
2634     return p_root;
2635 }
2636
2637
2638 static void __MP4_BoxDumpStructure( stream_t *s,
2639                                     MP4_Box_t *p_box, unsigned int i_level )
2640 {
2641     MP4_Box_t *p_child;
2642
2643     if( !i_level )
2644     {
2645         msg_Dbg( s, "dumping root Box \"%4.4s\"",
2646                           (char*)&p_box->i_type );
2647     }
2648     else
2649     {
2650         char str[512];
2651         unsigned int i;
2652         memset( str, (uint8_t)' ', 512 );
2653         for( i = 0; i < i_level; i++ )
2654         {
2655             str[i*5] = '|';
2656         }
2657         sprintf( str + i_level * 5, "+ %4.4s size %d",
2658                       (char*)&p_box->i_type,
2659                       (uint32_t)p_box->i_size );
2660
2661         msg_Dbg( s, "%s", str );
2662     }
2663     p_child = p_box->p_first;
2664     while( p_child )
2665     {
2666         __MP4_BoxDumpStructure( s, p_child, i_level + 1 );
2667         p_child = p_child->p_next;
2668     }
2669 }
2670
2671 void MP4_BoxDumpStructure( stream_t *s, MP4_Box_t *p_box )
2672 {
2673     __MP4_BoxDumpStructure( s, p_box, 0 );
2674 }
2675
2676
2677
2678 /*****************************************************************************
2679  *****************************************************************************
2680  **
2681  **  High level methods to acces an MP4 file
2682  **
2683  *****************************************************************************
2684  *****************************************************************************/
2685 static void __get_token( char **ppsz_path, char **ppsz_token, int *pi_number )
2686 {
2687     size_t i_len ;
2688     if( !*ppsz_path[0] )
2689     {
2690         *ppsz_token = NULL;
2691         *pi_number = 0;
2692         return;
2693     }
2694     i_len = 0;
2695     while(  (*ppsz_path)[i_len] &&
2696             (*ppsz_path)[i_len] != '/' && (*ppsz_path)[i_len] != '[' )
2697     {
2698         i_len++;
2699     }
2700     if( !i_len && **ppsz_path == '/' )
2701     {
2702         i_len = 1;
2703     }
2704     *ppsz_token = malloc( i_len + 1 );
2705
2706     memcpy( *ppsz_token, *ppsz_path, i_len );
2707
2708     (*ppsz_token)[i_len] = '\0';
2709
2710     *ppsz_path += i_len;
2711
2712     if( **ppsz_path == '[' )
2713     {
2714         (*ppsz_path)++;
2715         *pi_number = strtol( *ppsz_path, NULL, 10 );
2716         while( **ppsz_path && **ppsz_path != ']' )
2717         {
2718             (*ppsz_path)++;
2719         }
2720         if( **ppsz_path == ']' )
2721         {
2722             (*ppsz_path)++;
2723         }
2724     }
2725     else
2726     {
2727         *pi_number = 0;
2728     }
2729     while( **ppsz_path == '/' )
2730     {
2731         (*ppsz_path)++;
2732     }
2733 }
2734
2735 static void __MP4_BoxGet( MP4_Box_t **pp_result,
2736                           MP4_Box_t *p_box, const char *psz_fmt, va_list args)
2737 {
2738     char *psz_dup;
2739     char    *psz_path;
2740
2741     if( !p_box )
2742     {
2743         *pp_result = NULL;
2744         return;
2745     }
2746
2747     vasprintf( &psz_path, psz_fmt, args );
2748
2749     if( !psz_path || !psz_path[0] )
2750     {
2751         FREENULL( psz_path );
2752         *pp_result = NULL;
2753         return;
2754     }
2755
2756 //    fprintf( stderr, "path:'%s'\n", psz_path );
2757     psz_dup = psz_path; /* keep this pointer, as it need to be unallocated */
2758     for( ; ; )
2759     {
2760         char *psz_token;
2761         int i_number;
2762
2763         __get_token( &psz_path, &psz_token, &i_number );
2764 //        fprintf( stderr, "path:'%s', token:'%s' n:%d\n",
2765 //                 psz_path,psz_token,i_number );
2766         if( !psz_token )
2767         {
2768             FREENULL( psz_token );
2769             free( psz_dup );
2770             *pp_result = p_box;
2771             return;
2772         }
2773         else
2774         if( !strcmp( psz_token, "/" ) )
2775         {
2776             /* Find root box */
2777             while( p_box && p_box->i_type != VLC_FOURCC( 'r', 'o', 'o', 't' ) )
2778             {
2779                 p_box = p_box->p_father;
2780             }
2781             if( !p_box )
2782             {
2783                 free( psz_token );
2784                 free( psz_dup );
2785                 *pp_result = NULL;
2786                 return;
2787             }
2788         }
2789         else
2790         if( !strcmp( psz_token, "." ) )
2791         {
2792             /* Do nothing */
2793         }
2794         else
2795         if( !strcmp( psz_token, ".." ) )
2796         {
2797             p_box = p_box->p_father;
2798             if( !p_box )
2799             {
2800                 free( psz_token );
2801                 free( psz_dup );
2802                 *pp_result = NULL;
2803                 return;
2804             }
2805         }
2806         else
2807         if( strlen( psz_token ) == 4 )
2808         {
2809             uint32_t i_fourcc;
2810             i_fourcc = VLC_FOURCC( psz_token[0], psz_token[1],
2811                                    psz_token[2], psz_token[3] );
2812             p_box = p_box->p_first;
2813             for( ; ; )
2814             {
2815                 if( !p_box )
2816                 {
2817                     free( psz_token );
2818                     free( psz_dup );
2819                     *pp_result = NULL;
2820                     return;
2821                 }
2822                 if( p_box->i_type == i_fourcc )
2823                 {
2824                     if( !i_number )
2825                     {
2826                         break;
2827                     }
2828                     i_number--;
2829                 }
2830                 p_box = p_box->p_next;
2831             }
2832         }
2833         else
2834         if( strlen( psz_token ) == 0 )
2835         {
2836             p_box = p_box->p_first;
2837             for( ; ; )
2838             {
2839                 if( !p_box )
2840                 {
2841                     free( psz_token );
2842                     free( psz_dup );
2843                     *pp_result = NULL;
2844                     return;
2845                 }
2846                 if( !i_number )
2847                 {
2848                     break;
2849                 }
2850                 i_number--;
2851                 p_box = p_box->p_next;
2852             }
2853         }
2854         else
2855         {
2856 //            fprintf( stderr, "Argg malformed token \"%s\"",psz_token );
2857             FREENULL( psz_token );
2858             free( psz_dup );
2859             *pp_result = NULL;
2860             return;
2861         }
2862
2863         free( psz_token );
2864     }
2865 }
2866
2867 /*****************************************************************************
2868  * MP4_BoxGet: find a box given a path relative to p_box
2869  *****************************************************************************
2870  * Path Format: . .. / as usual
2871  *              [number] to specifie box number ex: trak[12]
2872  *
2873  * ex: /moov/trak[12]
2874  *     ../mdia
2875  *****************************************************************************/
2876 MP4_Box_t *MP4_BoxGet( MP4_Box_t *p_box, const char *psz_fmt, ... )
2877 {
2878     va_list args;
2879     MP4_Box_t *p_result;
2880
2881     va_start( args, psz_fmt );
2882     __MP4_BoxGet( &p_result, p_box, psz_fmt, args );
2883     va_end( args );
2884
2885     return( p_result );
2886 }
2887
2888 /*****************************************************************************
2889  * MP4_BoxCount: count box given a path relative to p_box
2890  *****************************************************************************
2891  * Path Format: . .. / as usual
2892  *              [number] to specifie box number ex: trak[12]
2893  *
2894  * ex: /moov/trak[12]
2895  *     ../mdia
2896  *****************************************************************************/
2897 int MP4_BoxCount( MP4_Box_t *p_box, const char *psz_fmt, ... )
2898 {
2899     va_list args;
2900     int     i_count;
2901     MP4_Box_t *p_result, *p_next;
2902
2903     va_start( args, psz_fmt );
2904     __MP4_BoxGet( &p_result, p_box, psz_fmt, args );
2905     va_end( args );
2906     if( !p_result )
2907     {
2908         return( 0 );
2909     }
2910
2911     i_count = 1;
2912     for( p_next = p_result->p_next; p_next != NULL; p_next = p_next->p_next)
2913     {
2914         if( p_next->i_type == p_result->i_type)
2915         {
2916             i_count++;
2917         }
2918     }
2919     return( i_count );
2920 }