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