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