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