]> git.sesse.net Git - vlc/blob - modules/demux/mp4/libmp4.c
Don't include config.h from the headers - refs #297.
[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;
2059         if( config_GetInt( p_stream, "france" ) )
2060         {
2061             i_ret = -7;
2062         }
2063         else
2064         {
2065             i_ret= drms_init( p_drms_box->data.p_sample_soun->p_drms,
2066                                p_box->i_type, p_peek, i_read );
2067         }
2068         if( i_ret )
2069         {
2070             const char *psz_error;
2071
2072             switch( i_ret )
2073             {
2074                 case -1: psz_error = "unimplemented"; break;
2075                 case -2: psz_error = "invalid argument"; break;
2076                 case -3: psz_error = "could not get system key"; break;
2077                 case -4: psz_error = "could not get SCI data"; break;
2078                 case -5: psz_error = "no user key found in SCI data"; break;
2079                 case -6: psz_error = "invalid user key"; break;
2080                 case -7: psz_error = "you live in France"; break;
2081                 default: psz_error = "unknown error"; break;
2082             }
2083             if MP4_BOX_TYPE_ASCII()
2084                 msg_Err( p_stream, "drms_init(%4.4s) failed (%s)",
2085                         (char *)&p_box->i_type, psz_error );
2086             else
2087                 msg_Err( p_stream, "drms_init(c%3.3s) failed (%s)",
2088                         (char *)&p_box->i_type+1, psz_error );
2089
2090             drms_free( p_drms_box->data.p_sample_soun->p_drms );
2091             p_drms_box->data.p_sample_soun->p_drms = NULL;
2092         }
2093     }
2094
2095     MP4_READBOX_EXIT( 1 );
2096 }
2097
2098 static int MP4_ReadBox_0xa9xxx( stream_t *p_stream, MP4_Box_t *p_box )
2099 {
2100     uint16_t i_length, i_dummy;
2101
2102     MP4_READBOX_ENTER( MP4_Box_data_0xa9xxx_t );
2103
2104     p_box->data.p_0xa9xxx->psz_text = NULL;
2105
2106     MP4_GET2BYTES( i_length );
2107
2108     if( i_length > 0 )
2109     {
2110         MP4_GET2BYTES( i_dummy );
2111         if( i_length > i_read ) i_length = i_read;
2112
2113         p_box->data.p_0xa9xxx->psz_text = malloc( i_length + 1 );
2114
2115         memcpy( p_box->data.p_0xa9xxx->psz_text,
2116                 p_peek, i_length );
2117         p_box->data.p_0xa9xxx->psz_text[i_length] = '\0';
2118
2119 #ifdef MP4_VERBOSE
2120         msg_Dbg( p_stream,
2121                  "read box: \"c%3.3s\" text=`%s'",
2122                  ((char*)&p_box->i_type + 1),
2123                  p_box->data.p_0xa9xxx->psz_text );
2124 #endif
2125     }
2126     else
2127     {
2128         /* try iTune/Quicktime format, rewind to start */
2129         p_peek -= 2; i_read += 2;
2130         // we are expecting a 'data' box
2131         uint32_t i_data_len;
2132         uint32_t i_data_tag;
2133
2134         MP4_GET4BYTES( i_data_len );
2135         if( i_data_len > i_read ) i_data_len = i_read;
2136         MP4_GETFOURCC( i_data_tag );
2137         if( (i_data_len > 0) && (i_data_tag == VLC_FOURCC('d', 'a', 't', 'a')) )
2138         {
2139             /* data box contains a version/flags field */
2140             uint32_t i_version;
2141             uint32_t i_reserved;
2142             MP4_GET4BYTES( i_version );
2143             MP4_GET4BYTES( i_reserved );
2144             // version should be 0, flags should be 1 for text, 0 for data
2145             if( i_version == 0x00000001 )
2146             {
2147                 // the rest is the text
2148                 i_data_len -= 12;
2149                 p_box->data.p_0xa9xxx->psz_text = malloc( i_data_len + 1 );
2150
2151                 memcpy( p_box->data.p_0xa9xxx->psz_text,
2152                         p_peek, i_data_len );
2153                 p_box->data.p_0xa9xxx->psz_text[i_data_len] = '\0';
2154 #ifdef MP4_VERBOSE
2155         msg_Dbg( p_stream,
2156                  "read box: \"c%3.3s\" text=`%s'",
2157                  ((char*)&p_box->i_type+1),
2158                  p_box->data.p_0xa9xxx->psz_text );
2159 #endif
2160             }
2161             else
2162             {
2163                 // TODO: handle data values for ID3 tag values, track num or cover art,etc...
2164             }
2165         }
2166     }
2167
2168     MP4_READBOX_EXIT( 1 );
2169 }
2170 static void MP4_FreeBox_0xa9xxx( MP4_Box_t *p_box )
2171 {
2172     FREENULL( p_box->data.p_0xa9xxx->psz_text );
2173 }
2174
2175 /* Chapter support */
2176 static int MP4_ReadBox_chpl( stream_t *p_stream, MP4_Box_t *p_box )
2177 {
2178     MP4_Box_data_chpl_t *p_chpl;
2179     uint32_t i_dummy;
2180     int i;
2181     MP4_READBOX_ENTER( MP4_Box_data_chpl_t );
2182
2183     p_chpl = p_box->data.p_chpl;
2184
2185     MP4_GETVERSIONFLAGS( p_chpl );
2186
2187     MP4_GET4BYTES( i_dummy );
2188
2189     MP4_GET1BYTE( p_chpl->i_chapter );
2190
2191     for( i = 0; i < p_chpl->i_chapter; i++ )
2192     {
2193         uint64_t i_start;
2194         uint8_t i_len;
2195         int i_copy;
2196         MP4_GET8BYTES( i_start );
2197         MP4_GET1BYTE( i_len );
2198
2199         p_chpl->chapter[i].psz_name = malloc( i_len + 1 );
2200         i_copy = __MIN( i_len, i_read );
2201         if( i_copy > 0 )
2202             memcpy( p_chpl->chapter[i].psz_name, p_peek, i_copy );
2203         p_chpl->chapter[i].psz_name[i_copy] = '\0';
2204         p_chpl->chapter[i].i_start = i_start;
2205
2206         p_peek += i_copy;
2207         i_read -= i_copy;
2208     }
2209     /* Bubble sort by increasing start date */
2210     do
2211     {
2212         for( i = 0; i < p_chpl->i_chapter - 1; i++ )
2213         {
2214             if( p_chpl->chapter[i].i_start > p_chpl->chapter[i+1].i_start )
2215             {
2216                 char *psz = p_chpl->chapter[i+1].psz_name;
2217                 int64_t i64 = p_chpl->chapter[i+1].i_start;
2218
2219                 p_chpl->chapter[i+1].psz_name = p_chpl->chapter[i].psz_name;
2220                 p_chpl->chapter[i+1].i_start = p_chpl->chapter[i].i_start;
2221
2222                 p_chpl->chapter[i].psz_name = psz;
2223                 p_chpl->chapter[i].i_start = i64;
2224
2225                 i = -1;
2226                 break;
2227             }
2228         }
2229     } while( i == -1 );
2230
2231 #ifdef MP4_VERBOSE
2232     msg_Dbg( p_stream, "read box: \"chpl\" %d chapters",
2233                        p_chpl->i_chapter );
2234 #endif
2235     MP4_READBOX_EXIT( 1 );
2236 }
2237 static void MP4_FreeBox_chpl( MP4_Box_t *p_box )
2238 {
2239     MP4_Box_data_chpl_t *p_chpl = p_box->data.p_chpl;
2240     int i;
2241     for( i = 0; i < p_chpl->i_chapter; i++ )
2242         free( p_chpl->chapter[i].psz_name );
2243 }
2244
2245 static int MP4_ReadBox_tref_generic( stream_t *p_stream, MP4_Box_t *p_box )
2246 {
2247     unsigned int i;
2248     MP4_READBOX_ENTER( MP4_Box_data_tref_generic_t );
2249
2250     p_box->data.p_tref_generic->i_track_ID = NULL;
2251     p_box->data.p_tref_generic->i_entry_count = i_read / sizeof(uint32_t);
2252     if( p_box->data.p_tref_generic->i_entry_count > 0 )
2253         p_box->data.p_tref_generic->i_track_ID = malloc( p_box->data.p_tref_generic->i_entry_count * sizeof(uint32_t) );
2254
2255     for( i = 0; i < p_box->data.p_tref_generic->i_entry_count; i++ )
2256     {
2257         MP4_GET4BYTES( p_box->data.p_tref_generic->i_track_ID[i] );
2258     }
2259 #ifdef MP4_VERBOSE
2260         msg_Dbg( p_stream, "read box: \"chap\" %d references",
2261                  p_box->data.p_tref_generic->i_entry_count );
2262 #endif
2263
2264     MP4_READBOX_EXIT( 1 );
2265 }
2266 static void MP4_FreeBox_tref_generic( MP4_Box_t *p_box )
2267 {
2268     FREENULL( p_box->data.p_tref_generic->i_track_ID );
2269 }
2270
2271 static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
2272 {
2273     uint8_t meta_data[8];
2274     int i_actually_read;
2275
2276     // skip over box header
2277     i_actually_read = stream_Read( p_stream, meta_data, 8 );
2278     if( i_actually_read < 8 )
2279         return 0;
2280
2281     /* meta content starts with a 4 byte version/flags value (should be 0) */
2282     i_actually_read = stream_Read( p_stream, meta_data, 4 );
2283     if( i_actually_read < 4 )
2284         return 0;
2285
2286     /* then it behaves like a container */
2287     return MP4_ReadBoxContainerRaw( p_stream, p_box );
2288 }
2289
2290 /* For generic */
2291 static int MP4_ReadBox_default( stream_t *p_stream, MP4_Box_t *p_box )
2292 {
2293     if( !p_box->p_father )
2294     {
2295         goto unknown;
2296     }
2297     if( p_box->p_father->i_type == FOURCC_stsd )
2298     {
2299         MP4_Box_t *p_mdia = MP4_BoxGet( p_box, "../../../.." );
2300         MP4_Box_t *p_hdlr;
2301
2302         if( p_mdia == NULL || p_mdia->i_type != FOURCC_mdia ||
2303             (p_hdlr = MP4_BoxGet( p_mdia, "hdlr" )) == NULL )
2304         {
2305             goto unknown;
2306         }
2307         switch( p_hdlr->data.p_hdlr->i_handler_type )
2308         {
2309             case FOURCC_soun:
2310                 return MP4_ReadBox_sample_soun( p_stream, p_box );
2311             case FOURCC_vide:
2312                 return MP4_ReadBox_sample_vide( p_stream, p_box );
2313             case FOURCC_text:
2314                 return MP4_ReadBox_sample_text( p_stream, p_box );
2315             case FOURCC_tx3g:
2316                 return MP4_ReadBox_sample_tx3g( p_stream, p_box );
2317             default:
2318                 msg_Warn( p_stream,
2319                           "unknown handler type in stsd (incompletely loaded)" );
2320                 return 1;
2321         }
2322     }
2323
2324 unknown:
2325     if MP4_BOX_TYPE_ASCII()
2326         msg_Warn( p_stream,
2327                 "unknown box type %4.4s (incompletely loaded)",
2328                 (char*)&p_box->i_type );
2329     else
2330         msg_Warn( p_stream,
2331                 "unknown box type c%3.3s (incompletely loaded)",
2332                 (char*)&p_box->i_type+1 );
2333
2334     return 1;
2335 }
2336
2337 /**** ------------------------------------------------------------------- ****/
2338 /****                   "Higher level" Functions                          ****/
2339 /**** ------------------------------------------------------------------- ****/
2340
2341 static struct
2342 {
2343     uint32_t i_type;
2344     int  (*MP4_ReadBox_function )( stream_t *p_stream, MP4_Box_t *p_box );
2345     void (*MP4_FreeBox_function )( MP4_Box_t *p_box );
2346 } MP4_Box_Function [] =
2347 {
2348     /* Containers */
2349     { FOURCC_moov,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2350     { FOURCC_trak,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2351     { FOURCC_mdia,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2352     { FOURCC_moof,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2353     { FOURCC_minf,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2354     { FOURCC_stbl,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2355     { FOURCC_dinf,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2356     { FOURCC_edts,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2357     { FOURCC_udta,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2358     { FOURCC_nmhd,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2359     { FOURCC_hnti,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2360     { FOURCC_rmra,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2361     { FOURCC_rmda,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2362     { FOURCC_tref,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2363     { FOURCC_gmhd,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2364     { FOURCC_wave,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2365     { FOURCC_ilst,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2366
2367     /* specific box */
2368     { FOURCC_ftyp,  MP4_ReadBox_ftyp,       MP4_FreeBox_ftyp },
2369     { FOURCC_cmov,  MP4_ReadBox_cmov,       MP4_FreeBox_Common },
2370     { FOURCC_mvhd,  MP4_ReadBox_mvhd,       MP4_FreeBox_Common },
2371     { FOURCC_tkhd,  MP4_ReadBox_tkhd,       MP4_FreeBox_Common },
2372     { FOURCC_mdhd,  MP4_ReadBox_mdhd,       MP4_FreeBox_Common },
2373     { FOURCC_hdlr,  MP4_ReadBox_hdlr,       MP4_FreeBox_hdlr },
2374     { FOURCC_vmhd,  MP4_ReadBox_vmhd,       MP4_FreeBox_Common },
2375     { FOURCC_smhd,  MP4_ReadBox_smhd,       MP4_FreeBox_Common },
2376     { FOURCC_hmhd,  MP4_ReadBox_hmhd,       MP4_FreeBox_Common },
2377     { FOURCC_url,   MP4_ReadBox_url,        MP4_FreeBox_url },
2378     { FOURCC_urn,   MP4_ReadBox_urn,        MP4_FreeBox_urn },
2379     { FOURCC_dref,  MP4_ReadBox_dref,       MP4_FreeBox_Common },
2380     { FOURCC_stts,  MP4_ReadBox_stts,       MP4_FreeBox_stts },
2381     { FOURCC_ctts,  MP4_ReadBox_ctts,       MP4_FreeBox_ctts },
2382     { FOURCC_stsd,  MP4_ReadBox_stsd,       MP4_FreeBox_Common },
2383     { FOURCC_stsz,  MP4_ReadBox_stsz,       MP4_FreeBox_stsz },
2384     { FOURCC_stsc,  MP4_ReadBox_stsc,       MP4_FreeBox_stsc },
2385     { FOURCC_stco,  MP4_ReadBox_stco_co64,  MP4_FreeBox_stco_co64 },
2386     { FOURCC_co64,  MP4_ReadBox_stco_co64,  MP4_FreeBox_stco_co64 },
2387     { FOURCC_stss,  MP4_ReadBox_stss,       MP4_FreeBox_stss },
2388     { FOURCC_stsh,  MP4_ReadBox_stsh,       MP4_FreeBox_stsh },
2389     { FOURCC_stdp,  MP4_ReadBox_stdp,       MP4_FreeBox_stdp },
2390     { FOURCC_padb,  MP4_ReadBox_padb,       MP4_FreeBox_padb },
2391     { FOURCC_elst,  MP4_ReadBox_elst,       MP4_FreeBox_elst },
2392     { FOURCC_cprt,  MP4_ReadBox_cprt,       MP4_FreeBox_cprt },
2393     { FOURCC_esds,  MP4_ReadBox_esds,       MP4_FreeBox_esds },
2394     { FOURCC_dcom,  MP4_ReadBox_dcom,       MP4_FreeBox_Common },
2395     { FOURCC_cmvd,  MP4_ReadBox_cmvd,       MP4_FreeBox_cmvd },
2396     { FOURCC_avcC,  MP4_ReadBox_avcC,       MP4_FreeBox_avcC },
2397
2398     /* Nothing to do with this box */
2399     { FOURCC_mdat,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2400     { FOURCC_skip,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2401     { FOURCC_free,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2402     { FOURCC_wide,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2403
2404     /* for codecs */
2405     { FOURCC_soun,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2406     { FOURCC_ms02,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2407     { FOURCC_ms11,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2408     { FOURCC_ms55,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2409     { FOURCC__mp3,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2410     { FOURCC_mp4a,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2411     { FOURCC_twos,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2412     { FOURCC_sowt,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2413     { FOURCC_QDMC,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2414     { FOURCC_QDM2,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2415     { FOURCC_ima4,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2416     { FOURCC_IMA4,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2417     { FOURCC_dvi,   MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2418     { FOURCC_alaw,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2419     { FOURCC_ulaw,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2420     { FOURCC_raw,   MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2421     { FOURCC_MAC3,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2422     { FOURCC_MAC6,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2423     { FOURCC_Qclp,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2424     { FOURCC_samr,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2425     { FOURCC_sawb,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2426     { FOURCC_OggS,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2427     { FOURCC_alac,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2428
2429     { FOURCC_vide,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2430     { FOURCC_mp4v,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2431     { FOURCC_SVQ1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2432     { FOURCC_SVQ3,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2433     { FOURCC_ZyGo,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2434     { FOURCC_DIVX,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2435     { FOURCC_XVID,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2436     { FOURCC_h263,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2437     { FOURCC_s263,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2438     { FOURCC_cvid,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2439     { FOURCC_3IV1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2440     { FOURCC_3iv1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2441     { FOURCC_3IV2,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2442     { FOURCC_3iv2,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2443     { FOURCC_3IVD,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2444     { FOURCC_3ivd,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2445     { FOURCC_3VID,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2446     { FOURCC_3vid,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2447     { FOURCC_mjpa,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2448     { FOURCC_mjpb,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2449     { FOURCC_qdrw,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2450     { FOURCC_mp2v,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2451     { FOURCC_hdv2,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2452
2453     { FOURCC_mjqt,  MP4_ReadBox_default,        NULL }, /* found in mjpa/b */
2454     { FOURCC_mjht,  MP4_ReadBox_default,        NULL },
2455
2456     { FOURCC_dvc,   MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2457     { FOURCC_dvp,   MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2458     { FOURCC_VP31,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2459     { FOURCC_vp31,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2460     { FOURCC_h264,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2461
2462     { FOURCC_jpeg,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2463     { FOURCC_avc1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2464
2465     { FOURCC_yv12,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2466     { FOURCC_yuv2,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
2467
2468     { FOURCC_mp4s,  MP4_ReadBox_sample_mp4s,    MP4_FreeBox_Common },
2469
2470     /* XXX there is 2 box where we could find this entry stbl and tref*/
2471     { FOURCC_hint,  MP4_ReadBox_default,        MP4_FreeBox_Common },
2472
2473     /* found in tref box */
2474     { FOURCC_dpnd,  MP4_ReadBox_default,   NULL },
2475     { FOURCC_ipir,  MP4_ReadBox_default,   NULL },
2476     { FOURCC_mpod,  MP4_ReadBox_default,   NULL },
2477     { FOURCC_chap,  MP4_ReadBox_tref_generic,   MP4_FreeBox_tref_generic },
2478
2479     /* found in hnti */
2480     { FOURCC_rtp,   MP4_ReadBox_default,   NULL },
2481
2482     /* found in rmra */
2483     { FOURCC_rdrf,  MP4_ReadBox_rdrf,           MP4_FreeBox_rdrf   },
2484     { FOURCC_rmdr,  MP4_ReadBox_rmdr,           MP4_FreeBox_Common },
2485     { FOURCC_rmqu,  MP4_ReadBox_rmqu,           MP4_FreeBox_Common },
2486     { FOURCC_rmvc,  MP4_ReadBox_rmvc,           MP4_FreeBox_Common },
2487
2488     { FOURCC_drms,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
2489     { FOURCC_sinf,  MP4_ReadBoxContainer,       MP4_FreeBox_Common },
2490     { FOURCC_schi,  MP4_ReadBoxContainer,       MP4_FreeBox_Common },
2491     { FOURCC_user,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
2492     { FOURCC_key,   MP4_ReadBox_drms,           MP4_FreeBox_Common },
2493     { FOURCC_iviv,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
2494     { FOURCC_name,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
2495     { FOURCC_priv,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
2496
2497     /* found in udta */
2498     { FOURCC_0xa9nam,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2499     { FOURCC_0xa9aut,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2500     { FOURCC_0xa9cpy,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2501     { FOURCC_0xa9swr,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2502     { FOURCC_0xa9inf,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2503     { FOURCC_0xa9ART,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2504     { FOURCC_0xa9dir,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2505     { FOURCC_0xa9cmt,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2506     { FOURCC_0xa9req,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2507     { FOURCC_0xa9day,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2508     { FOURCC_0xa9des,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2509     { FOURCC_0xa9fmt,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2510     { FOURCC_0xa9prd,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2511     { FOURCC_0xa9prf,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2512     { FOURCC_0xa9src,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2513     { FOURCC_0xa9alb,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2514     { FOURCC_0xa9dis,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2515     { FOURCC_0xa9enc,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2516     { FOURCC_0xa9gen,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2517     { FOURCC_0xa9trk,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2518     { FOURCC_0xa9dsa,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2519     { FOURCC_0xa9hst,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2520     { FOURCC_0xa9url,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2521     { FOURCC_0xa9ope,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2522     { FOURCC_0xa9com,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
2523
2524     { FOURCC_chpl,   MP4_ReadBox_chpl,          MP4_FreeBox_chpl },
2525
2526     /* iTunes/Quicktime meta info */
2527     { FOURCC_meta,  MP4_ReadBox_meta,       MP4_FreeBox_Common },
2528
2529     /* Last entry */
2530     { 0,             MP4_ReadBox_default,       NULL }
2531 };
2532
2533
2534
2535 /*****************************************************************************
2536  * MP4_ReadBox : parse the actual box and the children
2537  *  XXX : Do not go to the next box
2538  *****************************************************************************/
2539 static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father )
2540 {
2541     MP4_Box_t    *p_box = malloc( sizeof( MP4_Box_t ) );
2542     unsigned int i_index;
2543
2544     if( !MP4_ReadBoxCommon( p_stream, p_box ) )
2545     {
2546         msg_Warn( p_stream, "cannot read one box" );
2547         free( p_box );
2548         return NULL;
2549     }
2550     if( !p_box->i_size )
2551     {
2552         msg_Dbg( p_stream, "found an empty box (null size)" );
2553         free( p_box );
2554         return NULL;
2555     }
2556     p_box->p_father = p_father;
2557
2558     /* Now search function to call */
2559     for( i_index = 0; ; i_index++ )
2560     {
2561         if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
2562             ( MP4_Box_Function[i_index].i_type == 0 ) )
2563         {
2564             break;
2565         }
2566     }
2567
2568     if( !(MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box ) )
2569     {
2570         free( p_box );
2571         return NULL;
2572     }
2573
2574     return p_box;
2575 }
2576
2577 /*****************************************************************************
2578  * MP4_FreeBox : free memory after read with MP4_ReadBox and all
2579  * the children
2580  *****************************************************************************/
2581 void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
2582 {
2583     unsigned int i_index;
2584     MP4_Box_t    *p_child;
2585
2586     if( !p_box )
2587     {
2588         return; /* hehe */
2589     }
2590
2591     for( p_child = p_box->p_first; p_child != NULL; )
2592     {
2593         MP4_Box_t *p_next;
2594
2595         p_next = p_child->p_next;
2596         MP4_BoxFree( s, p_child );
2597         p_child = p_next;
2598     }
2599
2600     /* Now search function to call */
2601     if( p_box->data.p_data )
2602     {
2603         for( i_index = 0; ; i_index++ )
2604         {
2605             if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
2606                 ( MP4_Box_Function[i_index].i_type == 0 ) )
2607             {
2608                 break;
2609             }
2610         }
2611         if( MP4_Box_Function[i_index].MP4_FreeBox_function == NULL )
2612         {
2613             /* Should not happen */
2614             if MP4_BOX_TYPE_ASCII()
2615                 msg_Warn( s,
2616                         "cannot free box %4.4s, type unknown",
2617                         (char*)&p_box->i_type );
2618             else
2619                 msg_Warn( s,
2620                         "cannot free box c%3.3s, type unknown",
2621                         (char*)&p_box->i_type+1 );
2622         }
2623         else
2624         {
2625             MP4_Box_Function[i_index].MP4_FreeBox_function( p_box );
2626         }
2627
2628         free( p_box->data.p_data );
2629     }
2630
2631     free( p_box );
2632 }
2633
2634 /*****************************************************************************
2635  * MP4_BoxGetRoot : Parse the entire file, and create all boxes in memory
2636  *****************************************************************************
2637  *  The first box is a virtual box "root" and is the father for all first
2638  *  level boxes for the file, a sort of virtual contener
2639  *****************************************************************************/
2640 MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
2641 {
2642     MP4_Box_t *p_root;
2643     stream_t *p_stream;
2644     int i_result;
2645
2646     p_root = malloc( sizeof( MP4_Box_t ) );
2647     p_root->i_pos = 0;
2648     p_root->i_type = VLC_FOURCC( 'r', 'o', 'o', 't' );
2649     p_root->i_shortsize = 1;
2650     p_root->i_size = stream_Size( s );
2651     CreateUUID( &p_root->i_uuid, p_root->i_type );
2652
2653     p_root->data.p_data = NULL;
2654     p_root->p_father = NULL;
2655     p_root->p_first  = NULL;
2656     p_root->p_last  = NULL;
2657     p_root->p_next   = NULL;
2658
2659     p_stream = s;
2660
2661     i_result = MP4_ReadBoxContainerRaw( p_stream, p_root );
2662
2663     if( i_result )
2664     {
2665         MP4_Box_t *p_child;
2666         MP4_Box_t *p_moov;
2667         MP4_Box_t *p_cmov;
2668
2669         /* check if there is a cmov, if so replace
2670           compressed moov by  uncompressed one */
2671         if( ( ( p_moov = MP4_BoxGet( p_root, "moov" ) ) &&
2672               ( p_cmov = MP4_BoxGet( p_root, "moov/cmov" ) ) ) ||
2673             ( ( p_moov = MP4_BoxGet( p_root, "foov" ) ) &&
2674               ( p_cmov = MP4_BoxGet( p_root, "foov/cmov" ) ) ) )
2675         {
2676             /* rename the compressed moov as a box to skip */
2677             p_moov->i_type = FOURCC_skip;
2678
2679             /* get uncompressed p_moov */
2680             p_moov = p_cmov->data.p_cmov->p_moov;
2681             p_cmov->data.p_cmov->p_moov = NULL;
2682
2683             /* make p_root father of this new moov */
2684             p_moov->p_father = p_root;
2685
2686             /* insert this new moov box as first child of p_root */
2687             p_moov->p_next = p_child = p_root->p_first;
2688             p_root->p_first = p_moov;
2689         }
2690     }
2691
2692     return p_root;
2693 }
2694
2695
2696 static void __MP4_BoxDumpStructure( stream_t *s,
2697                                     MP4_Box_t *p_box, unsigned int i_level )
2698 {
2699     MP4_Box_t *p_child;
2700
2701     if( !i_level )
2702     {
2703         if MP4_BOX_TYPE_ASCII()
2704             msg_Dbg( s, "dumping root Box \"%4.4s\"",
2705                               (char*)&p_box->i_type );
2706         else
2707             msg_Dbg( s, "dumping root Box \"c%3.3s\"",
2708                               (char*)&p_box->i_type+1 );
2709     }
2710     else
2711     {
2712         char str[512];
2713         unsigned int i;
2714         memset( str, (uint8_t)' ', 512 );
2715         for( i = 0; i < i_level; i++ )
2716         {
2717             str[i*5] = '|';
2718         }
2719         if MP4_BOX_TYPE_ASCII()
2720             sprintf( str + i_level * 5, "+ %4.4s size %d",
2721                         (char*)&p_box->i_type, (uint32_t)p_box->i_size );
2722         else
2723             sprintf( str + i_level * 5, "+ c%3.3s size %d",
2724                         (char*)&p_box->i_type+1, (uint32_t)p_box->i_size );
2725         msg_Dbg( s, "%s", str );
2726     }
2727     p_child = p_box->p_first;
2728     while( p_child )
2729     {
2730         __MP4_BoxDumpStructure( s, p_child, i_level + 1 );
2731         p_child = p_child->p_next;
2732     }
2733 }
2734
2735 void MP4_BoxDumpStructure( stream_t *s, MP4_Box_t *p_box )
2736 {
2737     __MP4_BoxDumpStructure( s, p_box, 0 );
2738 }
2739
2740
2741
2742 /*****************************************************************************
2743  *****************************************************************************
2744  **
2745  **  High level methods to acces an MP4 file
2746  **
2747  *****************************************************************************
2748  *****************************************************************************/
2749 static void __get_token( char **ppsz_path, char **ppsz_token, int *pi_number )
2750 {
2751     size_t i_len ;
2752     if( !*ppsz_path[0] )
2753     {
2754         *ppsz_token = NULL;
2755         *pi_number = 0;
2756         return;
2757     }
2758     i_len = 0;
2759     while(  (*ppsz_path)[i_len] &&
2760             (*ppsz_path)[i_len] != '/' && (*ppsz_path)[i_len] != '[' )
2761     {
2762         i_len++;
2763     }
2764     if( !i_len && **ppsz_path == '/' )
2765     {
2766         i_len = 1;
2767     }
2768     *ppsz_token = malloc( i_len + 1 );
2769
2770     memcpy( *ppsz_token, *ppsz_path, i_len );
2771
2772     (*ppsz_token)[i_len] = '\0';
2773
2774     *ppsz_path += i_len;
2775
2776     if( **ppsz_path == '[' )
2777     {
2778         (*ppsz_path)++;
2779         *pi_number = strtol( *ppsz_path, NULL, 10 );
2780         while( **ppsz_path && **ppsz_path != ']' )
2781         {
2782             (*ppsz_path)++;
2783         }
2784         if( **ppsz_path == ']' )
2785         {
2786             (*ppsz_path)++;
2787         }
2788     }
2789     else
2790     {
2791         *pi_number = 0;
2792     }
2793     while( **ppsz_path == '/' )
2794     {
2795         (*ppsz_path)++;
2796     }
2797 }
2798
2799 static void __MP4_BoxGet( MP4_Box_t **pp_result,
2800                           MP4_Box_t *p_box, const char *psz_fmt, va_list args)
2801 {
2802     char *psz_dup;
2803     char    *psz_path;
2804
2805     if( !p_box )
2806     {
2807         *pp_result = NULL;
2808         return;
2809     }
2810
2811     vasprintf( &psz_path, psz_fmt, args );
2812
2813     if( !psz_path || !psz_path[0] )
2814     {
2815         FREENULL( psz_path );
2816         *pp_result = NULL;
2817         return;
2818     }
2819
2820 //    fprintf( stderr, "path:'%s'\n", psz_path );
2821     psz_dup = psz_path; /* keep this pointer, as it need to be unallocated */
2822     for( ; ; )
2823     {
2824         char *psz_token;
2825         int i_number;
2826
2827         __get_token( &psz_path, &psz_token, &i_number );
2828 //        fprintf( stderr, "path:'%s', token:'%s' n:%d\n",
2829 //                 psz_path,psz_token,i_number );
2830         if( !psz_token )
2831         {
2832             FREENULL( psz_token );
2833             free( psz_dup );
2834             *pp_result = p_box;
2835             return;
2836         }
2837         else
2838         if( !strcmp( psz_token, "/" ) )
2839         {
2840             /* Find root box */
2841             while( p_box && p_box->i_type != VLC_FOURCC( 'r', 'o', 'o', 't' ) )
2842             {
2843                 p_box = p_box->p_father;
2844             }
2845             if( !p_box )
2846             {
2847                 free( psz_token );
2848                 free( psz_dup );
2849                 *pp_result = NULL;
2850                 return;
2851             }
2852         }
2853         else
2854         if( !strcmp( psz_token, "." ) )
2855         {
2856             /* Do nothing */
2857         }
2858         else
2859         if( !strcmp( psz_token, ".." ) )
2860         {
2861             p_box = p_box->p_father;
2862             if( !p_box )
2863             {
2864                 free( psz_token );
2865                 free( psz_dup );
2866                 *pp_result = NULL;
2867                 return;
2868             }
2869         }
2870         else
2871         if( strlen( psz_token ) == 4 )
2872         {
2873             uint32_t i_fourcc;
2874             i_fourcc = VLC_FOURCC( psz_token[0], psz_token[1],
2875                                    psz_token[2], psz_token[3] );
2876             p_box = p_box->p_first;
2877             for( ; ; )
2878             {
2879                 if( !p_box )
2880                 {
2881                     free( psz_token );
2882                     free( psz_dup );
2883                     *pp_result = NULL;
2884                     return;
2885                 }
2886                 if( p_box->i_type == i_fourcc )
2887                 {
2888                     if( !i_number )
2889                     {
2890                         break;
2891                     }
2892                     i_number--;
2893                 }
2894                 p_box = p_box->p_next;
2895             }
2896         }
2897         else
2898         if( strlen( psz_token ) == 0 )
2899         {
2900             p_box = p_box->p_first;
2901             for( ; ; )
2902             {
2903                 if( !p_box )
2904                 {
2905                     free( psz_token );
2906                     free( psz_dup );
2907                     *pp_result = NULL;
2908                     return;
2909                 }
2910                 if( !i_number )
2911                 {
2912                     break;
2913                 }
2914                 i_number--;
2915                 p_box = p_box->p_next;
2916             }
2917         }
2918         else
2919         {
2920 //            fprintf( stderr, "Argg malformed token \"%s\"",psz_token );
2921             FREENULL( psz_token );
2922             free( psz_dup );
2923             *pp_result = NULL;
2924             return;
2925         }
2926
2927         free( psz_token );
2928     }
2929 }
2930
2931 /*****************************************************************************
2932  * MP4_BoxGet: find a box given a path relative to p_box
2933  *****************************************************************************
2934  * Path Format: . .. / as usual
2935  *              [number] to specifie box number ex: trak[12]
2936  *
2937  * ex: /moov/trak[12]
2938  *     ../mdia
2939  *****************************************************************************/
2940 MP4_Box_t *MP4_BoxGet( MP4_Box_t *p_box, const char *psz_fmt, ... )
2941 {
2942     va_list args;
2943     MP4_Box_t *p_result;
2944
2945     va_start( args, psz_fmt );
2946     __MP4_BoxGet( &p_result, p_box, psz_fmt, args );
2947     va_end( args );
2948
2949     return( p_result );
2950 }
2951
2952 /*****************************************************************************
2953  * MP4_BoxCount: count box given a path relative to p_box
2954  *****************************************************************************
2955  * Path Format: . .. / as usual
2956  *              [number] to specifie box number ex: trak[12]
2957  *
2958  * ex: /moov/trak[12]
2959  *     ../mdia
2960  *****************************************************************************/
2961 int MP4_BoxCount( MP4_Box_t *p_box, const char *psz_fmt, ... )
2962 {
2963     va_list args;
2964     int     i_count;
2965     MP4_Box_t *p_result, *p_next;
2966
2967     va_start( args, psz_fmt );
2968     __MP4_BoxGet( &p_result, p_box, psz_fmt, args );
2969     va_end( args );
2970     if( !p_result )
2971     {
2972         return( 0 );
2973     }
2974
2975     i_count = 1;
2976     for( p_next = p_result->p_next; p_next != NULL; p_next = p_next->p_next)
2977     {
2978         if( p_next->i_type == p_result->i_type)
2979         {
2980             i_count++;
2981         }
2982     }
2983     return( i_count );
2984 }