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