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