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