]> git.sesse.net Git - vlc/blob - modules/demux/mp4/libmp4.c
demux/mp4: be less picky wrt VC-1 profiles we accept
[vlc] / modules / demux / mp4 / libmp4.c
1 /*****************************************************************************
2  * libmp4.c : LibMP4 library for mp4 module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001-2004, 2010 the VideoLAN team
5  *
6  * Author: Laurent Aimar <fenrir@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <vlc_common.h>
28 #include <vlc_stream.h>                               /* stream_Peek*/
29
30 #ifdef HAVE_ZLIB_H
31 #   include <zlib.h>                                  /* for compressed moov */
32 #endif
33
34 #include "libmp4.h"
35 #include <math.h>
36
37 /* Some assumptions:
38  * The input method HAS to be seekable
39  */
40
41 /* convert 16.16 fixed point to floating point */
42 static double conv_fx( int32_t fx ) {
43     double fp = fx;
44     fp /= 65536.;
45     return fp;
46 }
47
48 /* some functions for mp4 encoding of variables */
49 #ifdef MP4_VERBOSE
50 static void MP4_ConvertDate2Str( char *psz, uint64_t i_date )
51 {
52     int i_day;
53     int i_hour;
54     int i_min;
55     int i_sec;
56
57     /* date begin at 1 jan 1904 */
58     i_date += ((INT64_C(1904) * 365) + 17) * 24 * 60 * 60;
59
60     i_day = i_date / ( 60*60*24);
61     i_hour = ( i_date /( 60*60 ) ) % 60;
62     i_min  = ( i_date / 60 ) % 60;
63     i_sec =  i_date % 60;
64     sprintf( psz, "%dd-%2.2dh:%2.2dm:%2.2ds", i_day, i_hour, i_min, i_sec );
65 }
66 #endif
67
68 /*****************************************************************************
69  * Some prototypes.
70  *****************************************************************************/
71 static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father );
72
73
74 /*****************************************************************************
75  * MP4_ReadBoxCommon : Load only common parameters for all boxes
76  *****************************************************************************
77  * p_box need to be an already allocated MP4_Box_t, and all data
78  *  will only be peek not read
79  *
80  * RETURN : 0 if it fail, 1 otherwise
81  *****************************************************************************/
82 int MP4_ReadBoxCommon( stream_t *p_stream, MP4_Box_t *p_box )
83 {
84     int      i_read;
85     const uint8_t  *p_peek;
86
87     if( ( ( i_read = stream_Peek( p_stream, &p_peek, 32 ) ) < 8 ) )
88     {
89         return 0;
90     }
91     p_box->i_pos = stream_Tell( p_stream );
92
93     p_box->data.p_data = NULL;
94     p_box->p_father = NULL;
95     p_box->p_first  = NULL;
96     p_box->p_last  = NULL;
97     p_box->p_next   = NULL;
98
99     MP4_GET4BYTES( p_box->i_shortsize );
100     MP4_GETFOURCC( p_box->i_type );
101
102     /* Now special case */
103
104     if( p_box->i_shortsize == 1 )
105     {
106         /* get the true size on 64 bits */
107         MP4_GET8BYTES( p_box->i_size );
108     }
109     else
110     {
111         p_box->i_size = p_box->i_shortsize;
112         /* XXX size of 0 means that the box extends to end of file */
113     }
114
115     if( p_box->i_type == ATOM_uuid )
116     {
117         /* get extented type on 16 bytes */
118         GetUUID( &p_box->i_uuid, p_peek );
119         p_peek += 16; i_read -= 16;
120     }
121     else
122     {
123         CreateUUID( &p_box->i_uuid, p_box->i_type );
124     }
125 #ifdef MP4_VERBOSE
126     if( p_box->i_size )
127     {
128         if MP4_BOX_TYPE_ASCII()
129             msg_Dbg( p_stream, "found Box: %4.4s size %"PRId64,
130                     (char*)&p_box->i_type, p_box->i_size );
131         else
132             msg_Dbg( p_stream, "found Box: c%3.3s size %"PRId64,
133                     (char*)&p_box->i_type+1, p_box->i_size );
134     }
135 #endif
136
137     return 1;
138 }
139
140 /*****************************************************************************
141  * MP4_NextBox : Go to the next box
142  *****************************************************************************
143  * if p_box == NULL, go to the next box in which we are( at the begining ).
144  *****************************************************************************/
145 static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
146 {
147     MP4_Box_t box;
148
149     if( !p_box )
150     {
151         MP4_ReadBoxCommon( p_stream, &box );
152         p_box = &box;
153     }
154
155     if( !p_box->i_size )
156     {
157         return 2; /* Box with infinite size */
158     }
159
160     if( p_box->p_father )
161     {
162         /* if father's size == 0, it means unknown or infinite size,
163          * and we skip the followong check */
164         if( p_box->p_father->i_size > 0 )
165         {
166             const off_t i_box_end = p_box->i_size + p_box->i_pos;
167             const off_t i_father_end = p_box->p_father->i_size + p_box->p_father->i_pos;
168
169             /* check if it's within p-father */
170             if( i_box_end >= i_father_end )
171             {
172                 if( i_box_end > i_father_end )
173                     msg_Dbg( p_stream, "out of bound child" );
174                 return 0; /* out of bound */
175             }
176         }
177     }
178     if( stream_Seek( p_stream, p_box->i_size + p_box->i_pos ) )
179     {
180         return 0;
181     }
182
183     return 1;
184 }
185
186 /*****************************************************************************
187  * For all known box a loader is given,
188  *  XXX: all common struct have to be already read by MP4_ReadBoxCommon
189  *       after called one of theses functions, file position is unknown
190  *       you need to call MP4_GotoBox to go where you want
191  *****************************************************************************/
192 static int MP4_ReadBoxContainerChildren( stream_t *p_stream,
193                                     MP4_Box_t *p_container, uint32_t i_last_child )
194 {
195     MP4_Box_t *p_box;
196
197     /* Size of root container is set to 0 when unknown, for exemple
198      * with a DASH stream. In that case, we skip the following check */
199     if( p_container->i_size
200             && ( stream_Tell( p_stream ) + 8 >
201         (off_t)(p_container->i_pos + p_container->i_size) )
202       )
203     {
204         /* there is no box to load */
205         return 0;
206     }
207
208     do
209     {
210         if( ( p_box = MP4_ReadBox( p_stream, p_container ) ) == NULL ) break;
211
212         /* chain this box with the father and the other at same level */
213         if( !p_container->p_first ) p_container->p_first = p_box;
214         else p_container->p_last->p_next = p_box;
215         p_container->p_last = p_box;
216
217         if( p_box->i_type == i_last_child )
218             break;
219
220     } while( MP4_NextBox( p_stream, p_box ) == 1 );
221
222     return 1;
223 }
224
225 static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container )
226 {
227     return MP4_ReadBoxContainerChildren( p_stream, p_container, 0 );
228 }
229
230 static int MP4_ReadBoxContainer( stream_t *p_stream, MP4_Box_t *p_container )
231 {
232     if( p_container->i_size &&
233         ( p_container->i_size <= (size_t)mp4_box_headersize(p_container ) + 8 ) )
234     {
235         /* container is empty, 8 stand for the first header in this box */
236         return 1;
237     }
238
239     /* enter box */
240     stream_Seek( p_stream, p_container->i_pos +
241                  mp4_box_headersize( p_container ) );
242
243     return MP4_ReadBoxContainerRaw( p_stream, p_container );
244 }
245
246 static void MP4_FreeBox_Common( MP4_Box_t *p_box )
247 {
248     /* Up to now do nothing */
249     (void)p_box;
250 }
251
252 static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box )
253 {
254     /* XXX sometime moov is hiden in a free box */
255     if( p_box->p_father &&
256         p_box->p_father->i_type == ATOM_root &&
257         p_box->i_type == ATOM_free )
258     {
259         const uint8_t *p_peek;
260         int     i_read;
261         vlc_fourcc_t i_fcc;
262
263         i_read  = stream_Peek( p_stream, &p_peek, 44 );
264
265         p_peek += mp4_box_headersize( p_box ) + 4;
266         i_read -= mp4_box_headersize( p_box ) + 4;
267
268         if( i_read >= 8 )
269         {
270             i_fcc = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
271
272             if( i_fcc == ATOM_cmov || i_fcc == ATOM_mvhd )
273             {
274                 msg_Warn( p_stream, "detected moov hidden in a free box ..." );
275
276                 p_box->i_type = ATOM_foov;
277                 return MP4_ReadBoxContainer( p_stream, p_box );
278             }
279         }
280     }
281
282     /* Nothing to do */
283 #ifdef MP4_VERBOSE
284     if MP4_BOX_TYPE_ASCII()
285         msg_Dbg( p_stream, "skip box: \"%4.4s\"", (char*)&p_box->i_type );
286     else
287         msg_Dbg( p_stream, "skip box: \"c%3.3s\"", (char*)&p_box->i_type+1 );
288 #endif
289     return 1;
290 }
291
292 static int MP4_ReadBox_ftyp( stream_t *p_stream, MP4_Box_t *p_box )
293 {
294     MP4_READBOX_ENTER( MP4_Box_data_ftyp_t );
295
296     MP4_GETFOURCC( p_box->data.p_ftyp->i_major_brand );
297     MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version );
298
299     if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) )
300     {
301         uint32_t *tab = p_box->data.p_ftyp->i_compatible_brands =
302             calloc( p_box->data.p_ftyp->i_compatible_brands_count,
303                     sizeof(uint32_t));
304
305         if( unlikely( tab == NULL ) )
306             MP4_READBOX_EXIT( 0 );
307
308         for( unsigned i = 0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )
309         {
310             MP4_GETFOURCC( tab[i] );
311         }
312     }
313     else
314     {
315         p_box->data.p_ftyp->i_compatible_brands = NULL;
316     }
317
318     MP4_READBOX_EXIT( 1 );
319 }
320
321 static void MP4_FreeBox_ftyp( MP4_Box_t *p_box )
322 {
323     FREENULL( p_box->data.p_ftyp->i_compatible_brands );
324 }
325
326
327 static int MP4_ReadBox_mvhd(  stream_t *p_stream, MP4_Box_t *p_box )
328 {
329 #ifdef MP4_VERBOSE
330     char s_creation_time[128];
331     char s_modification_time[128];
332     char s_duration[128];
333 #endif
334     MP4_READBOX_ENTER( MP4_Box_data_mvhd_t );
335
336     MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );
337
338     if( p_box->data.p_mvhd->i_version )
339     {
340         MP4_GET8BYTES( p_box->data.p_mvhd->i_creation_time );
341         MP4_GET8BYTES( p_box->data.p_mvhd->i_modification_time );
342         MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
343         MP4_GET8BYTES( p_box->data.p_mvhd->i_duration );
344     }
345     else
346     {
347         MP4_GET4BYTES( p_box->data.p_mvhd->i_creation_time );
348         MP4_GET4BYTES( p_box->data.p_mvhd->i_modification_time );
349         MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
350         MP4_GET4BYTES( p_box->data.p_mvhd->i_duration );
351     }
352     MP4_GET4BYTES( p_box->data.p_mvhd->i_rate );
353     MP4_GET2BYTES( p_box->data.p_mvhd->i_volume );
354     MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 );
355
356
357     for( unsigned i = 0; i < 2; i++ )
358     {
359         MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] );
360     }
361     for( unsigned i = 0; i < 9; i++ )
362     {
363         MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] );
364     }
365     for( unsigned i = 0; i < 6; i++ )
366     {
367         MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] );
368     }
369
370     MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id );
371
372
373 #ifdef MP4_VERBOSE
374     MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
375     MP4_ConvertDate2Str( s_modification_time,
376                          p_box->data.p_mvhd->i_modification_time );
377     if( p_box->data.p_mvhd->i_rate )
378     {
379         MP4_ConvertDate2Str( s_duration,
380                  p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate );
381     }
382     else
383     {
384         s_duration[0] = 0;
385     }
386     msg_Dbg( p_stream, "read box: \"mvhd\" creation %s modification %s time scale %d duration %s rate %f volume %f next track id %d",
387                   s_creation_time,
388                   s_modification_time,
389                   (uint32_t)p_box->data.p_mvhd->i_timescale,
390                   s_duration,
391                   (float)p_box->data.p_mvhd->i_rate / (1<<16 ),
392                   (float)p_box->data.p_mvhd->i_volume / 256 ,
393                   (uint32_t)p_box->data.p_mvhd->i_next_track_id );
394 #endif
395     MP4_READBOX_EXIT( 1 );
396 }
397
398 static int MP4_ReadBox_mfhd(  stream_t *p_stream, MP4_Box_t *p_box )
399 {
400     MP4_READBOX_ENTER( MP4_Box_data_mfhd_t );
401
402     MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );
403
404     MP4_GET4BYTES( p_box->data.p_mfhd->i_sequence_number );
405
406 #ifdef MP4_VERBOSE
407     msg_Dbg( p_stream, "read box: \"mfhd\" sequence number %d",
408                   p_box->data.p_mfhd->i_sequence_number );
409 #endif
410     MP4_READBOX_EXIT( 1 );
411 }
412
413 static int MP4_ReadBox_tfxd(  stream_t *p_stream, MP4_Box_t *p_box )
414 {
415     MP4_READBOX_ENTER( MP4_Box_data_tfxd_t );
416
417     MP4_Box_data_tfxd_t *p_tfxd_data = p_box->data.p_tfxd;
418     MP4_GETVERSIONFLAGS( p_tfxd_data );
419
420     if( p_tfxd_data->i_version == 0 )
421     {
422         MP4_GET4BYTES( p_tfxd_data->i_fragment_abs_time );
423         MP4_GET4BYTES( p_tfxd_data->i_fragment_duration );
424     }
425     else
426     {
427         MP4_GET8BYTES( p_tfxd_data->i_fragment_abs_time );
428         MP4_GET8BYTES( p_tfxd_data->i_fragment_duration );
429     }
430
431 #ifdef MP4_VERBOSE
432     msg_Dbg( p_stream, "read box: \"tfxd\" version %d, flags 0x%x, "\
433             "fragment duration %"PRIu64", fragment abs time %"PRIu64,
434                 p_tfxd_data->i_version,
435                 p_tfxd_data->i_flags,
436                 p_tfxd_data->i_fragment_duration,
437                 p_tfxd_data->i_fragment_abs_time
438            );
439 #endif
440
441     MP4_READBOX_EXIT( 1 );
442 }
443
444 static int MP4_ReadBox_tfrf(  stream_t *p_stream, MP4_Box_t *p_box )
445 {
446     MP4_READBOX_ENTER( MP4_Box_data_tfxd_t );
447
448     MP4_Box_data_tfrf_t *p_tfrf_data = p_box->data.p_tfrf;
449     MP4_GETVERSIONFLAGS( p_tfrf_data );
450
451     MP4_GET1BYTE( p_tfrf_data->i_fragment_count );
452
453     p_tfrf_data->p_tfrf_data_fields = calloc( p_tfrf_data->i_fragment_count,
454                                               sizeof( TfrfBoxDataFields_t ) );
455     if( !p_tfrf_data->p_tfrf_data_fields )
456         MP4_READBOX_EXIT( 0 );
457
458     for( uint8_t i = 0; i < p_tfrf_data->i_fragment_count; i++ )
459     {
460         TfrfBoxDataFields_t *TfrfBoxDataField = &p_tfrf_data->p_tfrf_data_fields[i];
461         if( p_tfrf_data->i_version == 0 )
462         {
463             MP4_GET4BYTES( TfrfBoxDataField->i_fragment_abs_time );
464             MP4_GET4BYTES( TfrfBoxDataField->i_fragment_duration );
465         }
466         else
467         {
468             MP4_GET8BYTES( TfrfBoxDataField->i_fragment_abs_time );
469             MP4_GET8BYTES( TfrfBoxDataField->i_fragment_duration );
470         }
471     }
472
473 #ifdef MP4_VERBOSE
474     msg_Dbg( p_stream, "read box: \"tfrf\" version %d, flags 0x%x, "\
475             "fragment count %"PRIu8, p_tfrf_data->i_version,
476                 p_tfrf_data->i_flags, p_tfrf_data->i_fragment_count );
477
478     for( uint8_t i = 0; i < p_tfrf_data->i_fragment_count; i++ )
479     {
480         TfrfBoxDataFields_t *TfrfBoxDataField = &p_tfrf_data->p_tfrf_data_fields[i];
481         msg_Dbg( p_stream, "\"tfrf\" fragment duration %"PRIu64", "\
482                                     "fragment abs time %"PRIu64,
483                     TfrfBoxDataField->i_fragment_duration,
484                     TfrfBoxDataField->i_fragment_abs_time );
485     }
486
487 #endif
488
489     MP4_READBOX_EXIT( 1 );
490 }
491
492 static void MP4_FreeBox_tfrf( MP4_Box_t *p_box )
493 {
494     FREENULL( p_box->data.p_tfrf->p_tfrf_data_fields );
495 }
496
497 static int MP4_ReadBox_stra( stream_t *p_stream, MP4_Box_t *p_box )
498 {
499     MP4_READBOX_ENTER( MP4_Box_data_stra_t );
500     MP4_Box_data_stra_t *p_stra = p_box->data.p_stra;
501
502     uint8_t i_reserved;
503     MP4_GET1BYTE( p_stra->i_es_cat );
504     MP4_GET1BYTE( i_reserved );
505     MP4_GET2BYTES( p_stra->i_track_ID );
506
507     MP4_GET4BYTES( p_stra->i_timescale );
508     MP4_GET8BYTES( p_stra->i_duration );
509
510     MP4_GET4BYTES( p_stra->FourCC );
511     MP4_GET4BYTES( p_stra->Bitrate );
512     MP4_GET4BYTES( p_stra->MaxWidth );
513     MP4_GET4BYTES( p_stra->MaxHeight );
514     MP4_GET4BYTES( p_stra->SamplingRate );
515     MP4_GET4BYTES( p_stra->Channels );
516     MP4_GET4BYTES( p_stra->BitsPerSample );
517     MP4_GET4BYTES( p_stra->AudioTag );
518     MP4_GET2BYTES( p_stra->nBlockAlign );
519
520     MP4_GET1BYTE( i_reserved );
521     MP4_GET1BYTE( i_reserved );
522     MP4_GET1BYTE( i_reserved );
523     MP4_GET1BYTE( p_stra->cpd_len );
524     if( p_stra->cpd_len > i_read )
525         goto error;
526     p_stra->CodecPrivateData = malloc( p_stra->cpd_len );
527     if( unlikely( p_stra->CodecPrivateData == NULL ) )
528         goto error;
529     memcpy( p_stra->CodecPrivateData, p_peek, p_stra->cpd_len );
530
531 #ifdef MP4_VERBOSE
532     msg_Dbg( p_stream, "es_cat is %"PRIu8", birate is %"PRIu32,
533               p_stra->i_es_cat, p_stra->Bitrate );
534 #endif
535
536     MP4_READBOX_EXIT( 1 );
537 error:
538     MP4_READBOX_EXIT( 0 );
539 }
540
541 static void MP4_FreeBox_stra( MP4_Box_t *p_box )
542 {
543     FREENULL( p_box->data.p_stra->CodecPrivateData );
544 }
545
546 static int MP4_ReadBox_uuid( stream_t *p_stream, MP4_Box_t *p_box )
547 {
548     if( !CmpUUID( &p_box->i_uuid, &TfrfBoxUUID ) )
549         return MP4_ReadBox_tfrf( p_stream, p_box );
550     if( !CmpUUID( &p_box->i_uuid, &TfxdBoxUUID ) )
551         return MP4_ReadBox_tfxd( p_stream, p_box );
552     if( !CmpUUID( &p_box->i_uuid, &SmooBoxUUID ) )
553         return MP4_ReadBoxContainer( p_stream, p_box );
554     if( !CmpUUID( &p_box->i_uuid, &StraBoxUUID ) )
555         return MP4_ReadBox_stra( p_stream, p_box );
556
557     msg_Warn( p_stream, "Unknown uuid type box" );
558     return 1;
559 }
560
561 static void MP4_FreeBox_uuid( MP4_Box_t *p_box )
562 {
563     if( !CmpUUID( &p_box->i_uuid, &TfrfBoxUUID ) )
564         return MP4_FreeBox_tfrf( p_box );
565     if( !CmpUUID( &p_box->i_uuid, &TfxdBoxUUID ) )
566         return MP4_FreeBox_Common( p_box );
567     if( !CmpUUID( &p_box->i_uuid, &SmooBoxUUID ) )
568         return MP4_FreeBox_Common( p_box );
569     if( !CmpUUID( &p_box->i_uuid, &StraBoxUUID ) )
570         return MP4_FreeBox_stra( p_box );
571 }
572
573 static int MP4_ReadBox_sidx(  stream_t *p_stream, MP4_Box_t *p_box )
574 {
575     MP4_READBOX_ENTER( MP4_Box_data_sidx_t );
576
577     MP4_Box_data_sidx_t *p_sidx_data = p_box->data.p_sidx;
578     MP4_GETVERSIONFLAGS( p_sidx_data );
579
580     MP4_GET4BYTES( p_sidx_data->i_reference_ID );
581     MP4_GET4BYTES( p_sidx_data->i_timescale );
582
583     if( p_sidx_data->i_version == 0 )
584     {
585         MP4_GET4BYTES( p_sidx_data->i_earliest_presentation_time );
586         MP4_GET4BYTES( p_sidx_data->i_first_offset );
587     }
588     else
589     {
590         MP4_GET8BYTES( p_sidx_data->i_earliest_presentation_time );
591         MP4_GET8BYTES( p_sidx_data->i_first_offset );
592     }
593
594     uint16_t i_reserved;
595     MP4_GET2BYTES( i_reserved );
596     MP4_GET2BYTES( p_sidx_data->i_reference_count );
597     uint16_t i_count = p_sidx_data->i_reference_count;
598
599     p_sidx_data->p_items = calloc( i_count, sizeof( MP4_Box_sidx_item_t ) );
600     uint32_t tmp;
601     for( unsigned i = 0; i < i_count; i++ )
602     {
603         MP4_GET4BYTES( tmp );
604         p_sidx_data->p_items[i].b_reference_type = (bool)((tmp & 0x80000000)>>24);
605         p_sidx_data->p_items[i].i_referenced_size = tmp & 0x7fffffff;
606         MP4_GET4BYTES( p_sidx_data->p_items[i].i_subsegment_duration );
607
608         MP4_GET4BYTES( tmp );
609         p_sidx_data->p_items[i].b_starts_with_SAP = (bool)((tmp & 0x80000000)>>24);
610         p_sidx_data->p_items[i].i_SAP_type = (tmp & 0x70000000)>>24;
611         p_sidx_data->p_items[i].i_SAP_delta_time = tmp & 0xfffffff;
612     }
613
614 #ifdef MP4_VERBOSE
615     msg_Dbg( p_stream, "read box: \"sidx\" version %d, flags 0x%x, "\
616             "ref_ID %"PRIu32", timescale %"PRIu32", ref_count %"PRIu16", "\
617             "first subsegmt duration %"PRIu32,
618                 p_sidx_data->i_version,
619                 p_sidx_data->i_flags,
620                 p_sidx_data->i_reference_ID,
621                 p_sidx_data->i_timescale,
622                 p_sidx_data->i_reference_count,
623                 p_sidx_data->p_items[0].i_subsegment_duration
624            );
625 #endif
626
627     MP4_READBOX_EXIT( 1 );
628 }
629
630 static void MP4_FreeBox_sidx( MP4_Box_t *p_box )
631 {
632     FREENULL( p_box->data.p_sidx->p_items );
633 }
634
635 static int MP4_ReadBox_tfhd(  stream_t *p_stream, MP4_Box_t *p_box )
636 {
637     MP4_READBOX_ENTER( MP4_Box_data_tfhd_t );
638
639     MP4_GETVERSIONFLAGS( p_box->data.p_tfhd );
640
641     if( p_box->data.p_tfhd->i_version != 0 )
642     {
643         msg_Warn( p_stream, "'tfhd' box with version != 0. "\
644                 " Don't know what to do with that, please patch" );
645         MP4_READBOX_EXIT( 0 );
646     }
647
648     MP4_GET4BYTES( p_box->data.p_tfhd->i_track_ID );
649
650     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DURATION_IS_EMPTY )
651     {
652         msg_Dbg( p_stream, "'duration-is-empty' flag is present "\
653                 "=> no samples for this time interval." );
654         p_box->data.p_tfhd->b_empty = true;
655     }
656     else
657         p_box->data.p_tfhd->b_empty = false;
658
659     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
660         MP4_GET8BYTES( p_box->data.p_tfhd->i_base_data_offset );
661     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
662         MP4_GET4BYTES( p_box->data.p_tfhd->i_sample_description_index );
663     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
664         MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_duration );
665     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
666         MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_size );
667     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
668         MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_flags );
669
670 #ifdef MP4_VERBOSE
671     char psz_base[128] = "\0";
672     char psz_desc[128] = "\0";
673     char psz_dura[128] = "\0";
674     char psz_size[128] = "\0";
675     char psz_flag[128] = "\0";
676     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
677         snprintf(psz_base, sizeof(psz_base), "base offset %"PRId64, p_box->data.p_tfhd->i_base_data_offset);
678     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
679         snprintf(psz_desc, sizeof(psz_desc), "sample description index %d", p_box->data.p_tfhd->i_sample_description_index);
680     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
681         snprintf(psz_dura, sizeof(psz_dura), "sample duration %d", p_box->data.p_tfhd->i_default_sample_duration);
682     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
683         snprintf(psz_size, sizeof(psz_size), "sample size %d", p_box->data.p_tfhd->i_default_sample_size);
684     if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
685         snprintf(psz_flag, sizeof(psz_flag), "sample flags 0x%x", p_box->data.p_tfhd->i_default_sample_flags);
686
687     msg_Dbg( p_stream, "read box: \"tfhd\" version %d flags 0x%x track ID %d %s %s %s %s %s",
688                 p_box->data.p_tfhd->i_version,
689                 p_box->data.p_tfhd->i_flags,
690                 p_box->data.p_tfhd->i_track_ID,
691                 psz_base, psz_desc, psz_dura, psz_size, psz_flag );
692 #endif
693
694     MP4_READBOX_EXIT( 1 );
695 }
696
697 static int MP4_ReadBox_trun(  stream_t *p_stream, MP4_Box_t *p_box )
698 {
699     MP4_READBOX_ENTER( MP4_Box_data_trun_t );
700
701     MP4_GETVERSIONFLAGS( p_box->data.p_trun );
702
703     MP4_GET4BYTES( p_box->data.p_trun->i_sample_count );
704
705     if( p_box->data.p_trun->i_flags & MP4_TRUN_DATA_OFFSET )
706         MP4_GET4BYTES( p_box->data.p_trun->i_data_offset );
707     if( p_box->data.p_trun->i_flags & MP4_TRUN_FIRST_FLAGS )
708         MP4_GET4BYTES( p_box->data.p_trun->i_first_sample_flags );
709
710     p_box->data.p_trun->p_samples =
711       calloc( p_box->data.p_trun->i_sample_count, sizeof(MP4_descriptor_trun_sample_t) );
712     if ( p_box->data.p_trun->p_samples == NULL )
713         MP4_READBOX_EXIT( 0 );
714
715     for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
716     {
717         MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
718         if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION )
719             MP4_GET4BYTES( p_sample->i_duration );
720         if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE )
721             MP4_GET4BYTES( p_sample->i_size );
722         if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_FLAGS )
723             MP4_GET4BYTES( p_sample->i_flags );
724         if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET )
725             MP4_GET4BYTES( p_sample->i_composition_time_offset );
726     }
727
728 #ifdef MP4_VERBOSE
729     msg_Dbg( p_stream, "read box: \"trun\" version %u flags 0x%x sample count %u",
730                   p_box->data.p_trun->i_version,
731                   p_box->data.p_trun->i_flags,
732                   p_box->data.p_trun->i_sample_count );
733
734     for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
735     {
736         MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
737         msg_Dbg( p_stream, "read box: \"trun\" sample %4.4u flags 0x%x "\
738             "duration %"PRIu32" size %"PRIu32" composition time offset %"PRIu32,
739                         i, p_sample->i_flags, p_sample->i_duration,
740                         p_sample->i_size, p_sample->i_composition_time_offset );
741     }
742 #endif
743
744     MP4_READBOX_EXIT( 1 );
745 }
746
747 static void MP4_FreeBox_trun( MP4_Box_t *p_box )
748 {
749     FREENULL( p_box->data.p_trun->p_samples );
750 }
751
752
753 static int MP4_ReadBox_tkhd(  stream_t *p_stream, MP4_Box_t *p_box )
754 {
755 #ifdef MP4_VERBOSE
756     char s_creation_time[128];
757     char s_modification_time[128];
758     char s_duration[128];
759 #endif
760     MP4_READBOX_ENTER( MP4_Box_data_tkhd_t );
761
762     MP4_GETVERSIONFLAGS( p_box->data.p_tkhd );
763
764     if( p_box->data.p_tkhd->i_version )
765     {
766         MP4_GET8BYTES( p_box->data.p_tkhd->i_creation_time );
767         MP4_GET8BYTES( p_box->data.p_tkhd->i_modification_time );
768         MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
769         MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
770         MP4_GET8BYTES( p_box->data.p_tkhd->i_duration );
771     }
772     else
773     {
774         MP4_GET4BYTES( p_box->data.p_tkhd->i_creation_time );
775         MP4_GET4BYTES( p_box->data.p_tkhd->i_modification_time );
776         MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
777         MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
778         MP4_GET4BYTES( p_box->data.p_tkhd->i_duration );
779     }
780
781     for( unsigned i = 0; i < 2; i++ )
782     {
783         MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved2[i] );
784     }
785     MP4_GET2BYTES( p_box->data.p_tkhd->i_layer );
786     MP4_GET2BYTES( p_box->data.p_tkhd->i_predefined );
787     MP4_GET2BYTES( p_box->data.p_tkhd->i_volume );
788     MP4_GET2BYTES( p_box->data.p_tkhd->i_reserved3 );
789
790     for( unsigned i = 0; i < 9; i++ )
791     {
792         MP4_GET4BYTES( p_box->data.p_tkhd->i_matrix[i] );
793     }
794     MP4_GET4BYTES( p_box->data.p_tkhd->i_width );
795     MP4_GET4BYTES( p_box->data.p_tkhd->i_height );
796
797     double rotation;    //angle in degrees to be rotated clockwise
798     double scale[2];    // scale factor; sx = scale[0] , sy = scale[1]
799     double translate[2];// amount to translate; tx = translate[0] , ty = translate[1]
800
801     int *matrix = p_box->data.p_tkhd->i_matrix;
802
803     translate[0] = conv_fx(matrix[6]);
804     translate[1] = conv_fx(matrix[7]);
805
806     scale[0] = sqrt(conv_fx(matrix[0]) * conv_fx(matrix[0]) +
807                     conv_fx(matrix[3]) * conv_fx(matrix[3]));
808     scale[1] = sqrt(conv_fx(matrix[1]) * conv_fx(matrix[1]) +
809                     conv_fx(matrix[4]) * conv_fx(matrix[4]));
810
811     rotation = atan2(conv_fx(matrix[1]) / scale[1], conv_fx(matrix[0]) / scale[0]) * 180 / M_PI;
812
813     if (rotation < 0)
814         rotation += 360.;
815
816     p_box->data.p_tkhd->f_rotation = rotation;
817
818 #ifdef MP4_VERBOSE
819     MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
820     MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time );
821     MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration );
822
823     msg_Dbg( p_stream, "read box: \"tkhd\" creation %s modification %s duration %s track ID %d layer %d volume %f rotation %f scaleX %f scaleY %f translateX %f translateY %f width %f height %f. "
824             "Matrix: %i %i %i %i %i %i %i %i %i",
825                   s_creation_time,
826                   s_modification_time,
827                   s_duration,
828                   p_box->data.p_tkhd->i_track_ID,
829                   p_box->data.p_tkhd->i_layer,
830                   (float)p_box->data.p_tkhd->i_volume / 256 ,
831                   rotation,
832                   scale[0],
833                   scale[1],
834                   translate[0],
835                   translate[1],
836                   (float)p_box->data.p_tkhd->i_width / 65536,
837                   (float)p_box->data.p_tkhd->i_height / 65536,
838                   p_box->data.p_tkhd->i_matrix[0],
839                   p_box->data.p_tkhd->i_matrix[1],
840                   p_box->data.p_tkhd->i_matrix[2],
841                   p_box->data.p_tkhd->i_matrix[3],
842                   p_box->data.p_tkhd->i_matrix[4],
843                   p_box->data.p_tkhd->i_matrix[5],
844                   p_box->data.p_tkhd->i_matrix[6],
845                   p_box->data.p_tkhd->i_matrix[7],
846                   p_box->data.p_tkhd->i_matrix[8] );
847 #endif
848     MP4_READBOX_EXIT( 1 );
849 }
850
851
852 static int MP4_ReadBox_mdhd( stream_t *p_stream, MP4_Box_t *p_box )
853 {
854     uint16_t i_language;
855 #ifdef MP4_VERBOSE
856     char s_creation_time[128];
857     char s_modification_time[128];
858     char s_duration[128];
859 #endif
860     MP4_READBOX_ENTER( MP4_Box_data_mdhd_t );
861
862     MP4_GETVERSIONFLAGS( p_box->data.p_mdhd );
863
864     if( p_box->data.p_mdhd->i_version )
865     {
866         MP4_GET8BYTES( p_box->data.p_mdhd->i_creation_time );
867         MP4_GET8BYTES( p_box->data.p_mdhd->i_modification_time );
868         MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
869         MP4_GET8BYTES( p_box->data.p_mdhd->i_duration );
870     }
871     else
872     {
873         MP4_GET4BYTES( p_box->data.p_mdhd->i_creation_time );
874         MP4_GET4BYTES( p_box->data.p_mdhd->i_modification_time );
875         MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
876         MP4_GET4BYTES( p_box->data.p_mdhd->i_duration );
877     }
878     p_box->data.p_mdhd->i_language_code = i_language = GetWBE( p_peek );
879     for( unsigned i = 0; i < 3; i++ )
880     {
881         p_box->data.p_mdhd->i_language[i] =
882                     ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
883     }
884
885     MP4_GET2BYTES( p_box->data.p_mdhd->i_predefined );
886
887 #ifdef MP4_VERBOSE
888     MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time );
889     MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time );
890     MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration );
891     msg_Dbg( p_stream, "read box: \"mdhd\" creation %s modification %s time scale %d duration %s language %c%c%c",
892                   s_creation_time,
893                   s_modification_time,
894                   (uint32_t)p_box->data.p_mdhd->i_timescale,
895                   s_duration,
896                   p_box->data.p_mdhd->i_language[0],
897                   p_box->data.p_mdhd->i_language[1],
898                   p_box->data.p_mdhd->i_language[2] );
899 #endif
900     MP4_READBOX_EXIT( 1 );
901 }
902
903
904 static int MP4_ReadBox_hdlr( stream_t *p_stream, MP4_Box_t *p_box )
905 {
906     int32_t i_reserved;
907
908     MP4_READBOX_ENTER( MP4_Box_data_hdlr_t );
909
910     MP4_GETVERSIONFLAGS( p_box->data.p_hdlr );
911
912     MP4_GETFOURCC( p_box->data.p_hdlr->i_predefined );
913     MP4_GETFOURCC( p_box->data.p_hdlr->i_handler_type );
914
915     MP4_GET4BYTES( i_reserved );
916     MP4_GET4BYTES( i_reserved );
917     MP4_GET4BYTES( i_reserved );
918     p_box->data.p_hdlr->psz_name = NULL;
919
920     if( i_read > 0 )
921     {
922         uint8_t *psz = p_box->data.p_hdlr->psz_name = malloc( i_read + 1 );
923         if( unlikely( psz == NULL ) )
924             MP4_READBOX_EXIT( 0 );
925
926         /* Yes, I love .mp4 :( */
927         if( p_box->data.p_hdlr->i_predefined == VLC_FOURCC( 'm', 'h', 'l', 'r' ) )
928         {
929             uint8_t i_len;
930             int i_copy;
931
932             MP4_GET1BYTE( i_len );
933             i_copy = __MIN( i_read, i_len );
934
935             memcpy( psz, p_peek, i_copy );
936             p_box->data.p_hdlr->psz_name[i_copy] = '\0';
937         }
938         else
939         {
940             memcpy( psz, p_peek, i_read );
941             p_box->data.p_hdlr->psz_name[i_read] = '\0';
942         }
943     }
944
945 #ifdef MP4_VERBOSE
946         msg_Dbg( p_stream, "read box: \"hdlr\" handler type: \"%4.4s\" name: \"%s\"",
947                    (char*)&p_box->data.p_hdlr->i_handler_type,
948                    p_box->data.p_hdlr->psz_name );
949
950 #endif
951     MP4_READBOX_EXIT( 1 );
952 }
953
954 static void MP4_FreeBox_hdlr( MP4_Box_t *p_box )
955 {
956     FREENULL( p_box->data.p_hdlr->psz_name );
957 }
958
959 static int MP4_ReadBox_vmhd( stream_t *p_stream, MP4_Box_t *p_box )
960 {
961     MP4_READBOX_ENTER( MP4_Box_data_vmhd_t );
962
963     MP4_GETVERSIONFLAGS( p_box->data.p_vmhd );
964
965     MP4_GET2BYTES( p_box->data.p_vmhd->i_graphics_mode );
966     for( unsigned i = 0; i < 3; i++ )
967     {
968         MP4_GET2BYTES( p_box->data.p_vmhd->i_opcolor[i] );
969     }
970
971 #ifdef MP4_VERBOSE
972     msg_Dbg( p_stream, "read box: \"vmhd\" graphics-mode %d opcolor (%d, %d, %d)",
973                       p_box->data.p_vmhd->i_graphics_mode,
974                       p_box->data.p_vmhd->i_opcolor[0],
975                       p_box->data.p_vmhd->i_opcolor[1],
976                       p_box->data.p_vmhd->i_opcolor[2] );
977 #endif
978     MP4_READBOX_EXIT( 1 );
979 }
980
981 static int MP4_ReadBox_smhd( stream_t *p_stream, MP4_Box_t *p_box )
982 {
983     MP4_READBOX_ENTER( MP4_Box_data_smhd_t );
984
985     MP4_GETVERSIONFLAGS( p_box->data.p_smhd );
986
987
988
989     MP4_GET2BYTES( p_box->data.p_smhd->i_balance );
990
991     MP4_GET2BYTES( p_box->data.p_smhd->i_reserved );
992
993 #ifdef MP4_VERBOSE
994     msg_Dbg( p_stream, "read box: \"smhd\" balance %f",
995                       (float)p_box->data.p_smhd->i_balance / 256 );
996 #endif
997     MP4_READBOX_EXIT( 1 );
998 }
999
1000
1001 static int MP4_ReadBox_hmhd( stream_t *p_stream, MP4_Box_t *p_box )
1002 {
1003     MP4_READBOX_ENTER( MP4_Box_data_hmhd_t );
1004
1005     MP4_GETVERSIONFLAGS( p_box->data.p_hmhd );
1006
1007     MP4_GET2BYTES( p_box->data.p_hmhd->i_max_PDU_size );
1008     MP4_GET2BYTES( p_box->data.p_hmhd->i_avg_PDU_size );
1009
1010     MP4_GET4BYTES( p_box->data.p_hmhd->i_max_bitrate );
1011     MP4_GET4BYTES( p_box->data.p_hmhd->i_avg_bitrate );
1012
1013     MP4_GET4BYTES( p_box->data.p_hmhd->i_reserved );
1014
1015 #ifdef MP4_VERBOSE
1016     msg_Dbg( p_stream, "read box: \"hmhd\" maxPDU-size %d avgPDU-size %d max-bitrate %d avg-bitrate %d",
1017                       p_box->data.p_hmhd->i_max_PDU_size,
1018                       p_box->data.p_hmhd->i_avg_PDU_size,
1019                       p_box->data.p_hmhd->i_max_bitrate,
1020                       p_box->data.p_hmhd->i_avg_bitrate );
1021 #endif
1022     MP4_READBOX_EXIT( 1 );
1023 }
1024
1025 static int MP4_ReadBox_url( stream_t *p_stream, MP4_Box_t *p_box )
1026 {
1027     MP4_READBOX_ENTER( MP4_Box_data_url_t );
1028
1029     MP4_GETVERSIONFLAGS( p_box->data.p_url );
1030     MP4_GETSTRINGZ( p_box->data.p_url->psz_location );
1031
1032 #ifdef MP4_VERBOSE
1033     msg_Dbg( p_stream, "read box: \"url\" url: %s",
1034                        p_box->data.p_url->psz_location );
1035
1036 #endif
1037     MP4_READBOX_EXIT( 1 );
1038 }
1039
1040
1041 static void MP4_FreeBox_url( MP4_Box_t *p_box )
1042 {
1043     FREENULL( p_box->data.p_url->psz_location );
1044 }
1045
1046 static int MP4_ReadBox_urn( stream_t *p_stream, MP4_Box_t *p_box )
1047 {
1048     MP4_READBOX_ENTER( MP4_Box_data_urn_t );
1049
1050     MP4_GETVERSIONFLAGS( p_box->data.p_urn );
1051
1052     MP4_GETSTRINGZ( p_box->data.p_urn->psz_name );
1053     MP4_GETSTRINGZ( p_box->data.p_urn->psz_location );
1054
1055 #ifdef MP4_VERBOSE
1056     msg_Dbg( p_stream, "read box: \"urn\" name %s location %s",
1057                       p_box->data.p_urn->psz_name,
1058                       p_box->data.p_urn->psz_location );
1059 #endif
1060     MP4_READBOX_EXIT( 1 );
1061 }
1062 static void MP4_FreeBox_urn( MP4_Box_t *p_box )
1063 {
1064     FREENULL( p_box->data.p_urn->psz_name );
1065     FREENULL( p_box->data.p_urn->psz_location );
1066 }
1067
1068
1069 static int MP4_ReadBox_dref( stream_t *p_stream, MP4_Box_t *p_box )
1070 {
1071     MP4_READBOX_ENTER( MP4_Box_data_dref_t );
1072
1073     MP4_GETVERSIONFLAGS( p_box->data.p_dref );
1074
1075     MP4_GET4BYTES( p_box->data.p_dref->i_entry_count );
1076
1077     stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
1078     MP4_ReadBoxContainerRaw( p_stream, p_box );
1079
1080 #ifdef MP4_VERBOSE
1081     msg_Dbg( p_stream, "read box: \"dref\" entry-count %d",
1082                       p_box->data.p_dref->i_entry_count );
1083
1084 #endif
1085     MP4_READBOX_EXIT( 1 );
1086 }
1087
1088 static void MP4_FreeBox_stts( MP4_Box_t *p_box )
1089 {
1090     FREENULL( p_box->data.p_stts->i_sample_count );
1091     FREENULL( p_box->data.p_stts->i_sample_delta );
1092 }
1093
1094 static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box )
1095 {
1096     MP4_READBOX_ENTER( MP4_Box_data_stts_t );
1097
1098     MP4_GETVERSIONFLAGS( p_box->data.p_stts );
1099     MP4_GET4BYTES( p_box->data.p_stts->i_entry_count );
1100
1101     p_box->data.p_stts->i_sample_count =
1102         calloc( p_box->data.p_stts->i_entry_count, sizeof(uint32_t) );
1103     p_box->data.p_stts->i_sample_delta =
1104         calloc( p_box->data.p_stts->i_entry_count, sizeof(uint32_t) );
1105     if( p_box->data.p_stts->i_sample_count == NULL
1106      || p_box->data.p_stts->i_sample_delta == NULL )
1107     {
1108         MP4_READBOX_EXIT( 0 );
1109     }
1110
1111     for( unsigned int i = 0; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ )
1112     {
1113         MP4_GET4BYTES( p_box->data.p_stts->i_sample_count[i] );
1114         MP4_GET4BYTES( p_box->data.p_stts->i_sample_delta[i] );
1115     }
1116
1117 #ifdef MP4_VERBOSE
1118     msg_Dbg( p_stream, "read box: \"stts\" entry-count %d",
1119                       p_box->data.p_stts->i_entry_count );
1120
1121 #endif
1122     MP4_READBOX_EXIT( 1 );
1123 }
1124
1125
1126 static void MP4_FreeBox_ctts( MP4_Box_t *p_box )
1127 {
1128     FREENULL( p_box->data.p_ctts->i_sample_count );
1129     FREENULL( p_box->data.p_ctts->i_sample_offset );
1130 }
1131
1132 static int MP4_ReadBox_ctts( stream_t *p_stream, MP4_Box_t *p_box )
1133 {
1134     MP4_READBOX_ENTER( MP4_Box_data_ctts_t );
1135
1136     MP4_GETVERSIONFLAGS( p_box->data.p_ctts );
1137
1138     MP4_GET4BYTES( p_box->data.p_ctts->i_entry_count );
1139
1140     p_box->data.p_ctts->i_sample_count =
1141         calloc( p_box->data.p_ctts->i_entry_count, sizeof(uint32_t) );
1142     p_box->data.p_ctts->i_sample_offset =
1143         calloc( p_box->data.p_ctts->i_entry_count, sizeof(uint32_t) );
1144     if( ( p_box->data.p_ctts->i_sample_count == NULL )
1145      || ( p_box->data.p_ctts->i_sample_offset == NULL ) )
1146     {
1147         MP4_READBOX_EXIT( 0 );
1148     }
1149
1150     for( unsigned int i = 0; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ )
1151     {
1152         MP4_GET4BYTES( p_box->data.p_ctts->i_sample_count[i] );
1153         MP4_GET4BYTES( p_box->data.p_ctts->i_sample_offset[i] );
1154     }
1155
1156 #ifdef MP4_VERBOSE
1157     msg_Dbg( p_stream, "read box: \"ctts\" entry-count %d",
1158                       p_box->data.p_ctts->i_entry_count );
1159
1160 #endif
1161     MP4_READBOX_EXIT( 1 );
1162 }
1163
1164
1165 static int MP4_ReadLengthDescriptor( uint8_t **pp_peek, int64_t  *i_read )
1166 {
1167     unsigned int i_b;
1168     unsigned int i_len = 0;
1169     do
1170     {
1171         i_b = **pp_peek;
1172
1173         (*pp_peek)++;
1174         (*i_read)--;
1175         i_len = ( i_len << 7 ) + ( i_b&0x7f );
1176     } while( i_b&0x80 );
1177     return( i_len );
1178 }
1179
1180
1181 static void MP4_FreeBox_esds( MP4_Box_t *p_box )
1182 {
1183     FREENULL( p_box->data.p_esds->es_descriptor.psz_URL );
1184     if( p_box->data.p_esds->es_descriptor.p_decConfigDescr )
1185     {
1186         FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info );
1187         FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr );
1188     }
1189 }
1190
1191 static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
1192 {
1193 #define es_descriptor p_box->data.p_esds->es_descriptor
1194     unsigned int i_len;
1195     unsigned int i_flags;
1196     unsigned int i_type;
1197
1198     MP4_READBOX_ENTER( MP4_Box_data_esds_t );
1199
1200     MP4_GETVERSIONFLAGS( p_box->data.p_esds );
1201
1202
1203     MP4_GET1BYTE( i_type );
1204     if( i_type == 0x03 ) /* MP4ESDescrTag */
1205     {
1206         i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1207
1208 #ifdef MP4_VERBOSE
1209         msg_Dbg( p_stream, "found esds MPEG4ESDescr (%dBytes)",
1210                  i_len );
1211 #endif
1212
1213         MP4_GET2BYTES( es_descriptor.i_ES_ID );
1214         MP4_GET1BYTE( i_flags );
1215         es_descriptor.b_stream_dependence = ( (i_flags&0x80) != 0);
1216         es_descriptor.b_url = ( (i_flags&0x40) != 0);
1217         es_descriptor.b_OCRstream = ( (i_flags&0x20) != 0);
1218
1219         es_descriptor.i_stream_priority = i_flags&0x1f;
1220         if( es_descriptor.b_stream_dependence )
1221         {
1222             MP4_GET2BYTES( es_descriptor.i_depend_on_ES_ID );
1223         }
1224         if( es_descriptor.b_url )
1225         {
1226             unsigned int i_len;
1227
1228             MP4_GET1BYTE( i_len );
1229             es_descriptor.psz_URL = malloc( i_len + 1 );
1230             if( es_descriptor.psz_URL )
1231             {
1232                 memcpy( es_descriptor.psz_URL, p_peek, i_len );
1233                 es_descriptor.psz_URL[i_len] = 0;
1234             }
1235             p_peek += i_len;
1236             i_read -= i_len;
1237         }
1238         else
1239         {
1240             es_descriptor.psz_URL = NULL;
1241         }
1242         if( es_descriptor.b_OCRstream )
1243         {
1244             MP4_GET2BYTES( es_descriptor.i_OCR_ES_ID );
1245         }
1246         MP4_GET1BYTE( i_type ); /* get next type */
1247     }
1248
1249     if( i_type != 0x04)/* MP4DecConfigDescrTag */
1250     {
1251          es_descriptor.p_decConfigDescr = NULL;
1252          MP4_READBOX_EXIT( 1 ); /* rest isn't interesting up to now */
1253     }
1254
1255     i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1256
1257 #ifdef MP4_VERBOSE
1258         msg_Dbg( p_stream, "found esds MP4DecConfigDescr (%dBytes)",
1259                  i_len );
1260 #endif
1261
1262     es_descriptor.p_decConfigDescr =
1263             calloc( 1, sizeof( MP4_descriptor_decoder_config_t ));
1264     if( unlikely( es_descriptor.p_decConfigDescr == NULL ) )
1265         MP4_READBOX_EXIT( 0 );
1266
1267     MP4_GET1BYTE( es_descriptor.p_decConfigDescr->i_objectTypeIndication );
1268     MP4_GET1BYTE( i_flags );
1269     es_descriptor.p_decConfigDescr->i_streamType = i_flags >> 2;
1270     es_descriptor.p_decConfigDescr->b_upStream = ( i_flags >> 1 )&0x01;
1271     MP4_GET3BYTES( es_descriptor.p_decConfigDescr->i_buffer_sizeDB );
1272     MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_max_bitrate );
1273     MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_avg_bitrate );
1274     MP4_GET1BYTE( i_type );
1275     if( i_type !=  0x05 )/* MP4DecSpecificDescrTag */
1276     {
1277         es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = 0;
1278         es_descriptor.p_decConfigDescr->p_decoder_specific_info  = NULL;
1279         MP4_READBOX_EXIT( 1 );
1280     }
1281
1282     i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1283
1284 #ifdef MP4_VERBOSE
1285         msg_Dbg( p_stream, "found esds MP4DecSpecificDescr (%dBytes)",
1286                  i_len );
1287 #endif
1288     if( i_len > i_read )
1289         MP4_READBOX_EXIT( 0 );
1290
1291     es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = i_len;
1292     es_descriptor.p_decConfigDescr->p_decoder_specific_info = malloc( i_len );
1293     if( unlikely( es_descriptor.p_decConfigDescr->p_decoder_specific_info == NULL ) )
1294         MP4_READBOX_EXIT( 0 );
1295
1296     memcpy( es_descriptor.p_decConfigDescr->p_decoder_specific_info,
1297             p_peek, i_len );
1298
1299     MP4_READBOX_EXIT( 1 );
1300 #undef es_descriptor
1301 }
1302
1303 static void MP4_FreeBox_avcC( MP4_Box_t *p_box )
1304 {
1305     MP4_Box_data_avcC_t *p_avcC = p_box->data.p_avcC;
1306     int i;
1307
1308     if( p_avcC->i_avcC > 0 ) FREENULL( p_avcC->p_avcC );
1309
1310     if( p_avcC->sps )
1311     {
1312         for( i = 0; i < p_avcC->i_sps; i++ )
1313             FREENULL( p_avcC->sps[i] );
1314     }
1315     if( p_avcC->pps )
1316     {
1317         for( i = 0; i < p_avcC->i_pps; i++ )
1318             FREENULL( p_avcC->pps[i] );
1319     }
1320     if( p_avcC->i_sps > 0 ) FREENULL( p_avcC->sps );
1321     if( p_avcC->i_sps > 0 ) FREENULL( p_avcC->i_sps_length );
1322     if( p_avcC->i_pps > 0 ) FREENULL( p_avcC->pps );
1323     if( p_avcC->i_pps > 0 ) FREENULL( p_avcC->i_pps_length );
1324 }
1325
1326 static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box )
1327 {
1328     MP4_Box_data_avcC_t *p_avcC;
1329     int i;
1330
1331     MP4_READBOX_ENTER( MP4_Box_data_avcC_t );
1332     p_avcC = p_box->data.p_avcC;
1333
1334     p_avcC->i_avcC = i_read;
1335     if( p_avcC->i_avcC > 0 )
1336     {
1337         uint8_t * p = p_avcC->p_avcC = malloc( p_avcC->i_avcC );
1338         if( p )
1339             memcpy( p, p_peek, i_read );
1340     }
1341
1342     MP4_GET1BYTE( p_avcC->i_version );
1343     MP4_GET1BYTE( p_avcC->i_profile );
1344     MP4_GET1BYTE( p_avcC->i_profile_compatibility );
1345     MP4_GET1BYTE( p_avcC->i_level );
1346     MP4_GET1BYTE( p_avcC->i_reserved1 );
1347     p_avcC->i_length_size = (p_avcC->i_reserved1&0x03) + 1;
1348     p_avcC->i_reserved1 >>= 2;
1349
1350     MP4_GET1BYTE( p_avcC->i_reserved2 );
1351     p_avcC->i_sps = p_avcC->i_reserved2&0x1f;
1352     p_avcC->i_reserved2 >>= 5;
1353
1354     if( p_avcC->i_sps > 0 )
1355     {
1356         p_avcC->i_sps_length = calloc( p_avcC->i_sps, sizeof( uint16_t ) );
1357         p_avcC->sps = calloc( p_avcC->i_sps, sizeof( uint8_t* ) );
1358
1359         if( !p_avcC->i_sps_length || !p_avcC->sps )
1360             goto error;
1361
1362         for( i = 0; i < p_avcC->i_sps; i++ )
1363         {
1364             MP4_GET2BYTES( p_avcC->i_sps_length[i] );
1365             p_avcC->sps[i] = malloc( p_avcC->i_sps_length[i] );
1366             if( p_avcC->sps[i] )
1367                 memcpy( p_avcC->sps[i], p_peek, p_avcC->i_sps_length[i] );
1368
1369             p_peek += p_avcC->i_sps_length[i];
1370             i_read -= p_avcC->i_sps_length[i];
1371         }
1372     }
1373
1374     MP4_GET1BYTE( p_avcC->i_pps );
1375     if( p_avcC->i_pps > 0 )
1376     {
1377         p_avcC->i_pps_length = calloc( p_avcC->i_pps, sizeof( uint16_t ) );
1378         p_avcC->pps = calloc( p_avcC->i_pps, sizeof( uint8_t* ) );
1379
1380         if( !p_avcC->i_pps_length || !p_avcC->pps )
1381             goto error;
1382
1383         for( i = 0; i < p_avcC->i_pps; i++ )
1384         {
1385             MP4_GET2BYTES( p_avcC->i_pps_length[i] );
1386             p_avcC->pps[i] = malloc( p_avcC->i_pps_length[i] );
1387             if( p_avcC->pps[i] )
1388                 memcpy( p_avcC->pps[i], p_peek, p_avcC->i_pps_length[i] );
1389
1390             p_peek += p_avcC->i_pps_length[i];
1391             i_read -= p_avcC->i_pps_length[i];
1392         }
1393     }
1394 #ifdef MP4_VERBOSE
1395     msg_Dbg( p_stream,
1396              "read box: \"avcC\" version=%d profile=0x%x level=0x%x length size=%d sps=%d pps=%d",
1397              p_avcC->i_version, p_avcC->i_profile, p_avcC->i_level,
1398              p_avcC->i_length_size,
1399              p_avcC->i_sps, p_avcC->i_pps );
1400     for( i = 0; i < p_avcC->i_sps; i++ )
1401     {
1402         msg_Dbg( p_stream, "         - sps[%d] length=%d",
1403                  i, p_avcC->i_sps_length[i] );
1404     }
1405     for( i = 0; i < p_avcC->i_pps; i++ )
1406     {
1407         msg_Dbg( p_stream, "         - pps[%d] length=%d",
1408                  i, p_avcC->i_pps_length[i] );
1409     }
1410
1411 #endif
1412     MP4_READBOX_EXIT( 1 );
1413
1414 error:
1415     MP4_READBOX_EXIT( 0 );
1416 }
1417
1418 static int MP4_ReadBox_dac3( stream_t *p_stream, MP4_Box_t *p_box )
1419 {
1420     MP4_Box_data_dac3_t *p_dac3;
1421     MP4_READBOX_ENTER( MP4_Box_data_dac3_t );
1422
1423     p_dac3 = p_box->data.p_dac3;
1424
1425     unsigned i_header;
1426     MP4_GET3BYTES( i_header );
1427
1428     p_dac3->i_fscod = ( i_header >> 22 ) & 0x03;
1429     p_dac3->i_bsid  = ( i_header >> 17 ) & 0x01f;
1430     p_dac3->i_bsmod = ( i_header >> 14 ) & 0x07;
1431     p_dac3->i_acmod = ( i_header >> 11 ) & 0x07;
1432     p_dac3->i_lfeon = ( i_header >> 10 ) & 0x01;
1433     p_dac3->i_bitrate_code = ( i_header >> 5) & 0x1f;
1434
1435 #ifdef MP4_VERBOSE
1436     msg_Dbg( p_stream,
1437              "read box: \"dac3\" fscod=0x%x bsid=0x%x bsmod=0x%x acmod=0x%x lfeon=0x%x bitrate_code=0x%x",
1438              p_dac3->i_fscod, p_dac3->i_bsid, p_dac3->i_bsmod, p_dac3->i_acmod, p_dac3->i_lfeon, p_dac3->i_bitrate_code );
1439 #endif
1440     MP4_READBOX_EXIT( 1 );
1441 }
1442
1443 static int MP4_ReadBox_dvc1( stream_t *p_stream, MP4_Box_t *p_box )
1444 {
1445     MP4_Box_data_dvc1_t *p_dvc1;
1446
1447     MP4_READBOX_ENTER( MP4_Box_data_dvc1_t );
1448     p_dvc1 = p_box->data.p_dvc1;
1449
1450     MP4_GET1BYTE( p_dvc1->i_profile_level ); /* profile is on 4bits, level 3bits */
1451     uint8_t i_profile = (p_dvc1->i_profile_level & 0xf0) >> 4;
1452     if( i_profile != 0x06 && i_profile != 0x0c )
1453     {
1454         msg_Warn( p_stream, "unsupported VC-1 profile (%"PRIu8"), please report", i_profile );
1455         MP4_READBOX_EXIT( 0 );
1456     }
1457
1458
1459     p_dvc1->i_vc1 = p_box->i_size - 7; /* Header + profile_level */
1460
1461     if( p_dvc1->i_vc1 > 0 )
1462     {
1463         uint8_t *p = p_dvc1->p_vc1 = malloc( p_dvc1->i_vc1 );
1464         if( p )
1465             memcpy( p, p_peek, i_read );
1466     }
1467
1468 #ifdef MP4_VERBOSE
1469     msg_Dbg( p_stream,
1470              "read box: \"dvc1\" profile=%"PRIu8" level=%i",
1471              i_profile, p_dvc1->i_profile_level & 0x0e >> 1 );
1472 #endif
1473
1474     MP4_READBOX_EXIT( 1 );
1475 }
1476
1477 static int MP4_ReadBox_enda( stream_t *p_stream, MP4_Box_t *p_box )
1478 {
1479     MP4_Box_data_enda_t *p_enda;
1480     MP4_READBOX_ENTER( MP4_Box_data_enda_t );
1481
1482     p_enda = p_box->data.p_enda;
1483
1484     MP4_GET2BYTES( p_enda->i_little_endian );
1485
1486 #ifdef MP4_VERBOSE
1487     msg_Dbg( p_stream,
1488              "read box: \"enda\" little_endian=%d", p_enda->i_little_endian );
1489 #endif
1490     MP4_READBOX_EXIT( 1 );
1491 }
1492
1493 static int MP4_ReadBox_gnre( stream_t *p_stream, MP4_Box_t *p_box )
1494 {
1495     MP4_Box_data_gnre_t *p_gnre;
1496     MP4_READBOX_ENTER( MP4_Box_data_gnre_t );
1497
1498     p_gnre = p_box->data.p_gnre;
1499
1500     uint32_t i_data_len;
1501     uint32_t i_data_tag;
1502
1503     MP4_GET4BYTES( i_data_len );
1504     MP4_GETFOURCC( i_data_tag );
1505     if( i_data_len < 10 || i_data_tag != ATOM_data )
1506         MP4_READBOX_EXIT( 0 );
1507
1508     uint32_t i_version;
1509     uint32_t i_reserved;
1510     MP4_GET4BYTES( i_version );
1511     MP4_GET4BYTES( i_reserved );
1512     MP4_GET2BYTES( p_gnre->i_genre );
1513     if( p_gnre->i_genre == 0 )
1514         MP4_READBOX_EXIT( 0 );
1515 #ifdef MP4_VERBOSE
1516     msg_Dbg( p_stream, "read box: \"gnre\" genre=%i", p_gnre->i_genre );
1517 #endif
1518
1519     MP4_READBOX_EXIT( 1 );
1520 }
1521
1522 static int MP4_ReadBox_trkn( stream_t *p_stream, MP4_Box_t *p_box )
1523 {
1524     MP4_Box_data_trkn_t *p_trkn;
1525     MP4_READBOX_ENTER( MP4_Box_data_trkn_t );
1526
1527     p_trkn = p_box->data.p_trkn;
1528
1529     uint32_t i_data_len;
1530     uint32_t i_data_tag;
1531
1532     MP4_GET4BYTES( i_data_len );
1533     MP4_GETFOURCC( i_data_tag );
1534     if( i_data_len < 12 || i_data_tag != ATOM_data )
1535         MP4_READBOX_EXIT( 0 );
1536
1537     uint32_t i_version;
1538     uint32_t i_reserved;
1539     MP4_GET4BYTES( i_version );
1540     MP4_GET4BYTES( i_reserved );
1541     MP4_GET2BYTES( i_reserved );
1542     MP4_GET2BYTES( p_trkn->i_track_number );
1543 #ifdef MP4_VERBOSE
1544     msg_Dbg( p_stream, "read box: \"trkn\" number=%i", p_trkn->i_track_number );
1545 #endif
1546     if( i_data_len > 15 )
1547     {
1548        MP4_GET2BYTES( p_trkn->i_track_total );
1549 #ifdef MP4_VERBOSE
1550        msg_Dbg( p_stream, "read box: \"trkn\" total=%i", p_trkn->i_track_total );
1551 #endif
1552     }
1553
1554     MP4_READBOX_EXIT( 1 );
1555 }
1556
1557
1558 static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
1559 {
1560     MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t );
1561     p_box->data.p_sample_soun->p_qt_description = NULL;
1562
1563     /* Sanity check needed because the "wave" box does also contain an
1564      * "mp4a" box that we don't understand. */
1565     if( i_read < 28 )
1566     {
1567         i_read -= 30;
1568         MP4_READBOX_EXIT( 1 );
1569     }
1570
1571     for( unsigned i = 0; i < 6 ; i++ )
1572     {
1573         MP4_GET1BYTE( p_box->data.p_sample_soun->i_reserved1[i] );
1574     }
1575
1576     MP4_GET2BYTES( p_box->data.p_sample_soun->i_data_reference_index );
1577
1578     /*
1579      * XXX hack -> produce a copy of the nearly complete chunk
1580      */
1581     p_box->data.p_sample_soun->i_qt_description = 0;
1582     p_box->data.p_sample_soun->p_qt_description = NULL;
1583     if( i_read > 0 )
1584     {
1585         p_box->data.p_sample_soun->p_qt_description = malloc( i_read );
1586         if( p_box->data.p_sample_soun->p_qt_description )
1587         {
1588             p_box->data.p_sample_soun->i_qt_description = i_read;
1589             memcpy( p_box->data.p_sample_soun->p_qt_description, p_peek, i_read );
1590         }
1591     }
1592
1593     MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_version );
1594     MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_revision_level );
1595     MP4_GET4BYTES( p_box->data.p_sample_soun->i_qt_vendor );
1596
1597     MP4_GET2BYTES( p_box->data.p_sample_soun->i_channelcount );
1598     MP4_GET2BYTES( p_box->data.p_sample_soun->i_samplesize );
1599     MP4_GET2BYTES( p_box->data.p_sample_soun->i_predefined );
1600     MP4_GET2BYTES( p_box->data.p_sample_soun->i_reserved3 );
1601     MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratehi );
1602     MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratelo );
1603
1604     if( p_box->data.p_sample_soun->i_qt_version == 1 && i_read >= 16 )
1605     {
1606         /* SoundDescriptionV1 */
1607         MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
1608         MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_packet );
1609         MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_frame );
1610         MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_sample );
1611
1612 #ifdef MP4_VERBOSE
1613         msg_Dbg( p_stream,
1614                  "read box: \"soun\" qt3+ sample/packet=%d bytes/packet=%d "
1615                  "bytes/frame=%d bytes/sample=%d",
1616                  p_box->data.p_sample_soun->i_sample_per_packet,
1617                  p_box->data.p_sample_soun->i_bytes_per_packet,
1618                  p_box->data.p_sample_soun->i_bytes_per_frame,
1619                  p_box->data.p_sample_soun->i_bytes_per_sample );
1620 #endif
1621         stream_Seek( p_stream, p_box->i_pos +
1622                         mp4_box_headersize( p_box ) + 44 );
1623     }
1624     else if( p_box->data.p_sample_soun->i_qt_version == 2 && i_read >= 36 )
1625     {
1626         /* SoundDescriptionV2 */
1627         double f_sample_rate;
1628         int64_t dummy;
1629         uint32_t i_channel;
1630
1631         MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
1632         MP4_GET8BYTES( dummy );
1633         memcpy( &f_sample_rate, &dummy, 8 );
1634
1635         msg_Dbg( p_stream, "read box: %f Hz", f_sample_rate );
1636         p_box->data.p_sample_soun->i_sampleratehi = (int)f_sample_rate % 65536;
1637         p_box->data.p_sample_soun->i_sampleratelo = f_sample_rate / 65536;
1638
1639         MP4_GET4BYTES( i_channel );
1640         p_box->data.p_sample_soun->i_channelcount = i_channel;
1641
1642 #ifdef MP4_VERBOSE
1643         msg_Dbg( p_stream, "read box: \"soun\" V2" );
1644 #endif
1645         stream_Seek( p_stream, p_box->i_pos +
1646                         mp4_box_headersize( p_box ) + 28 + 36 );
1647     }
1648     else
1649     {
1650         p_box->data.p_sample_soun->i_sample_per_packet = 0;
1651         p_box->data.p_sample_soun->i_bytes_per_packet = 0;
1652         p_box->data.p_sample_soun->i_bytes_per_frame = 0;
1653         p_box->data.p_sample_soun->i_bytes_per_sample = 0;
1654
1655 #ifdef MP4_VERBOSE
1656         msg_Dbg( p_stream, "read box: \"soun\" mp4 or qt1/2 (rest=%"PRId64")",
1657                  i_read );
1658 #endif
1659         stream_Seek( p_stream, p_box->i_pos +
1660                         mp4_box_headersize( p_box ) + 28 );
1661     }
1662
1663     if( p_box->i_type == ATOM_drms )
1664     {
1665         msg_Warn( p_stream, "DRM protected streams are not supported." );
1666         MP4_READBOX_EXIT( 0 );
1667     }
1668
1669     if( p_box->i_type == ATOM_samr || p_box->i_type == ATOM_sawb )
1670     {
1671         /* Ignore channelcount for AMR (3gpp AMRSpecificBox) */
1672         p_box->data.p_sample_soun->i_channelcount = 1;
1673     }
1674
1675     MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds/wave/... */
1676
1677 #ifdef MP4_VERBOSE
1678     msg_Dbg( p_stream, "read box: \"soun\" in stsd channel %d "
1679              "sample size %d sample rate %f",
1680              p_box->data.p_sample_soun->i_channelcount,
1681              p_box->data.p_sample_soun->i_samplesize,
1682              (float)p_box->data.p_sample_soun->i_sampleratehi +
1683              (float)p_box->data.p_sample_soun->i_sampleratelo / 65536 );
1684
1685 #endif
1686     MP4_READBOX_EXIT( 1 );
1687 }
1688
1689
1690 static void MP4_FreeBox_sample_soun( MP4_Box_t *p_box )
1691 {
1692     FREENULL( p_box->data.p_sample_soun->p_qt_description );
1693 }
1694
1695
1696 int MP4_ReadBox_sample_vide( stream_t *p_stream, MP4_Box_t *p_box )
1697 {
1698     MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t );
1699
1700     for( unsigned i = 0; i < 6 ; i++ )
1701     {
1702         MP4_GET1BYTE( p_box->data.p_sample_vide->i_reserved1[i] );
1703     }
1704
1705     MP4_GET2BYTES( p_box->data.p_sample_vide->i_data_reference_index );
1706
1707     /*
1708      * XXX hack -> produce a copy of the nearly complete chunk
1709      */
1710     if( i_read > 0 )
1711     {
1712         p_box->data.p_sample_vide->p_qt_image_description = malloc( i_read );
1713         if( unlikely( p_box->data.p_sample_vide->p_qt_image_description == NULL ) )
1714             MP4_READBOX_EXIT( 0 );
1715         p_box->data.p_sample_vide->i_qt_image_description = i_read;
1716         memcpy( p_box->data.p_sample_vide->p_qt_image_description,
1717                 p_peek, i_read );
1718     }
1719     else
1720     {
1721         p_box->data.p_sample_vide->i_qt_image_description = 0;
1722         p_box->data.p_sample_vide->p_qt_image_description = NULL;
1723     }
1724
1725     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_version );
1726     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_revision_level );
1727     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_vendor );
1728
1729     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_temporal_quality );
1730     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_spatial_quality );
1731
1732     MP4_GET2BYTES( p_box->data.p_sample_vide->i_width );
1733     MP4_GET2BYTES( p_box->data.p_sample_vide->i_height );
1734
1735     MP4_GET4BYTES( p_box->data.p_sample_vide->i_horizresolution );
1736     MP4_GET4BYTES( p_box->data.p_sample_vide->i_vertresolution );
1737
1738     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_data_size );
1739     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_frame_count );
1740
1741     memcpy( &p_box->data.p_sample_vide->i_compressorname, p_peek, 32 );
1742     p_peek += 32; i_read -= 32;
1743
1744     MP4_GET2BYTES( p_box->data.p_sample_vide->i_depth );
1745     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_color_table );
1746
1747     stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 78);
1748
1749     if( p_box->i_type == ATOM_drmi )
1750     {
1751         msg_Warn( p_stream, "DRM protected streams are not supported." );
1752         MP4_READBOX_EXIT( 0 );
1753     }
1754
1755     MP4_ReadBoxContainerRaw( p_stream, p_box );
1756
1757 #ifdef MP4_VERBOSE
1758     msg_Dbg( p_stream, "read box: \"vide\" in stsd %dx%d depth %d",
1759                       p_box->data.p_sample_vide->i_width,
1760                       p_box->data.p_sample_vide->i_height,
1761                       p_box->data.p_sample_vide->i_depth );
1762
1763 #endif
1764     MP4_READBOX_EXIT( 1 );
1765 }
1766
1767
1768 void MP4_FreeBox_sample_vide( MP4_Box_t *p_box )
1769 {
1770     FREENULL( p_box->data.p_sample_vide->p_qt_image_description );
1771 }
1772
1773 static int MP4_ReadBox_sample_mp4s( stream_t *p_stream, MP4_Box_t *p_box )
1774 {
1775     stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
1776     MP4_ReadBoxContainerRaw( p_stream, p_box );
1777     return 1;
1778 }
1779
1780 static int MP4_ReadBox_sample_text( stream_t *p_stream, MP4_Box_t *p_box )
1781 {
1782     int32_t t;
1783
1784     MP4_READBOX_ENTER( MP4_Box_data_sample_text_t );
1785
1786     MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved1 );
1787     MP4_GET2BYTES( p_box->data.p_sample_text->i_reserved2 );
1788
1789     MP4_GET2BYTES( p_box->data.p_sample_text->i_data_reference_index );
1790
1791     MP4_GET4BYTES( p_box->data.p_sample_text->i_display_flags );
1792
1793     MP4_GET4BYTES( t );
1794     switch( t )
1795     {
1796         /* FIXME search right signification */
1797         case 1: // Center
1798             p_box->data.p_sample_text->i_justification_horizontal = 1;
1799             p_box->data.p_sample_text->i_justification_vertical = 1;
1800             break;
1801         case -1:    // Flush Right
1802             p_box->data.p_sample_text->i_justification_horizontal = -1;
1803             p_box->data.p_sample_text->i_justification_vertical = -1;
1804             break;
1805         case -2:    // Flush Left
1806             p_box->data.p_sample_text->i_justification_horizontal = 0;
1807             p_box->data.p_sample_text->i_justification_vertical = 0;
1808             break;
1809         case 0: // Flush Default
1810         default:
1811             p_box->data.p_sample_text->i_justification_horizontal = 1;
1812             p_box->data.p_sample_text->i_justification_vertical = -1;
1813             break;
1814     }
1815
1816     MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[0] );
1817     MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[1] );
1818     MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[2] );
1819     p_box->data.p_sample_text->i_background_color[3] = 0;
1820
1821     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_top );
1822     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_left );
1823     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_bottom );
1824     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_right );
1825
1826 #ifdef MP4_VERBOSE
1827     msg_Dbg( p_stream, "read box: \"text\" in stsd text" );
1828 #endif
1829     MP4_READBOX_EXIT( 1 );
1830 }
1831
1832 static int MP4_ReadBox_sample_tx3g( stream_t *p_stream, MP4_Box_t *p_box )
1833 {
1834     MP4_READBOX_ENTER( MP4_Box_data_sample_text_t );
1835
1836     MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved1 );
1837     MP4_GET2BYTES( p_box->data.p_sample_text->i_reserved2 );
1838
1839     MP4_GET2BYTES( p_box->data.p_sample_text->i_data_reference_index );
1840
1841     MP4_GET4BYTES( p_box->data.p_sample_text->i_display_flags );
1842
1843     MP4_GET1BYTE ( p_box->data.p_sample_text->i_justification_horizontal );
1844     MP4_GET1BYTE ( p_box->data.p_sample_text->i_justification_vertical );
1845
1846     MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[0] );
1847     MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[1] );
1848     MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[2] );
1849     MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[3] );
1850
1851     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_top );
1852     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_left );
1853     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_bottom );
1854     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_right );
1855
1856 #ifdef MP4_VERBOSE
1857     msg_Dbg( p_stream, "read box: \"tx3g\" in stsd text" );
1858 #endif
1859     MP4_READBOX_EXIT( 1 );
1860 }
1861
1862
1863 #if 0
1864 /* We can't easily call it, and anyway ~ 20 bytes lost isn't a real problem */
1865 static void MP4_FreeBox_sample_text( MP4_Box_t *p_box )
1866 {
1867     FREENULL( p_box->data.p_sample_text->psz_text_name );
1868 }
1869 #endif
1870
1871
1872 static int MP4_ReadBox_stsd( stream_t *p_stream, MP4_Box_t *p_box )
1873 {
1874
1875     MP4_READBOX_ENTER( MP4_Box_data_stsd_t );
1876
1877     MP4_GETVERSIONFLAGS( p_box->data.p_stsd );
1878
1879     MP4_GET4BYTES( p_box->data.p_stsd->i_entry_count );
1880
1881     stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
1882
1883     MP4_ReadBoxContainerRaw( p_stream, p_box );
1884
1885 #ifdef MP4_VERBOSE
1886     msg_Dbg( p_stream, "read box: \"stsd\" entry-count %d",
1887                       p_box->data.p_stsd->i_entry_count );
1888
1889 #endif
1890     MP4_READBOX_EXIT( 1 );
1891 }
1892
1893
1894 static int MP4_ReadBox_stsz( stream_t *p_stream, MP4_Box_t *p_box )
1895 {
1896     MP4_READBOX_ENTER( MP4_Box_data_stsz_t );
1897
1898     MP4_GETVERSIONFLAGS( p_box->data.p_stsz );
1899
1900     MP4_GET4BYTES( p_box->data.p_stsz->i_sample_size );
1901     MP4_GET4BYTES( p_box->data.p_stsz->i_sample_count );
1902
1903     if( p_box->data.p_stsz->i_sample_size == 0 )
1904     {
1905         p_box->data.p_stsz->i_entry_size =
1906             calloc( p_box->data.p_stsz->i_sample_count, sizeof(uint32_t) );
1907         if( unlikely( !p_box->data.p_stsz->i_entry_size ) )
1908             MP4_READBOX_EXIT( 0 );
1909
1910         for( unsigned int i = 0; (i<p_box->data.p_stsz->i_sample_count)&&(i_read >= 4 ); i++ )
1911         {
1912             MP4_GET4BYTES( p_box->data.p_stsz->i_entry_size[i] );
1913         }
1914     }
1915     else
1916         p_box->data.p_stsz->i_entry_size = NULL;
1917
1918 #ifdef MP4_VERBOSE
1919     msg_Dbg( p_stream, "read box: \"stsz\" sample-size %d sample-count %d",
1920                       p_box->data.p_stsz->i_sample_size,
1921                       p_box->data.p_stsz->i_sample_count );
1922
1923 #endif
1924     MP4_READBOX_EXIT( 1 );
1925 }
1926
1927 static void MP4_FreeBox_stsz( MP4_Box_t *p_box )
1928 {
1929     FREENULL( p_box->data.p_stsz->i_entry_size );
1930 }
1931
1932 static void MP4_FreeBox_stsc( MP4_Box_t *p_box )
1933 {
1934     FREENULL( p_box->data.p_stsc->i_first_chunk );
1935     FREENULL( p_box->data.p_stsc->i_samples_per_chunk );
1936     FREENULL( p_box->data.p_stsc->i_sample_description_index );
1937 }
1938
1939 static int MP4_ReadBox_stsc( stream_t *p_stream, MP4_Box_t *p_box )
1940 {
1941     MP4_READBOX_ENTER( MP4_Box_data_stsc_t );
1942
1943     MP4_GETVERSIONFLAGS( p_box->data.p_stsc );
1944
1945     MP4_GET4BYTES( p_box->data.p_stsc->i_entry_count );
1946
1947     p_box->data.p_stsc->i_first_chunk =
1948         calloc( p_box->data.p_stsc->i_entry_count, sizeof(uint32_t) );
1949     p_box->data.p_stsc->i_samples_per_chunk =
1950         calloc( p_box->data.p_stsc->i_entry_count, sizeof(uint32_t) );
1951     p_box->data.p_stsc->i_sample_description_index =
1952         calloc( p_box->data.p_stsc->i_entry_count, sizeof(uint32_t) );
1953     if( unlikely( p_box->data.p_stsc->i_first_chunk == NULL
1954      || p_box->data.p_stsc->i_samples_per_chunk == NULL
1955      || p_box->data.p_stsc->i_sample_description_index == NULL ) )
1956     {
1957         MP4_READBOX_EXIT( 0 );
1958     }
1959
1960     for( unsigned int i = 0; (i < p_box->data.p_stsc->i_entry_count )&&( i_read >= 12 );i++ )
1961     {
1962         MP4_GET4BYTES( p_box->data.p_stsc->i_first_chunk[i] );
1963         MP4_GET4BYTES( p_box->data.p_stsc->i_samples_per_chunk[i] );
1964         MP4_GET4BYTES( p_box->data.p_stsc->i_sample_description_index[i] );
1965     }
1966
1967 #ifdef MP4_VERBOSE
1968     msg_Dbg( p_stream, "read box: \"stsc\" entry-count %d",
1969                       p_box->data.p_stsc->i_entry_count );
1970
1971 #endif
1972     MP4_READBOX_EXIT( 1 );
1973 }
1974
1975 static int MP4_ReadBox_stco_co64( stream_t *p_stream, MP4_Box_t *p_box )
1976 {
1977     MP4_READBOX_ENTER( MP4_Box_data_co64_t );
1978
1979     MP4_GETVERSIONFLAGS( p_box->data.p_co64 );
1980
1981     MP4_GET4BYTES( p_box->data.p_co64->i_entry_count );
1982
1983     p_box->data.p_co64->i_chunk_offset =
1984         calloc( p_box->data.p_co64->i_entry_count, sizeof(uint64_t) );
1985     if( p_box->data.p_co64->i_chunk_offset == NULL )
1986         MP4_READBOX_EXIT( 0 );
1987
1988     for( unsigned int i = 0; i < p_box->data.p_co64->i_entry_count; i++ )
1989     {
1990         if( p_box->i_type == ATOM_stco )
1991         {
1992             if( i_read < 4 )
1993             {
1994                 break;
1995             }
1996             MP4_GET4BYTES( p_box->data.p_co64->i_chunk_offset[i] );
1997         }
1998         else
1999         {
2000             if( i_read < 8 )
2001             {
2002                 break;
2003             }
2004             MP4_GET8BYTES( p_box->data.p_co64->i_chunk_offset[i] );
2005         }
2006     }
2007
2008 #ifdef MP4_VERBOSE
2009     msg_Dbg( p_stream, "read box: \"co64\" entry-count %d",
2010                       p_box->data.p_co64->i_entry_count );
2011
2012 #endif
2013     MP4_READBOX_EXIT( 1 );
2014 }
2015
2016 static void MP4_FreeBox_stco_co64( MP4_Box_t *p_box )
2017 {
2018     FREENULL( p_box->data.p_co64->i_chunk_offset );
2019 }
2020
2021 static int MP4_ReadBox_stss( stream_t *p_stream, MP4_Box_t *p_box )
2022 {
2023     MP4_READBOX_ENTER( MP4_Box_data_stss_t );
2024
2025     MP4_GETVERSIONFLAGS( p_box->data.p_stss );
2026
2027     MP4_GET4BYTES( p_box->data.p_stss->i_entry_count );
2028
2029     p_box->data.p_stss->i_sample_number =
2030         calloc( p_box->data.p_stss->i_entry_count, sizeof(uint32_t) );
2031     if( unlikely( p_box->data.p_stss->i_sample_number == NULL ) )
2032         MP4_READBOX_EXIT( 0 );
2033
2034     for( unsigned int i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 4 ); i++ )
2035     {
2036
2037         MP4_GET4BYTES( p_box->data.p_stss->i_sample_number[i] );
2038         /* XXX in libmp4 sample begin at 0 */
2039         p_box->data.p_stss->i_sample_number[i]--;
2040     }
2041
2042 #ifdef MP4_VERBOSE
2043     msg_Dbg( p_stream, "read box: \"stss\" entry-count %d",
2044                       p_box->data.p_stss->i_entry_count );
2045
2046 #endif
2047     MP4_READBOX_EXIT( 1 );
2048 }
2049
2050 static void MP4_FreeBox_stss( MP4_Box_t *p_box )
2051 {
2052     FREENULL( p_box->data.p_stss->i_sample_number );
2053 }
2054
2055 static void MP4_FreeBox_stsh( MP4_Box_t *p_box )
2056 {
2057     FREENULL( p_box->data.p_stsh->i_shadowed_sample_number );
2058     FREENULL( p_box->data.p_stsh->i_sync_sample_number );
2059 }
2060
2061 static int MP4_ReadBox_stsh( stream_t *p_stream, MP4_Box_t *p_box )
2062 {
2063     MP4_READBOX_ENTER( MP4_Box_data_stsh_t );
2064
2065     MP4_GETVERSIONFLAGS( p_box->data.p_stsh );
2066
2067
2068     MP4_GET4BYTES( p_box->data.p_stsh->i_entry_count );
2069
2070     p_box->data.p_stsh->i_shadowed_sample_number =
2071         calloc( p_box->data.p_stsh->i_entry_count, sizeof(uint32_t) );
2072     p_box->data.p_stsh->i_sync_sample_number =
2073         calloc( p_box->data.p_stsh->i_entry_count, sizeof(uint32_t) );
2074
2075     if( p_box->data.p_stsh->i_shadowed_sample_number == NULL
2076      || p_box->data.p_stsh->i_sync_sample_number == NULL )
2077     {
2078         MP4_READBOX_EXIT( 0 );
2079     }
2080
2081     for( unsigned i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 8 ); i++ )
2082     {
2083         MP4_GET4BYTES( p_box->data.p_stsh->i_shadowed_sample_number[i] );
2084         MP4_GET4BYTES( p_box->data.p_stsh->i_sync_sample_number[i] );
2085     }
2086
2087 #ifdef MP4_VERBOSE
2088     msg_Dbg( p_stream, "read box: \"stsh\" entry-count %d",
2089                       p_box->data.p_stsh->i_entry_count );
2090 #endif
2091     MP4_READBOX_EXIT( 1 );
2092 }
2093
2094
2095 static int MP4_ReadBox_stdp( stream_t *p_stream, MP4_Box_t *p_box )
2096 {
2097     MP4_READBOX_ENTER( MP4_Box_data_stdp_t );
2098
2099     MP4_GETVERSIONFLAGS( p_box->data.p_stdp );
2100
2101     p_box->data.p_stdp->i_priority =
2102         calloc( i_read / 2, sizeof(uint16_t) );
2103
2104     if( unlikely( !p_box->data.p_stdp->i_priority ) )
2105         MP4_READBOX_EXIT( 0 );
2106
2107     for( unsigned i = 0; i < i_read / 2 ; i++ )
2108     {
2109         MP4_GET2BYTES( p_box->data.p_stdp->i_priority[i] );
2110     }
2111
2112 #ifdef MP4_VERBOSE
2113     msg_Dbg( p_stream, "read box: \"stdp\" entry-count %"PRId64,
2114                       i_read / 2 );
2115
2116 #endif
2117     MP4_READBOX_EXIT( 1 );
2118 }
2119
2120 static void MP4_FreeBox_stdp( MP4_Box_t *p_box )
2121 {
2122     FREENULL( p_box->data.p_stdp->i_priority );
2123 }
2124
2125 static void MP4_FreeBox_padb( MP4_Box_t *p_box )
2126 {
2127     FREENULL( p_box->data.p_padb->i_reserved1 );
2128     FREENULL( p_box->data.p_padb->i_pad2 );
2129     FREENULL( p_box->data.p_padb->i_reserved2 );
2130     FREENULL( p_box->data.p_padb->i_pad1 );
2131 }
2132
2133 static int MP4_ReadBox_padb( stream_t *p_stream, MP4_Box_t *p_box )
2134 {
2135     uint32_t count;
2136
2137     MP4_READBOX_ENTER( MP4_Box_data_padb_t );
2138
2139     MP4_GETVERSIONFLAGS( p_box->data.p_padb );
2140
2141     MP4_GET4BYTES( p_box->data.p_padb->i_sample_count );
2142     count = (p_box->data.p_padb->i_sample_count + 1) / 2;
2143
2144     p_box->data.p_padb->i_reserved1 = calloc( count, sizeof(uint16_t) );
2145     p_box->data.p_padb->i_pad2 = calloc( count, sizeof(uint16_t) );
2146     p_box->data.p_padb->i_reserved2 = calloc( count, sizeof(uint16_t) );
2147     p_box->data.p_padb->i_pad1 = calloc( count, sizeof(uint16_t) );
2148     if( p_box->data.p_padb->i_reserved1 == NULL
2149      || p_box->data.p_padb->i_pad2 == NULL
2150      || p_box->data.p_padb->i_reserved2 == NULL
2151      || p_box->data.p_padb->i_pad1 == NULL )
2152     {
2153         MP4_READBOX_EXIT( 0 );
2154     }
2155
2156     for( unsigned int i = 0; i < i_read / 2 ; i++ )
2157     {
2158         if( i >= count )
2159         {
2160             MP4_READBOX_EXIT( 0 );
2161         }
2162         p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 7 )&0x01;
2163         p_box->data.p_padb->i_pad2[i] = ( (*p_peek) >> 4 )&0x07;
2164         p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 3 )&0x01;
2165         p_box->data.p_padb->i_pad1[i] = ( (*p_peek) )&0x07;
2166
2167         p_peek += 1; i_read -= 1;
2168     }
2169
2170 #ifdef MP4_VERBOSE
2171     msg_Dbg( p_stream, "read box: \"stdp\" entry-count %"PRId64,
2172                       i_read / 2 );
2173
2174 #endif
2175     MP4_READBOX_EXIT( 1 );
2176 }
2177
2178 static void MP4_FreeBox_elst( MP4_Box_t *p_box )
2179 {
2180     FREENULL( p_box->data.p_elst->i_segment_duration );
2181     FREENULL( p_box->data.p_elst->i_media_time );
2182     FREENULL( p_box->data.p_elst->i_media_rate_integer );
2183     FREENULL( p_box->data.p_elst->i_media_rate_fraction );
2184 }
2185
2186 static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box )
2187 {
2188     MP4_READBOX_ENTER( MP4_Box_data_elst_t );
2189
2190     MP4_GETVERSIONFLAGS( p_box->data.p_elst );
2191
2192
2193     MP4_GET4BYTES( p_box->data.p_elst->i_entry_count );
2194
2195     p_box->data.p_elst->i_segment_duration =
2196         calloc( p_box->data.p_elst->i_entry_count, sizeof(uint64_t) );
2197     p_box->data.p_elst->i_media_time =
2198         calloc( p_box->data.p_elst->i_entry_count, sizeof(uint64_t) );
2199     p_box->data.p_elst->i_media_rate_integer =
2200         calloc( p_box->data.p_elst->i_entry_count, sizeof(uint16_t) );
2201     p_box->data.p_elst->i_media_rate_fraction =
2202         calloc( p_box->data.p_elst->i_entry_count, sizeof(uint16_t) );
2203     if( p_box->data.p_elst->i_segment_duration == NULL
2204      || p_box->data.p_elst->i_media_time == NULL
2205      || p_box->data.p_elst->i_media_rate_integer == NULL
2206      || p_box->data.p_elst->i_media_rate_fraction == NULL )
2207     {
2208         MP4_READBOX_EXIT( 0 );
2209     }
2210
2211
2212     for( unsigned i = 0; i < p_box->data.p_elst->i_entry_count; i++ )
2213     {
2214         if( p_box->data.p_elst->i_version == 1 )
2215         {
2216
2217             MP4_GET8BYTES( p_box->data.p_elst->i_segment_duration[i] );
2218
2219             MP4_GET8BYTES( p_box->data.p_elst->i_media_time[i] );
2220         }
2221         else
2222         {
2223
2224             MP4_GET4BYTES( p_box->data.p_elst->i_segment_duration[i] );
2225
2226             MP4_GET4BYTES( p_box->data.p_elst->i_media_time[i] );
2227             p_box->data.p_elst->i_media_time[i] = (int32_t)p_box->data.p_elst->i_media_time[i];
2228         }
2229
2230         MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_integer[i] );
2231         MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_fraction[i] );
2232     }
2233
2234 #ifdef MP4_VERBOSE
2235     msg_Dbg( p_stream, "read box: \"elst\" entry-count %lu",
2236              (unsigned long)p_box->data.p_elst->i_entry_count );
2237 #endif
2238     MP4_READBOX_EXIT( 1 );
2239 }
2240
2241 static int MP4_ReadBox_cprt( stream_t *p_stream, MP4_Box_t *p_box )
2242 {
2243     unsigned int i_language;
2244
2245     MP4_READBOX_ENTER( MP4_Box_data_cprt_t );
2246
2247     MP4_GETVERSIONFLAGS( p_box->data.p_cprt );
2248
2249     i_language = GetWBE( p_peek );
2250     for( unsigned i = 0; i < 3; i++ )
2251     {
2252         p_box->data.p_cprt->i_language[i] =
2253             ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
2254     }
2255     p_peek += 2; i_read -= 2;
2256     MP4_GETSTRINGZ( p_box->data.p_cprt->psz_notice );
2257
2258 #ifdef MP4_VERBOSE
2259     msg_Dbg( p_stream, "read box: \"cprt\" language %c%c%c notice %s",
2260                       p_box->data.p_cprt->i_language[0],
2261                       p_box->data.p_cprt->i_language[1],
2262                       p_box->data.p_cprt->i_language[2],
2263                       p_box->data.p_cprt->psz_notice );
2264
2265 #endif
2266     MP4_READBOX_EXIT( 1 );
2267 }
2268
2269 static void MP4_FreeBox_cprt( MP4_Box_t *p_box )
2270 {
2271     FREENULL( p_box->data.p_cprt->psz_notice );
2272 }
2273
2274
2275 static int MP4_ReadBox_dcom( stream_t *p_stream, MP4_Box_t *p_box )
2276 {
2277     MP4_READBOX_ENTER( MP4_Box_data_dcom_t );
2278
2279     MP4_GETFOURCC( p_box->data.p_dcom->i_algorithm );
2280 #ifdef MP4_VERBOSE
2281     msg_Dbg( p_stream,
2282              "read box: \"dcom\" compression algorithm : %4.4s",
2283                       (char*)&p_box->data.p_dcom->i_algorithm );
2284 #endif
2285     MP4_READBOX_EXIT( 1 );
2286 }
2287
2288 static int MP4_ReadBox_cmvd( stream_t *p_stream, MP4_Box_t *p_box )
2289 {
2290     MP4_READBOX_ENTER( MP4_Box_data_cmvd_t );
2291
2292     MP4_GET4BYTES( p_box->data.p_cmvd->i_uncompressed_size );
2293
2294     p_box->data.p_cmvd->i_compressed_size = i_read;
2295
2296     if( !( p_box->data.p_cmvd->p_data = malloc( i_read ) ) )
2297         MP4_READBOX_EXIT( 0 );
2298
2299     /* now copy compressed data */
2300     memcpy( p_box->data.p_cmvd->p_data, p_peek,i_read);
2301
2302     p_box->data.p_cmvd->b_compressed = 1;
2303
2304 #ifdef MP4_VERBOSE
2305     msg_Dbg( p_stream, "read box: \"cmvd\" compressed data size %d",
2306                       p_box->data.p_cmvd->i_compressed_size );
2307 #endif
2308
2309     MP4_READBOX_EXIT( 1 );
2310 }
2311 static void MP4_FreeBox_cmvd( MP4_Box_t *p_box )
2312 {
2313     FREENULL( p_box->data.p_cmvd->p_data );
2314 }
2315
2316
2317 static int MP4_ReadBox_cmov( stream_t *p_stream, MP4_Box_t *p_box )
2318 {
2319     MP4_Box_t *p_dcom;
2320     MP4_Box_t *p_cmvd;
2321
2322 #ifdef HAVE_ZLIB_H
2323     stream_t *p_stream_memory;
2324     z_stream z_data;
2325     uint8_t *p_data;
2326     int i_result;
2327 #endif
2328
2329     if( !( p_box->data.p_cmov = calloc(1, sizeof( MP4_Box_data_cmov_t ) ) ) )
2330         return 0;
2331
2332     if( !p_box->p_father ||
2333         ( p_box->p_father->i_type != ATOM_moov &&
2334           p_box->p_father->i_type != ATOM_foov ) )
2335     {
2336         msg_Warn( p_stream, "Read box: \"cmov\" box alone" );
2337         return 1;
2338     }
2339
2340     if( !MP4_ReadBoxContainer( p_stream, p_box ) )
2341     {
2342         return 0;
2343     }
2344
2345     if( ( p_dcom = MP4_BoxGet( p_box, "dcom" ) ) == NULL ||
2346         ( p_cmvd = MP4_BoxGet( p_box, "cmvd" ) ) == NULL ||
2347         p_cmvd->data.p_cmvd->p_data == NULL )
2348     {
2349         msg_Warn( p_stream, "read box: \"cmov\" incomplete" );
2350         return 0;
2351     }
2352
2353     if( p_dcom->data.p_dcom->i_algorithm != ATOM_zlib )
2354     {
2355         msg_Dbg( p_stream, "read box: \"cmov\" compression algorithm : %4.4s "
2356                  "not supported", (char*)&p_dcom->data.p_dcom->i_algorithm );
2357         return 0;
2358     }
2359
2360 #ifndef HAVE_ZLIB_H
2361     msg_Dbg( p_stream, "read box: \"cmov\" zlib unsupported" );
2362     return 0;
2363
2364 #else
2365     /* decompress data */
2366     /* allocate a new buffer */
2367     if( !( p_data = malloc( p_cmvd->data.p_cmvd->i_uncompressed_size ) ) )
2368         return 0;
2369     /* init default structures */
2370     z_data.next_in   = p_cmvd->data.p_cmvd->p_data;
2371     z_data.avail_in  = p_cmvd->data.p_cmvd->i_compressed_size;
2372     z_data.next_out  = p_data;
2373     z_data.avail_out = p_cmvd->data.p_cmvd->i_uncompressed_size;
2374     z_data.zalloc    = (alloc_func)Z_NULL;
2375     z_data.zfree     = (free_func)Z_NULL;
2376     z_data.opaque    = (voidpf)Z_NULL;
2377
2378     /* init zlib */
2379     if( inflateInit( &z_data ) != Z_OK )
2380     {
2381         msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
2382         free( p_data );
2383         return 0;
2384     }
2385
2386     /* uncompress */
2387     i_result = inflate( &z_data, Z_NO_FLUSH );
2388     if( i_result != Z_OK && i_result != Z_STREAM_END )
2389     {
2390         msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
2391         free( p_data );
2392         return 0;
2393     }
2394
2395     if( p_cmvd->data.p_cmvd->i_uncompressed_size != z_data.total_out )
2396     {
2397         msg_Warn( p_stream, "read box: \"cmov\" uncompressing data size "
2398                   "mismatch" );
2399     }
2400     p_cmvd->data.p_cmvd->i_uncompressed_size = z_data.total_out;
2401
2402     /* close zlib */
2403     if( inflateEnd( &z_data ) != Z_OK )
2404     {
2405         msg_Warn( p_stream, "read box: \"cmov\" error while uncompressing "
2406                   "data (ignored)" );
2407     }
2408
2409     free( p_cmvd->data.p_cmvd->p_data );
2410     p_cmvd->data.p_cmvd->p_data = p_data;
2411     p_cmvd->data.p_cmvd->b_compressed = 0;
2412
2413     msg_Dbg( p_stream, "read box: \"cmov\" box successfully uncompressed" );
2414
2415     /* now create a memory stream */
2416     p_stream_memory =
2417         stream_MemoryNew( VLC_OBJECT(p_stream), p_cmvd->data.p_cmvd->p_data,
2418                           p_cmvd->data.p_cmvd->i_uncompressed_size, true );
2419
2420     /* and read uncompressd moov */
2421     p_box->data.p_cmov->p_moov = MP4_ReadBox( p_stream_memory, NULL );
2422
2423     stream_Delete( p_stream_memory );
2424
2425 #ifdef MP4_VERBOSE
2426     msg_Dbg( p_stream, "read box: \"cmov\" compressed movie header completed");
2427 #endif
2428
2429     return p_box->data.p_cmov->p_moov ? 1 : 0;
2430 #endif /* HAVE_ZLIB_H */
2431 }
2432
2433 static int MP4_ReadBox_rdrf( stream_t *p_stream, MP4_Box_t *p_box )
2434 {
2435     uint32_t i_len;
2436     MP4_READBOX_ENTER( MP4_Box_data_rdrf_t );
2437
2438     MP4_GETVERSIONFLAGS( p_box->data.p_rdrf );
2439     MP4_GETFOURCC( p_box->data.p_rdrf->i_ref_type );
2440     MP4_GET4BYTES( i_len );
2441     i_len++;
2442
2443     if( i_len > 0 )
2444     {
2445         p_box->data.p_rdrf->psz_ref = malloc( i_len );
2446         if( p_box->data.p_rdrf->psz_ref == NULL )
2447             MP4_READBOX_EXIT( 0 );
2448         i_len--;
2449
2450         for( unsigned i = 0; i < i_len; i++ )
2451         {
2452             MP4_GET1BYTE( p_box->data.p_rdrf->psz_ref[i] );
2453         }
2454         p_box->data.p_rdrf->psz_ref[i_len] = '\0';
2455     }
2456     else
2457     {
2458         p_box->data.p_rdrf->psz_ref = NULL;
2459     }
2460
2461 #ifdef MP4_VERBOSE
2462     msg_Dbg( p_stream,
2463             "read box: \"rdrf\" type:%4.4s ref %s",
2464             (char*)&p_box->data.p_rdrf->i_ref_type,
2465             p_box->data.p_rdrf->psz_ref );
2466 #endif
2467     MP4_READBOX_EXIT( 1 );
2468 }
2469
2470 static void MP4_FreeBox_rdrf( MP4_Box_t *p_box )
2471 {
2472     FREENULL( p_box->data.p_rdrf->psz_ref );
2473 }
2474
2475
2476 static int MP4_ReadBox_rmdr( stream_t *p_stream, MP4_Box_t *p_box )
2477 {
2478     MP4_READBOX_ENTER( MP4_Box_data_rmdr_t );
2479
2480     MP4_GETVERSIONFLAGS( p_box->data.p_rmdr );
2481
2482     MP4_GET4BYTES( p_box->data.p_rmdr->i_rate );
2483
2484 #ifdef MP4_VERBOSE
2485     msg_Dbg( p_stream,
2486              "read box: \"rmdr\" rate:%d",
2487              p_box->data.p_rmdr->i_rate );
2488 #endif
2489     MP4_READBOX_EXIT( 1 );
2490 }
2491
2492 static int MP4_ReadBox_rmqu( stream_t *p_stream, MP4_Box_t *p_box )
2493 {
2494     MP4_READBOX_ENTER( MP4_Box_data_rmqu_t );
2495
2496     MP4_GET4BYTES( p_box->data.p_rmqu->i_quality );
2497
2498 #ifdef MP4_VERBOSE
2499     msg_Dbg( p_stream,
2500              "read box: \"rmqu\" quality:%d",
2501              p_box->data.p_rmqu->i_quality );
2502 #endif
2503     MP4_READBOX_EXIT( 1 );
2504 }
2505
2506 static int MP4_ReadBox_rmvc( stream_t *p_stream, MP4_Box_t *p_box )
2507 {
2508     MP4_READBOX_ENTER( MP4_Box_data_rmvc_t );
2509     MP4_GETVERSIONFLAGS( p_box->data.p_rmvc );
2510
2511     MP4_GETFOURCC( p_box->data.p_rmvc->i_gestaltType );
2512     MP4_GET4BYTES( p_box->data.p_rmvc->i_val1 );
2513     MP4_GET4BYTES( p_box->data.p_rmvc->i_val2 );
2514     MP4_GET2BYTES( p_box->data.p_rmvc->i_checkType );
2515
2516 #ifdef MP4_VERBOSE
2517     msg_Dbg( p_stream,
2518              "read box: \"rmvc\" gestaltType:%4.4s val1:0x%x val2:0x%x checkType:0x%x",
2519              (char*)&p_box->data.p_rmvc->i_gestaltType,
2520              p_box->data.p_rmvc->i_val1,p_box->data.p_rmvc->i_val2,
2521              p_box->data.p_rmvc->i_checkType );
2522 #endif
2523
2524     MP4_READBOX_EXIT( 1 );
2525 }
2526
2527 static int MP4_ReadBox_frma( stream_t *p_stream, MP4_Box_t *p_box )
2528 {
2529     MP4_READBOX_ENTER( MP4_Box_data_frma_t );
2530
2531     MP4_GETFOURCC( p_box->data.p_frma->i_type );
2532
2533 #ifdef MP4_VERBOSE
2534     msg_Dbg( p_stream, "read box: \"frma\" i_type:%4.4s",
2535              (char *)&p_box->data.p_frma->i_type );
2536 #endif
2537
2538     MP4_READBOX_EXIT( 1 );
2539 }
2540
2541 static int MP4_ReadBox_skcr( stream_t *p_stream, MP4_Box_t *p_box )
2542 {
2543     MP4_READBOX_ENTER( MP4_Box_data_skcr_t );
2544
2545     MP4_GET4BYTES( p_box->data.p_skcr->i_init );
2546     MP4_GET4BYTES( p_box->data.p_skcr->i_encr );
2547     MP4_GET4BYTES( p_box->data.p_skcr->i_decr );
2548
2549 #ifdef MP4_VERBOSE
2550     msg_Dbg( p_stream, "read box: \"skcr\" i_init:%d i_encr:%d i_decr:%d",
2551              p_box->data.p_skcr->i_init,
2552              p_box->data.p_skcr->i_encr,
2553              p_box->data.p_skcr->i_decr );
2554 #endif
2555
2556     MP4_READBOX_EXIT( 1 );
2557 }
2558
2559 static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box )
2560 {
2561     VLC_UNUSED(p_box);
2562     /* ATOMs 'user', 'key', 'iviv', and 'priv' will be skipped,
2563      * so unless data decrypt itself by magic, there will be no playback,
2564      * but we never know... */
2565     msg_Warn( p_stream, "DRM protected streams are not supported." );
2566     return 1;
2567 }
2568
2569 static int MP4_ReadBox_name( stream_t *p_stream, MP4_Box_t *p_box )
2570 {
2571     MP4_READBOX_ENTER( MP4_Box_data_name_t );
2572
2573     p_box->data.p_name->psz_text = malloc( p_box->i_size + 1 - 8 ); /* +\0, -name, -size */
2574     if( p_box->data.p_name->psz_text == NULL )
2575         MP4_READBOX_EXIT( 0 );
2576
2577     memcpy( p_box->data.p_name->psz_text, p_peek, p_box->i_size - 8 );
2578     p_box->data.p_name->psz_text[p_box->i_size - 8] = '\0';
2579
2580 #ifdef MP4_VERBOSE
2581         msg_Dbg( p_stream, "read box: \"name\" text=`%s'",
2582                  p_box->data.p_name->psz_text );
2583 #endif
2584     MP4_READBOX_EXIT( 1 );
2585 }
2586
2587 static void MP4_FreeBox_name( MP4_Box_t *p_box )
2588 {
2589     FREENULL( p_box->data.p_name->psz_text );
2590 }
2591
2592 static int MP4_ReadBox_0xa9xxx( stream_t *p_stream, MP4_Box_t *p_box )
2593 {
2594     uint16_t i16;
2595
2596     MP4_READBOX_ENTER( MP4_Box_data_0xa9xxx_t );
2597
2598     p_box->data.p_0xa9xxx->psz_text = NULL;
2599
2600     MP4_GET2BYTES( i16 );
2601
2602     if( i16 > 0 )
2603     {
2604         int i_length = i16;
2605
2606         MP4_GET2BYTES( i16 );
2607         if( i_length >= i_read ) i_length = i_read + 1;
2608
2609         p_box->data.p_0xa9xxx->psz_text = malloc( i_length );
2610         if( p_box->data.p_0xa9xxx->psz_text == NULL )
2611             MP4_READBOX_EXIT( 0 );
2612
2613         i_length--;
2614         memcpy( p_box->data.p_0xa9xxx->psz_text,
2615                 p_peek, i_length );
2616         p_box->data.p_0xa9xxx->psz_text[i_length] = '\0';
2617
2618 #ifdef MP4_VERBOSE
2619         msg_Dbg( p_stream,
2620                  "read box: \"c%3.3s\" text=`%s'",
2621                  ((char*)&p_box->i_type + 1),
2622                  p_box->data.p_0xa9xxx->psz_text );
2623 #endif
2624     }
2625     else
2626     {
2627         /* try iTune/Quicktime format, rewind to start */
2628         p_peek -= 2; i_read += 2;
2629         // we are expecting a 'data' box
2630         uint32_t i_data_len;
2631         uint32_t i_data_tag;
2632
2633         MP4_GET4BYTES( i_data_len );
2634         if( i_data_len > i_read ) i_data_len = i_read;
2635         MP4_GETFOURCC( i_data_tag );
2636         if( (i_data_len > 0) && (i_data_tag == ATOM_data) )
2637         {
2638             /* data box contains a version/flags field */
2639             uint32_t i_version;
2640             uint32_t i_reserved;
2641             MP4_GET4BYTES( i_version );
2642             MP4_GET4BYTES( i_reserved );
2643             // version should be 0, flags should be 1 for text, 0 for data
2644             if( ( i_version == 0x00000001 ) && (i_data_len >= 12 ) )
2645             {
2646                 // the rest is the text
2647                 i_data_len -= 12;
2648                 p_box->data.p_0xa9xxx->psz_text = malloc( i_data_len + 1 );
2649                 if( p_box->data.p_0xa9xxx->psz_text == NULL )
2650                     MP4_READBOX_EXIT( 0 );
2651
2652                 memcpy( p_box->data.p_0xa9xxx->psz_text,
2653                         p_peek, i_data_len );
2654                 p_box->data.p_0xa9xxx->psz_text[i_data_len] = '\0';
2655 #ifdef MP4_VERBOSE
2656         msg_Dbg( p_stream,
2657                  "read box: \"c%3.3s\" text=`%s'",
2658                  ((char*)&p_box->i_type+1),
2659                  p_box->data.p_0xa9xxx->psz_text );
2660 #endif
2661             }
2662             else
2663             {
2664                 // TODO: handle data values for ID3 tag values, track num or cover art,etc...
2665             }
2666         }
2667     }
2668
2669     MP4_READBOX_EXIT( 1 );
2670 }
2671 static void MP4_FreeBox_0xa9xxx( MP4_Box_t *p_box )
2672 {
2673     FREENULL( p_box->data.p_0xa9xxx->psz_text );
2674 }
2675
2676 /* Chapter support */
2677 static void MP4_FreeBox_chpl( MP4_Box_t *p_box )
2678 {
2679     MP4_Box_data_chpl_t *p_chpl = p_box->data.p_chpl;
2680     for( unsigned i = 0; i < p_chpl->i_chapter; i++ )
2681         free( p_chpl->chapter[i].psz_name );
2682 }
2683
2684 static int MP4_ReadBox_chpl( stream_t *p_stream, MP4_Box_t *p_box )
2685 {
2686     MP4_Box_data_chpl_t *p_chpl;
2687     uint32_t i_dummy;
2688     int i;
2689     MP4_READBOX_ENTER( MP4_Box_data_chpl_t );
2690
2691     p_chpl = p_box->data.p_chpl;
2692
2693     MP4_GETVERSIONFLAGS( p_chpl );
2694
2695     MP4_GET4BYTES( i_dummy );
2696
2697     MP4_GET1BYTE( p_chpl->i_chapter );
2698
2699     for( i = 0; i < p_chpl->i_chapter; i++ )
2700     {
2701         uint64_t i_start;
2702         uint8_t i_len;
2703         int i_copy;
2704         MP4_GET8BYTES( i_start );
2705         MP4_GET1BYTE( i_len );
2706
2707         p_chpl->chapter[i].psz_name = malloc( i_len + 1 );
2708         if( !p_chpl->chapter[i].psz_name )
2709             MP4_READBOX_EXIT( 0 );
2710
2711         i_copy = __MIN( i_len, i_read );
2712         if( i_copy > 0 )
2713             memcpy( p_chpl->chapter[i].psz_name, p_peek, i_copy );
2714         p_chpl->chapter[i].psz_name[i_copy] = '\0';
2715         p_chpl->chapter[i].i_start = i_start;
2716
2717         p_peek += i_copy;
2718         i_read -= i_copy;
2719     }
2720     /* Bubble sort by increasing start date */
2721     do
2722     {
2723         for( i = 0; i < p_chpl->i_chapter - 1; i++ )
2724         {
2725             if( p_chpl->chapter[i].i_start > p_chpl->chapter[i+1].i_start )
2726             {
2727                 char *psz = p_chpl->chapter[i+1].psz_name;
2728                 int64_t i64 = p_chpl->chapter[i+1].i_start;
2729
2730                 p_chpl->chapter[i+1].psz_name = p_chpl->chapter[i].psz_name;
2731                 p_chpl->chapter[i+1].i_start = p_chpl->chapter[i].i_start;
2732
2733                 p_chpl->chapter[i].psz_name = psz;
2734                 p_chpl->chapter[i].i_start = i64;
2735
2736                 i = -1;
2737                 break;
2738             }
2739         }
2740     } while( i == -1 );
2741
2742 #ifdef MP4_VERBOSE
2743     msg_Dbg( p_stream, "read box: \"chpl\" %d chapters",
2744                        p_chpl->i_chapter );
2745 #endif
2746     MP4_READBOX_EXIT( 1 );
2747 }
2748
2749 static int MP4_ReadBox_tref_generic( stream_t *p_stream, MP4_Box_t *p_box )
2750 {
2751     MP4_READBOX_ENTER( MP4_Box_data_tref_generic_t );
2752
2753     p_box->data.p_tref_generic->i_track_ID = NULL;
2754     p_box->data.p_tref_generic->i_entry_count = i_read / sizeof(uint32_t);
2755     if( p_box->data.p_tref_generic->i_entry_count > 0 )
2756         p_box->data.p_tref_generic->i_track_ID = calloc( p_box->data.p_tref_generic->i_entry_count, sizeof(uint32_t) );
2757     if( p_box->data.p_tref_generic->i_track_ID == NULL )
2758         MP4_READBOX_EXIT( 0 );
2759
2760     for( unsigned i = 0; i < p_box->data.p_tref_generic->i_entry_count; i++ )
2761     {
2762         MP4_GET4BYTES( p_box->data.p_tref_generic->i_track_ID[i] );
2763     }
2764 #ifdef MP4_VERBOSE
2765         msg_Dbg( p_stream, "read box: \"chap\" %d references",
2766                  p_box->data.p_tref_generic->i_entry_count );
2767 #endif
2768
2769     MP4_READBOX_EXIT( 1 );
2770 }
2771 static void MP4_FreeBox_tref_generic( MP4_Box_t *p_box )
2772 {
2773     FREENULL( p_box->data.p_tref_generic->i_track_ID );
2774 }
2775
2776 static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
2777 {
2778     uint8_t meta_data[8];
2779     int i_actually_read;
2780
2781     // skip over box header
2782     i_actually_read = stream_Read( p_stream, meta_data, 8 );
2783     if( i_actually_read < 8 )
2784         return 0;
2785
2786     /* meta content starts with a 4 byte version/flags value (should be 0) */
2787     i_actually_read = stream_Read( p_stream, meta_data, 4 );
2788     if( i_actually_read < 4 )
2789         return 0;
2790
2791     /* then it behaves like a container */
2792     return MP4_ReadBoxContainerRaw( p_stream, p_box );
2793 }
2794
2795 static int MP4_ReadBox_iods( stream_t *p_stream, MP4_Box_t *p_box )
2796 {
2797     char i_unused;
2798
2799     MP4_READBOX_ENTER( MP4_Box_data_iods_t );
2800     MP4_GETVERSIONFLAGS( p_box->data.p_iods );
2801
2802     MP4_GET1BYTE( i_unused ); /* tag */
2803     MP4_GET1BYTE( i_unused ); /* length */
2804
2805     MP4_GET2BYTES( p_box->data.p_iods->i_object_descriptor ); /* 10bits, 6 other bits
2806                                                               are used for other flags */
2807     MP4_GET1BYTE( p_box->data.p_iods->i_OD_profile_level );
2808     MP4_GET1BYTE( p_box->data.p_iods->i_scene_profile_level );
2809     MP4_GET1BYTE( p_box->data.p_iods->i_audio_profile_level );
2810     MP4_GET1BYTE( p_box->data.p_iods->i_visual_profile_level );
2811     MP4_GET1BYTE( p_box->data.p_iods->i_graphics_profile_level );
2812
2813 #ifdef MP4_VERBOSE
2814     msg_Dbg( p_stream,
2815              "read box: \"iods\" objectDescriptorId: %i, OD: %i, scene: %i, audio: %i, "
2816              "visual: %i, graphics: %i",
2817              p_box->data.p_iods->i_object_descriptor >> 6,
2818              p_box->data.p_iods->i_OD_profile_level,
2819              p_box->data.p_iods->i_scene_profile_level,
2820              p_box->data.p_iods->i_audio_profile_level,
2821              p_box->data.p_iods->i_visual_profile_level,
2822              p_box->data.p_iods->i_graphics_profile_level );
2823 #endif
2824
2825     MP4_READBOX_EXIT( 1 );
2826 }
2827
2828 static int MP4_ReadBox_pasp( stream_t *p_stream, MP4_Box_t *p_box )
2829 {
2830     MP4_READBOX_ENTER( MP4_Box_data_pasp_t );
2831
2832     MP4_GET4BYTES( p_box->data.p_pasp->i_horizontal_spacing );
2833     MP4_GET4BYTES( p_box->data.p_pasp->i_vertical_spacing );
2834
2835 #ifdef MP4_VERBOSE
2836     msg_Dbg( p_stream,
2837              "read box: \"paps\" %dx%d",
2838              p_box->data.p_pasp->i_horizontal_spacing,
2839              p_box->data.p_pasp->i_vertical_spacing);
2840 #endif
2841
2842     MP4_READBOX_EXIT( 1 );
2843 }
2844
2845 static int MP4_ReadBox_mehd( stream_t *p_stream, MP4_Box_t *p_box )
2846 {
2847     MP4_READBOX_ENTER( MP4_Box_data_mehd_t );
2848
2849     MP4_GETVERSIONFLAGS( p_box->data.p_mehd );
2850     if( p_box->data.p_mehd->i_version == 1 )
2851         MP4_GET8BYTES( p_box->data.p_mehd->i_fragment_duration );
2852     else /* version == 0 */
2853         MP4_GET4BYTES( p_box->data.p_mehd->i_fragment_duration );
2854
2855 #ifdef MP4_VERBOSE
2856     msg_Dbg( p_stream,
2857              "read box: \"mehd\" frag dur. %"PRIu64"",
2858              p_box->data.p_mehd->i_fragment_duration );
2859 #endif
2860
2861     MP4_READBOX_EXIT( 1 );
2862 }
2863
2864 static int MP4_ReadBox_trex( stream_t *p_stream, MP4_Box_t *p_box )
2865 {
2866     MP4_READBOX_ENTER( MP4_Box_data_trex_t );
2867     MP4_GETVERSIONFLAGS( p_box->data.p_trex );
2868
2869     MP4_GET4BYTES( p_box->data.p_trex->i_track_ID );
2870     MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_description_index );
2871     MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_duration );
2872     MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_size );
2873     MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_flags );
2874
2875 #ifdef MP4_VERBOSE
2876     msg_Dbg( p_stream,
2877              "read box: \"trex\" trackID: %"PRIu32"",
2878              p_box->data.p_trex->i_track_ID );
2879 #endif
2880
2881     MP4_READBOX_EXIT( 1 );
2882 }
2883
2884 static int MP4_ReadBox_sdtp( stream_t *p_stream, MP4_Box_t *p_box )
2885 {
2886     uint32_t i_sample_count;
2887     MP4_READBOX_ENTER( MP4_Box_data_sdtp_t );
2888     MP4_Box_data_sdtp_t *p_sdtp = p_box->data.p_sdtp;
2889     MP4_GETVERSIONFLAGS( p_box->data.p_sdtp );
2890     i_sample_count = i_read;
2891
2892     p_sdtp->p_sample_table = calloc( i_sample_count, 1 );
2893
2894     if( !p_sdtp->p_sample_table )
2895         MP4_READBOX_EXIT( 0 );
2896
2897     for( uint32_t i = 0; i < i_sample_count; i++ )
2898         MP4_GET1BYTE( p_sdtp->p_sample_table[i] );
2899
2900 #ifdef MP4_VERBOSE
2901     msg_Info( p_stream, "i_sample_count is %"PRIu32"", i_sample_count );
2902     msg_Dbg( p_stream,
2903              "read box: \"sdtp\" head: %"PRIx8" %"PRIx8" %"PRIx8" %"PRIx8"",
2904                  p_sdtp->p_sample_table[0],
2905                  p_sdtp->p_sample_table[1],
2906                  p_sdtp->p_sample_table[2],
2907                  p_sdtp->p_sample_table[3] );
2908 #endif
2909
2910     MP4_READBOX_EXIT( 1 );
2911 }
2912
2913 static void MP4_FreeBox_sdtp( MP4_Box_t *p_box )
2914 {
2915     FREENULL( p_box->data.p_sdtp->p_sample_table );
2916 }
2917
2918 static int MP4_ReadBox_mfro( stream_t *p_stream, MP4_Box_t *p_box )
2919 {
2920     MP4_READBOX_ENTER( MP4_Box_data_mfro_t );
2921
2922     MP4_GETVERSIONFLAGS( p_box->data.p_mfro );
2923     MP4_GET4BYTES( p_box->data.p_mfro->i_size );
2924
2925 #ifdef MP4_VERBOSE
2926     msg_Dbg( p_stream,
2927              "read box: \"mfro\" size: %"PRIu32"",
2928              p_box->data.p_mfro->i_size);
2929 #endif
2930
2931     MP4_READBOX_EXIT( 1 );
2932 }
2933
2934 static int MP4_ReadBox_tfra( stream_t *p_stream, MP4_Box_t *p_box )
2935 {
2936     uint32_t i_number_of_entries;
2937     MP4_READBOX_ENTER( MP4_Box_data_tfra_t );
2938     MP4_Box_data_tfra_t *p_tfra = p_box->data.p_tfra;
2939     MP4_GETVERSIONFLAGS( p_box->data.p_tfra );
2940
2941     MP4_GET4BYTES( p_tfra->i_track_ID );
2942     uint32_t i_lengths = 0;
2943     MP4_GET4BYTES( i_lengths );
2944     MP4_GET4BYTES( p_tfra->i_number_of_entries );
2945     i_number_of_entries = p_tfra->i_number_of_entries;
2946     p_tfra->i_length_size_of_traf_num = i_lengths >> 4;
2947     p_tfra->i_length_size_of_trun_num = ( i_lengths & 0x0c ) >> 2;
2948     p_tfra->i_length_size_of_sample_num = i_lengths & 0x03;
2949
2950     size_t size = 4 + 4*p_tfra->i_version; /* size in {4, 8} */
2951     p_tfra->p_time = calloc( i_number_of_entries, size );
2952     p_tfra->p_moof_offset = calloc( i_number_of_entries, size );
2953
2954     size = 1 + p_tfra->i_length_size_of_traf_num; /* size in [|1, 4|] */
2955     p_tfra->p_traf_number = calloc( i_number_of_entries, size );
2956     size = 1 + p_tfra->i_length_size_of_trun_num;
2957     p_tfra->p_trun_number = calloc( i_number_of_entries, size );
2958     size = 1 + p_tfra->i_length_size_of_sample_num;
2959     p_tfra->p_sample_number = calloc( i_number_of_entries, size );
2960
2961     if( !p_tfra->p_time || !p_tfra->p_moof_offset || !p_tfra->p_traf_number
2962                         || !p_tfra->p_trun_number || !p_tfra->p_sample_number )
2963         goto error;
2964
2965     for( uint32_t i = 0; i < i_number_of_entries; i++ )
2966     {
2967         if( p_tfra->i_version == 1 )
2968         {
2969             MP4_GET8BYTES( p_tfra->p_time[i*2] );
2970             MP4_GET8BYTES( p_tfra->p_moof_offset[i*2] );
2971         }
2972         else
2973         {
2974             MP4_GET4BYTES( p_tfra->p_time[i] );
2975             MP4_GET4BYTES( p_tfra->p_moof_offset[i] );
2976         }
2977         switch (p_tfra->i_length_size_of_traf_num)
2978         {
2979             case 0:
2980                 MP4_GET1BYTE( p_tfra->p_traf_number[i] );
2981                 break;
2982             case 1:
2983                 MP4_GET2BYTES( p_tfra->p_traf_number[i*2] );
2984                 break;
2985             case 2:
2986                 MP4_GET3BYTES( p_tfra->p_traf_number[i*3] );
2987                 break;
2988             case 3:
2989                 MP4_GET4BYTES( p_tfra->p_traf_number[i*4] );
2990                 break;
2991             default:
2992                 goto error;
2993         }
2994
2995         switch (p_tfra->i_length_size_of_trun_num)
2996         {
2997             case 0:
2998                 MP4_GET1BYTE( p_tfra->p_trun_number[i] );
2999                 break;
3000             case 1:
3001                 MP4_GET2BYTES( p_tfra->p_trun_number[i*2] );
3002                 break;
3003             case 2:
3004                 MP4_GET3BYTES( p_tfra->p_trun_number[i*3] );
3005                 break;
3006             case 3:
3007                 MP4_GET4BYTES( p_tfra->p_trun_number[i*4] );
3008                 break;
3009             default:
3010                 goto error;
3011         }
3012
3013         switch (p_tfra->i_length_size_of_sample_num)
3014         {
3015             case 0:
3016                 MP4_GET1BYTE( p_tfra->p_sample_number[i] );
3017                 break;
3018             case 1:
3019                 MP4_GET2BYTES( p_tfra->p_sample_number[i*2] );
3020                 break;
3021             case 2:
3022                 MP4_GET3BYTES( p_tfra->p_sample_number[i*3] );
3023                 break;
3024             case 3:
3025                 MP4_GET4BYTES( p_tfra->p_sample_number[i*4] );
3026                 break;
3027             default:
3028                 goto error;
3029         }
3030     }
3031
3032 #ifdef MP4_VERBOSE
3033     if( p_tfra->i_version == 0 )
3034     {
3035         msg_Dbg( p_stream, "time[0]: %"PRIu32", moof_offset[0]: %"PRIx32"",
3036                          p_tfra->p_time[0], p_tfra->p_moof_offset[0] );
3037
3038         msg_Dbg( p_stream, "time[1]: %"PRIu32", moof_offset[1]: %"PRIx32"",
3039                          p_tfra->p_time[1], p_tfra->p_moof_offset[1] );
3040     }
3041     else
3042     {
3043         msg_Dbg( p_stream, "time[0]: %"PRIu64", moof_offset[0]: %"PRIx64"",
3044                 ((uint64_t *)(p_tfra->p_time))[0],
3045                 ((uint64_t *)(p_tfra->p_moof_offset))[0] );
3046
3047         msg_Dbg( p_stream, "time[1]: %"PRIu64", moof_offset[1]: %"PRIx64"",
3048                 ((uint64_t *)(p_tfra->p_time))[1],
3049                 ((uint64_t *)(p_tfra->p_moof_offset))[1] );
3050     }
3051
3052     msg_Info( p_stream, "number_of_entries is %"PRIu32"", i_number_of_entries );
3053     msg_Info( p_stream, "track ID is: %"PRIu32"", p_tfra->i_track_ID );
3054 #endif
3055
3056     MP4_READBOX_EXIT( 1 );
3057 error:
3058     MP4_READBOX_EXIT( 0 );
3059 }
3060
3061 static void MP4_FreeBox_tfra( MP4_Box_t *p_box )
3062 {
3063     FREENULL( p_box->data.p_tfra->p_time );
3064     FREENULL( p_box->data.p_tfra->p_moof_offset );
3065     FREENULL( p_box->data.p_tfra->p_traf_number );
3066     FREENULL( p_box->data.p_tfra->p_trun_number );
3067     FREENULL( p_box->data.p_tfra->p_sample_number );
3068 }
3069
3070
3071 /* For generic */
3072 static int MP4_ReadBox_default( stream_t *p_stream, MP4_Box_t *p_box )
3073 {
3074     if( !p_box->p_father )
3075     {
3076         goto unknown;
3077     }
3078     if( p_box->p_father->i_type == ATOM_stsd )
3079     {
3080         MP4_Box_t *p_mdia = MP4_BoxGet( p_box, "../../../.." );
3081         MP4_Box_t *p_hdlr;
3082
3083         if( p_mdia == NULL || p_mdia->i_type != ATOM_mdia ||
3084             (p_hdlr = MP4_BoxGet( p_mdia, "hdlr" )) == NULL )
3085         {
3086             goto unknown;
3087         }
3088         switch( p_hdlr->data.p_hdlr->i_handler_type )
3089         {
3090             case ATOM_soun:
3091                 return MP4_ReadBox_sample_soun( p_stream, p_box );
3092             case ATOM_vide:
3093                 return MP4_ReadBox_sample_vide( p_stream, p_box );
3094             case ATOM_text:
3095                 return MP4_ReadBox_sample_text( p_stream, p_box );
3096             case ATOM_tx3g:
3097             case ATOM_sbtl:
3098                 return MP4_ReadBox_sample_tx3g( p_stream, p_box );
3099             default:
3100                 msg_Warn( p_stream,
3101                           "unknown handler type in stsd (incompletely loaded)" );
3102                 return 1;
3103         }
3104     }
3105
3106 unknown:
3107     if MP4_BOX_TYPE_ASCII()
3108         msg_Warn( p_stream,
3109                 "unknown box type %4.4s (incompletely loaded)",
3110                 (char*)&p_box->i_type );
3111     else
3112         msg_Warn( p_stream,
3113                 "unknown box type c%3.3s (incompletely loaded)",
3114                 (char*)&p_box->i_type+1 );
3115
3116     return 1;
3117 }
3118
3119 /**** ------------------------------------------------------------------- ****/
3120 /****                   "Higher level" Functions                          ****/
3121 /**** ------------------------------------------------------------------- ****/
3122
3123 static const struct
3124 {
3125     uint32_t i_type;
3126     int  (*MP4_ReadBox_function )( stream_t *p_stream, MP4_Box_t *p_box );
3127     void (*MP4_FreeBox_function )( MP4_Box_t *p_box );
3128 } MP4_Box_Function [] =
3129 {
3130     /* Containers */
3131     { ATOM_moov,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3132     { ATOM_trak,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3133     { ATOM_mdia,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3134     { ATOM_moof,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3135     { ATOM_minf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3136     { ATOM_stbl,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3137     { ATOM_dinf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3138     { ATOM_edts,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3139     { ATOM_udta,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3140     { ATOM_nmhd,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3141     { ATOM_hnti,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3142     { ATOM_rmra,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3143     { ATOM_rmda,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3144     { ATOM_tref,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3145     { ATOM_gmhd,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3146     { ATOM_wave,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3147     { ATOM_ilst,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3148     { ATOM_mvex,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3149
3150     /* specific box */
3151     { ATOM_ftyp,    MP4_ReadBox_ftyp,         MP4_FreeBox_ftyp },
3152     { ATOM_cmov,    MP4_ReadBox_cmov,         MP4_FreeBox_Common },
3153     { ATOM_mvhd,    MP4_ReadBox_mvhd,         MP4_FreeBox_Common },
3154     { ATOM_tkhd,    MP4_ReadBox_tkhd,         MP4_FreeBox_Common },
3155     { ATOM_mdhd,    MP4_ReadBox_mdhd,         MP4_FreeBox_Common },
3156     { ATOM_hdlr,    MP4_ReadBox_hdlr,         MP4_FreeBox_hdlr },
3157     { ATOM_vmhd,    MP4_ReadBox_vmhd,         MP4_FreeBox_Common },
3158     { ATOM_smhd,    MP4_ReadBox_smhd,         MP4_FreeBox_Common },
3159     { ATOM_hmhd,    MP4_ReadBox_hmhd,         MP4_FreeBox_Common },
3160     { ATOM_url,     MP4_ReadBox_url,          MP4_FreeBox_url },
3161     { ATOM_urn,     MP4_ReadBox_urn,          MP4_FreeBox_urn },
3162     { ATOM_dref,    MP4_ReadBox_dref,         MP4_FreeBox_Common },
3163     { ATOM_stts,    MP4_ReadBox_stts,         MP4_FreeBox_stts },
3164     { ATOM_ctts,    MP4_ReadBox_ctts,         MP4_FreeBox_ctts },
3165     { ATOM_stsd,    MP4_ReadBox_stsd,         MP4_FreeBox_Common },
3166     { ATOM_stsz,    MP4_ReadBox_stsz,         MP4_FreeBox_stsz },
3167     { ATOM_stsc,    MP4_ReadBox_stsc,         MP4_FreeBox_stsc },
3168     { ATOM_stco,    MP4_ReadBox_stco_co64,    MP4_FreeBox_stco_co64 },
3169     { ATOM_co64,    MP4_ReadBox_stco_co64,    MP4_FreeBox_stco_co64 },
3170     { ATOM_stss,    MP4_ReadBox_stss,         MP4_FreeBox_stss },
3171     { ATOM_stsh,    MP4_ReadBox_stsh,         MP4_FreeBox_stsh },
3172     { ATOM_stdp,    MP4_ReadBox_stdp,         MP4_FreeBox_stdp },
3173     { ATOM_padb,    MP4_ReadBox_padb,         MP4_FreeBox_padb },
3174     { ATOM_elst,    MP4_ReadBox_elst,         MP4_FreeBox_elst },
3175     { ATOM_cprt,    MP4_ReadBox_cprt,         MP4_FreeBox_cprt },
3176     { ATOM_esds,    MP4_ReadBox_esds,         MP4_FreeBox_esds },
3177     { ATOM_dcom,    MP4_ReadBox_dcom,         MP4_FreeBox_Common },
3178     { ATOM_cmvd,    MP4_ReadBox_cmvd,         MP4_FreeBox_cmvd },
3179     { ATOM_avcC,    MP4_ReadBox_avcC,         MP4_FreeBox_avcC },
3180     { ATOM_dac3,    MP4_ReadBox_dac3,         MP4_FreeBox_Common },
3181     { ATOM_dvc1,    MP4_ReadBox_dvc1,         MP4_FreeBox_Common },
3182     { ATOM_enda,    MP4_ReadBox_enda,         MP4_FreeBox_Common },
3183     { ATOM_gnre,    MP4_ReadBox_gnre,         MP4_FreeBox_Common },
3184     { ATOM_trkn,    MP4_ReadBox_trkn,         MP4_FreeBox_Common },
3185     { ATOM_iods,    MP4_ReadBox_iods,         MP4_FreeBox_Common },
3186     { ATOM_pasp,    MP4_ReadBox_pasp,         MP4_FreeBox_Common },
3187
3188     /* Nothing to do with this box */
3189     { ATOM_mdat,    MP4_ReadBoxSkip,          MP4_FreeBox_Common },
3190     { ATOM_skip,    MP4_ReadBoxSkip,          MP4_FreeBox_Common },
3191     { ATOM_free,    MP4_ReadBoxSkip,          MP4_FreeBox_Common },
3192     { ATOM_wide,    MP4_ReadBoxSkip,          MP4_FreeBox_Common },
3193
3194     /* for codecs */
3195     { ATOM_soun,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3196     { ATOM_ms02,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3197     { ATOM_ms11,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3198     { ATOM_ms55,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3199     { ATOM__mp3,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3200     { ATOM_mp4a,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3201     { ATOM_twos,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3202     { ATOM_sowt,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3203     { ATOM_QDMC,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3204     { ATOM_QDM2,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3205     { ATOM_ima4,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3206     { ATOM_IMA4,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3207     { ATOM_dvi,     MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3208     { ATOM_alaw,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3209     { ATOM_ulaw,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3210     { ATOM_raw,     MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3211     { ATOM_MAC3,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3212     { ATOM_MAC6,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3213     { ATOM_Qclp,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3214     { ATOM_samr,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3215     { ATOM_sawb,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3216     { ATOM_OggS,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3217     { ATOM_alac,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3218
3219     { ATOM_drmi,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3220     { ATOM_vide,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3221     { ATOM_mp4v,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3222     { ATOM_SVQ1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3223     { ATOM_SVQ3,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3224     { ATOM_ZyGo,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3225     { ATOM_DIVX,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3226     { ATOM_XVID,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3227     { ATOM_h263,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3228     { ATOM_s263,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3229     { ATOM_cvid,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3230     { ATOM_3IV1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3231     { ATOM_3iv1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3232     { ATOM_3IV2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3233     { ATOM_3iv2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3234     { ATOM_3IVD,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3235     { ATOM_3ivd,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3236     { ATOM_3VID,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3237     { ATOM_3vid,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3238     { ATOM_mjpa,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3239     { ATOM_mjpb,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3240     { ATOM_qdrw,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3241     { ATOM_mp2v,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3242     { ATOM_hdv2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3243
3244     { ATOM_mjqt,    MP4_ReadBox_default,      NULL }, /* found in mjpa/b */
3245     { ATOM_mjht,    MP4_ReadBox_default,      NULL },
3246
3247     { ATOM_dvc,     MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3248     { ATOM_dvp,     MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3249     { ATOM_dv5n,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3250     { ATOM_dv5p,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3251     { ATOM_VP31,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3252     { ATOM_vp31,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3253     { ATOM_h264,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3254
3255     { ATOM_jpeg,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3256     { ATOM_avc1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3257
3258     { ATOM_yv12,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3259     { ATOM_yuv2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
3260
3261     { ATOM_mp4s,    MP4_ReadBox_sample_mp4s,  MP4_FreeBox_Common },
3262
3263     /* XXX there is 2 box where we could find this entry stbl and tref*/
3264     { ATOM_hint,    MP4_ReadBox_default,      MP4_FreeBox_Common },
3265
3266     /* found in tref box */
3267     { ATOM_dpnd,    MP4_ReadBox_default,      NULL },
3268     { ATOM_ipir,    MP4_ReadBox_default,      NULL },
3269     { ATOM_mpod,    MP4_ReadBox_default,      NULL },
3270     { ATOM_chap,    MP4_ReadBox_tref_generic, MP4_FreeBox_tref_generic },
3271
3272     /* found in hnti */
3273     { ATOM_rtp,     MP4_ReadBox_default,      NULL },
3274
3275     /* found in rmra */
3276     { ATOM_rdrf,    MP4_ReadBox_rdrf,         MP4_FreeBox_rdrf   },
3277     { ATOM_rmdr,    MP4_ReadBox_rmdr,         MP4_FreeBox_Common },
3278     { ATOM_rmqu,    MP4_ReadBox_rmqu,         MP4_FreeBox_Common },
3279     { ATOM_rmvc,    MP4_ReadBox_rmvc,         MP4_FreeBox_Common },
3280
3281     { ATOM_drms,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
3282     { ATOM_sinf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3283     { ATOM_schi,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3284     { ATOM_user,    MP4_ReadBox_drms,         MP4_FreeBox_Common },
3285     { ATOM_key,     MP4_ReadBox_drms,         MP4_FreeBox_Common },
3286     { ATOM_iviv,    MP4_ReadBox_drms,         MP4_FreeBox_Common },
3287     { ATOM_priv,    MP4_ReadBox_drms,         MP4_FreeBox_Common },
3288     { ATOM_frma,    MP4_ReadBox_frma,         MP4_FreeBox_Common },
3289     { ATOM_skcr,    MP4_ReadBox_skcr,         MP4_FreeBox_Common },
3290
3291     /* found in udta */
3292     { ATOM_0xa9nam, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3293     { ATOM_0xa9aut, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3294     { ATOM_0xa9cpy, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3295     { ATOM_0xa9swr, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3296     { ATOM_0xa9inf, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3297     { ATOM_0xa9ART, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3298     { ATOM_0xa9dir, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3299     { ATOM_0xa9cmt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3300     { ATOM_0xa9req, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3301     { ATOM_0xa9day, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3302     { ATOM_0xa9des, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3303     { ATOM_0xa9fmt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3304     { ATOM_0xa9prd, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3305     { ATOM_0xa9prf, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3306     { ATOM_0xa9src, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3307     { ATOM_0xa9alb, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3308     { ATOM_0xa9dis, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3309     { ATOM_0xa9enc, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3310     { ATOM_0xa9gen, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3311     { ATOM_0xa9trk, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3312     { ATOM_0xa9dsa, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3313     { ATOM_0xa9hst, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3314     { ATOM_0xa9url, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3315     { ATOM_0xa9ope, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3316     { ATOM_0xa9com, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3317     { ATOM_0xa9wrt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3318     { ATOM_0xa9too, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3319     { ATOM_0xa9wrn, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3320     { ATOM_0xa9mak, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3321     { ATOM_0xa9mod, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3322     { ATOM_0xa9PRD, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3323     { ATOM_0xa9grp, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3324     { ATOM_0xa9lyr, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3325     { ATOM_0xa9gen, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3326     { ATOM_0xa9st3, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3327     { ATOM_0xa9ard, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3328     { ATOM_0xa9arg, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3329     { ATOM_0xa9cak, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3330     { ATOM_0xa9con, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3331     { ATOM_0xa9des, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3332     { ATOM_0xa9lnt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3333     { ATOM_0xa9phg, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3334     { ATOM_0xa9pub, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3335     { ATOM_0xa9sne, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3336     { ATOM_0xa9sol, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3337     { ATOM_0xa9thx, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3338     { ATOM_0xa9xpd, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
3339
3340     { ATOM_chpl,    MP4_ReadBox_chpl,         MP4_FreeBox_chpl },
3341
3342     /* iTunes/Quicktime meta info */
3343     { ATOM_meta,    MP4_ReadBox_meta,         MP4_FreeBox_Common },
3344     { ATOM_name,    MP4_ReadBox_name,         MP4_FreeBox_name },
3345
3346     /* found in smoothstreaming */
3347     { ATOM_traf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3348     { ATOM_mfra,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
3349     { ATOM_mfhd,    MP4_ReadBox_mfhd,         MP4_FreeBox_Common },
3350     { ATOM_sidx,    MP4_ReadBox_sidx,         MP4_FreeBox_sidx },
3351     { ATOM_tfhd,    MP4_ReadBox_tfhd,         MP4_FreeBox_Common },
3352     { ATOM_trun,    MP4_ReadBox_trun,         MP4_FreeBox_trun },
3353     { ATOM_trex,    MP4_ReadBox_trex,         MP4_FreeBox_Common },
3354     { ATOM_mehd,    MP4_ReadBox_mehd,         MP4_FreeBox_Common },
3355     { ATOM_sdtp,    MP4_ReadBox_sdtp,         MP4_FreeBox_sdtp },
3356     { ATOM_tfra,    MP4_ReadBox_tfra,         MP4_FreeBox_tfra },
3357     { ATOM_mfro,    MP4_ReadBox_mfro,         MP4_FreeBox_Common },
3358     { ATOM_uuid,    MP4_ReadBox_uuid,         MP4_FreeBox_uuid },
3359
3360     /* Last entry */
3361     { 0,              MP4_ReadBox_default,      NULL }
3362 };
3363
3364
3365 /*****************************************************************************
3366  * MP4_ReadBox : parse the actual box and the children
3367  *  XXX : Do not go to the next box
3368  *****************************************************************************/
3369 static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father )
3370 {
3371     MP4_Box_t *p_box = calloc( 1, sizeof( MP4_Box_t ) ); /* Needed to ensure simple on error handler */
3372     unsigned int i_index;
3373
3374     if( p_box == NULL )
3375         return NULL;
3376
3377     if( !MP4_ReadBoxCommon( p_stream, p_box ) )
3378     {
3379         msg_Warn( p_stream, "cannot read one box" );
3380         free( p_box );
3381         return NULL;
3382     }
3383     if( !p_box->i_size )
3384     {
3385         msg_Dbg( p_stream, "found an empty box (null size)" );
3386         free( p_box );
3387         return NULL;
3388     }
3389     p_box->p_father = p_father;
3390
3391     /* Now search function to call */
3392     for( i_index = 0; ; i_index++ )
3393     {
3394         if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
3395             ( MP4_Box_Function[i_index].i_type == 0 ) )
3396         {
3397             break;
3398         }
3399     }
3400
3401     if( !(MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box ) )
3402     {
3403         MP4_BoxFree( p_stream, p_box );
3404         return NULL;
3405     }
3406
3407     return p_box;
3408 }
3409
3410 /*****************************************************************************
3411  * MP4_FreeBox : free memory after read with MP4_ReadBox and all
3412  * the children
3413  *****************************************************************************/
3414 void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
3415 {
3416     unsigned int i_index;
3417     MP4_Box_t    *p_child;
3418
3419     if( !p_box )
3420         return; /* hehe */
3421
3422     for( p_child = p_box->p_first; p_child != NULL; )
3423     {
3424         MP4_Box_t *p_next;
3425
3426         p_next = p_child->p_next;
3427         MP4_BoxFree( s, p_child );
3428         p_child = p_next;
3429     }
3430
3431     /* Now search function to call */
3432     if( p_box->data.p_data )
3433     {
3434         for( i_index = 0; ; i_index++ )
3435         {
3436             if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
3437                 ( MP4_Box_Function[i_index].i_type == 0 ) )
3438             {
3439                 break;
3440             }
3441         }
3442         if( MP4_Box_Function[i_index].MP4_FreeBox_function == NULL )
3443         {
3444             /* Should not happen */
3445             if MP4_BOX_TYPE_ASCII()
3446                 msg_Warn( s,
3447                         "cannot free box %4.4s, type unknown",
3448                         (char*)&p_box->i_type );
3449             else
3450                 msg_Warn( s,
3451                         "cannot free box c%3.3s, type unknown",
3452                         (char*)&p_box->i_type+1 );
3453         }
3454         else
3455         {
3456             MP4_Box_Function[i_index].MP4_FreeBox_function( p_box );
3457         }
3458         free( p_box->data.p_data );
3459     }
3460     free( p_box );
3461 }
3462
3463 /* SmooBox is a very simple MP4 box, VLC specific, used only for the stream_filter to
3464  * send information to the demux. SmooBox is actually a simplified moov box (we wanted
3465  * to avoid the hassle of building a moov box at the stream_filter level) */
3466 MP4_Box_t *MP4_BoxGetSmooBox( stream_t *s )
3467 {
3468     /* p_chunk is a virtual root container for the smoo box */
3469     MP4_Box_t *p_chunk;
3470     MP4_Box_t *p_smoo;
3471
3472     p_chunk = calloc( 1, sizeof( MP4_Box_t ) );
3473     if( unlikely( p_chunk == NULL ) )
3474         return NULL;
3475
3476     p_chunk->i_type = ATOM_root;
3477     p_chunk->i_shortsize = 1;
3478
3479     p_smoo = MP4_ReadBox( s, p_chunk );
3480     if( !p_smoo || p_smoo->i_type != ATOM_uuid || CmpUUID( &p_smoo->i_uuid, &SmooBoxUUID ) )
3481     {
3482         msg_Warn( s, "no smoo box found!");
3483         goto error;
3484     }
3485
3486     p_chunk->p_first = p_smoo;
3487     p_chunk->p_last = p_smoo;
3488
3489     return p_chunk;
3490
3491 error:
3492     free( p_chunk );
3493     return NULL;
3494 }
3495
3496 MP4_Box_t *MP4_BoxGetNextChunk( stream_t *s )
3497 {
3498     /* p_chunk is a virtual root container for the moof and mdat boxes */
3499     MP4_Box_t *p_chunk;
3500     MP4_Box_t *p_tmp_box = NULL;
3501
3502     p_tmp_box = calloc( 1, sizeof( MP4_Box_t ) );
3503     if( unlikely( p_tmp_box == NULL ) )
3504         return NULL;
3505
3506     /* We might get a ftyp box or a SmooBox */
3507     MP4_ReadBoxCommon( s, p_tmp_box );
3508
3509     if( (p_tmp_box->i_type == ATOM_uuid && !CmpUUID( &p_tmp_box->i_uuid, &SmooBoxUUID )) )
3510     {
3511         free( p_tmp_box );
3512         return MP4_BoxGetSmooBox( s );
3513     }
3514     else if( p_tmp_box->i_type == ATOM_ftyp )
3515     {
3516         free( p_tmp_box );
3517         return MP4_BoxGetRoot( s );
3518     }
3519     free( p_tmp_box );
3520
3521     p_chunk = calloc( 1, sizeof( MP4_Box_t ) );
3522     if( unlikely( p_chunk == NULL ) )
3523         return NULL;
3524
3525     p_chunk->i_type = ATOM_root;
3526     p_chunk->i_shortsize = 1;
3527
3528     MP4_ReadBoxContainerChildren( s, p_chunk, ATOM_moof );
3529
3530     return p_chunk;
3531 }
3532
3533 /*****************************************************************************
3534  * MP4_BoxGetRoot : Parse the entire file, and create all boxes in memory
3535  *****************************************************************************
3536  *  The first box is a virtual box "root" and is the father for all first
3537  *  level boxes for the file, a sort of virtual contener
3538  *****************************************************************************/
3539 MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
3540 {
3541     MP4_Box_t *p_root;
3542     stream_t *p_stream;
3543     int i_result;
3544
3545     p_root = malloc( sizeof( MP4_Box_t ) );
3546     if( p_root == NULL )
3547         return NULL;
3548
3549     p_root->i_pos = 0;
3550     p_root->i_type = ATOM_root;
3551     p_root->i_shortsize = 1;
3552     /* could be a DASH stream for exemple, 0 means unknown or infinite size */
3553     p_root->i_size = 0;
3554     CreateUUID( &p_root->i_uuid, p_root->i_type );
3555
3556     p_root->data.p_data = NULL;
3557     p_root->p_father    = NULL;
3558     p_root->p_first     = NULL;
3559     p_root->p_last      = NULL;
3560     p_root->p_next      = NULL;
3561
3562     p_stream = s;
3563
3564     /* First get the moov */
3565     i_result = MP4_ReadBoxContainerChildren( p_stream, p_root, ATOM_moov );
3566
3567     if( !i_result )
3568         goto error;
3569     /* If there is a mvex box, it means fragmented MP4, and we're done */
3570     else if( MP4_BoxCount( p_root, "moov/mvex" ) > 0 )
3571         return p_root;
3572
3573     p_root->i_size = stream_Size( s );
3574     stream_Seek( p_stream, 0 );
3575     /* Get the rest of the file */
3576     i_result = MP4_ReadBoxContainerRaw( p_stream, p_root );
3577
3578     if( !i_result )
3579         goto error;
3580
3581     MP4_Box_t *p_moov;
3582     MP4_Box_t *p_cmov;
3583
3584     /* check if there is a cmov, if so replace
3585       compressed moov by  uncompressed one */
3586     if( ( ( p_moov = MP4_BoxGet( p_root, "moov" ) ) &&
3587           ( p_cmov = MP4_BoxGet( p_root, "moov/cmov" ) ) ) ||
3588         ( ( p_moov = MP4_BoxGet( p_root, "foov" ) ) &&
3589           ( p_cmov = MP4_BoxGet( p_root, "foov/cmov" ) ) ) )
3590     {
3591         /* rename the compressed moov as a box to skip */
3592         p_moov->i_type = ATOM_skip;
3593
3594         /* get uncompressed p_moov */
3595         p_moov = p_cmov->data.p_cmov->p_moov;
3596         p_cmov->data.p_cmov->p_moov = NULL;
3597
3598         /* make p_root father of this new moov */
3599         p_moov->p_father = p_root;
3600
3601         /* insert this new moov box as first child of p_root */
3602         p_moov->p_next = p_root->p_first;
3603         p_root->p_first = p_moov;
3604     }
3605
3606     return p_root;
3607
3608 error:
3609     free( p_root );
3610     return NULL;
3611 }
3612
3613
3614 static void MP4_BoxDumpStructure_Internal( stream_t *s,
3615                                     MP4_Box_t *p_box, unsigned int i_level )
3616 {
3617     MP4_Box_t *p_child;
3618
3619     if( !i_level )
3620     {
3621         if MP4_BOX_TYPE_ASCII()
3622             msg_Dbg( s, "dumping root Box \"%4.4s\"",
3623                               (char*)&p_box->i_type );
3624         else
3625             msg_Dbg( s, "dumping root Box \"c%3.3s\"",
3626                               (char*)&p_box->i_type+1 );
3627     }
3628     else
3629     {
3630         char str[512];
3631         if( i_level >= (sizeof(str) - 1)/4 )
3632             return;
3633
3634         memset( str, ' ', sizeof(str) );
3635         for( unsigned i = 0; i < i_level; i++ )
3636         {
3637             str[i*4] = '|';
3638         }
3639         if( MP4_BOX_TYPE_ASCII() )
3640             snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
3641                       "+ %4.4s size %d",
3642                         (char*)&p_box->i_type, (uint32_t)p_box->i_size );
3643         else
3644             snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
3645                       "+ c%3.3s size %d",
3646                         (char*)&p_box->i_type+1, (uint32_t)p_box->i_size );
3647         msg_Dbg( s, "%s", str );
3648     }
3649     p_child = p_box->p_first;
3650     while( p_child )
3651     {
3652         MP4_BoxDumpStructure_Internal( s, p_child, i_level + 1 );
3653         p_child = p_child->p_next;
3654     }
3655 }
3656
3657 void MP4_BoxDumpStructure( stream_t *s, MP4_Box_t *p_box )
3658 {
3659     MP4_BoxDumpStructure_Internal( s, p_box, 0 );
3660 }
3661
3662
3663 /*****************************************************************************
3664  *****************************************************************************
3665  **
3666  **  High level methods to acces an MP4 file
3667  **
3668  *****************************************************************************
3669  *****************************************************************************/
3670 static void get_token( char **ppsz_path, char **ppsz_token, int *pi_number )
3671 {
3672     size_t i_len ;
3673     if( !*ppsz_path[0] )
3674     {
3675         *ppsz_token = NULL;
3676         *pi_number = 0;
3677         return;
3678     }
3679     i_len = strcspn( *ppsz_path, "/[" );
3680     if( !i_len && **ppsz_path == '/' )
3681     {
3682         i_len = 1;
3683     }
3684     *ppsz_token = strndup( *ppsz_path, i_len );
3685     if( unlikely(!*ppsz_token) )
3686         abort();
3687
3688     *ppsz_path += i_len;
3689
3690     if( **ppsz_path == '[' )
3691     {
3692         (*ppsz_path)++;
3693         *pi_number = strtol( *ppsz_path, NULL, 10 );
3694         while( **ppsz_path && **ppsz_path != ']' )
3695         {
3696             (*ppsz_path)++;
3697         }
3698         if( **ppsz_path == ']' )
3699         {
3700             (*ppsz_path)++;
3701         }
3702     }
3703     else
3704     {
3705         *pi_number = 0;
3706     }
3707     while( **ppsz_path == '/' )
3708     {
3709         (*ppsz_path)++;
3710     }
3711 }
3712
3713 static void MP4_BoxGet_Internal( MP4_Box_t **pp_result,
3714                           MP4_Box_t *p_box, const char *psz_fmt, va_list args)
3715 {
3716     char *psz_dup;
3717     char *psz_path;
3718     char *psz_token;
3719
3720     if( !p_box )
3721     {
3722         *pp_result = NULL;
3723         return;
3724     }
3725
3726     if( vasprintf( &psz_path, psz_fmt, args ) == -1 )
3727         psz_path = NULL;
3728
3729     if( !psz_path || !psz_path[0] )
3730     {
3731         free( psz_path );
3732         *pp_result = NULL;
3733         return;
3734     }
3735
3736 //    fprintf( stderr, "path:'%s'\n", psz_path );
3737     psz_dup = psz_path; /* keep this pointer, as it need to be unallocated */
3738     for( ; ; )
3739     {
3740         int i_number;
3741
3742         get_token( &psz_path, &psz_token, &i_number );
3743 //        fprintf( stderr, "path:'%s', token:'%s' n:%d\n",
3744 //                 psz_path,psz_token,i_number );
3745         if( !psz_token )
3746         {
3747             free( psz_dup );
3748             *pp_result = p_box;
3749             return;
3750         }
3751         else
3752         if( !strcmp( psz_token, "/" ) )
3753         {
3754             /* Find root box */
3755             while( p_box && p_box->i_type != ATOM_root )
3756             {
3757                 p_box = p_box->p_father;
3758             }
3759             if( !p_box )
3760             {
3761                 goto error_box;
3762             }
3763         }
3764         else
3765         if( !strcmp( psz_token, "." ) )
3766         {
3767             /* Do nothing */
3768         }
3769         else
3770         if( !strcmp( psz_token, ".." ) )
3771         {
3772             p_box = p_box->p_father;
3773             if( !p_box )
3774             {
3775                 goto error_box;
3776             }
3777         }
3778         else
3779         if( strlen( psz_token ) == 4 )
3780         {
3781             uint32_t i_fourcc;
3782             i_fourcc = VLC_FOURCC( psz_token[0], psz_token[1],
3783                                    psz_token[2], psz_token[3] );
3784             p_box = p_box->p_first;
3785             for( ; ; )
3786             {
3787                 if( !p_box )
3788                 {
3789                     goto error_box;
3790                 }
3791                 if( p_box->i_type == i_fourcc )
3792                 {
3793                     if( !i_number )
3794                     {
3795                         break;
3796                     }
3797                     i_number--;
3798                 }
3799                 p_box = p_box->p_next;
3800             }
3801         }
3802         else
3803         if( *psz_token == '\0' )
3804         {
3805             p_box = p_box->p_first;
3806             for( ; ; )
3807             {
3808                 if( !p_box )
3809                 {
3810                     goto error_box;
3811                 }
3812                 if( !i_number )
3813                 {
3814                     break;
3815                 }
3816                 i_number--;
3817                 p_box = p_box->p_next;
3818             }
3819         }
3820         else
3821         {
3822 //            fprintf( stderr, "Argg malformed token \"%s\"",psz_token );
3823             goto error_box;
3824         }
3825
3826         FREENULL( psz_token );
3827     }
3828
3829     return;
3830
3831 error_box:
3832     free( psz_token );
3833     free( psz_dup );
3834     *pp_result = NULL;
3835     return;
3836 }
3837
3838 /*****************************************************************************
3839  * MP4_BoxGet: find a box given a path relative to p_box
3840  *****************************************************************************
3841  * Path Format: . .. / as usual
3842  *              [number] to specifie box number ex: trak[12]
3843  *
3844  * ex: /moov/trak[12]
3845  *     ../mdia
3846  *****************************************************************************/
3847 MP4_Box_t *MP4_BoxGet( MP4_Box_t *p_box, const char *psz_fmt, ... )
3848 {
3849     va_list args;
3850     MP4_Box_t *p_result;
3851
3852     va_start( args, psz_fmt );
3853     MP4_BoxGet_Internal( &p_result, p_box, psz_fmt, args );
3854     va_end( args );
3855
3856     return( p_result );
3857 }
3858
3859 /*****************************************************************************
3860  * MP4_BoxCount: count box given a path relative to p_box
3861  *****************************************************************************
3862  * Path Format: . .. / as usual
3863  *              [number] to specifie box number ex: trak[12]
3864  *
3865  * ex: /moov/trak[12]
3866  *     ../mdia
3867  *****************************************************************************/
3868 int MP4_BoxCount( MP4_Box_t *p_box, const char *psz_fmt, ... )
3869 {
3870     va_list args;
3871     int     i_count;
3872     MP4_Box_t *p_result, *p_next;
3873
3874     va_start( args, psz_fmt );
3875     MP4_BoxGet_Internal( &p_result, p_box, psz_fmt, args );
3876     va_end( args );
3877     if( !p_result )
3878     {
3879         return( 0 );
3880     }
3881
3882     i_count = 1;
3883     for( p_next = p_result->p_next; p_next != NULL; p_next = p_next->p_next)
3884     {
3885         if( p_next->i_type == p_result->i_type)
3886         {
3887             i_count++;
3888         }
3889     }
3890     return( i_count );
3891 }