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