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