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