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