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