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