* mp4: more mov fields are parsed.
[vlc.git] / 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.21 2003/04/22 08:51:27 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     /*
1212      * XXX hack -> produce a copy of the nearly complete chunk
1213      */
1214     if( i_read > 0 )
1215     {
1216         p_box->data.p_sample_soun->i_qt_description = i_read;
1217         p_box->data.p_sample_soun->p_qt_description = malloc( i_read );
1218         memcpy( p_box->data.p_sample_soun->p_qt_description,
1219                 p_peek,
1220                 i_read );
1221     }
1222     else
1223     {
1224         p_box->data.p_sample_soun->i_qt_description = 0;
1225         p_box->data.p_sample_soun->p_qt_description = NULL;
1226     }
1227
1228     MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_version );
1229     MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_revision_level );
1230     MP4_GET4BYTES( p_box->data.p_sample_soun->i_qt_vendor );
1231
1232 #if 0
1233     for( i = 0; i < 2 ; i++ )
1234     {
1235         MP4_GET4BYTES( p_box->data.p_sample_soun->i_reserved2[i] );
1236     }
1237 #endif
1238
1239     MP4_GET2BYTES( p_box->data.p_sample_soun->i_channelcount );
1240     MP4_GET2BYTES( p_box->data.p_sample_soun->i_samplesize );
1241     MP4_GET2BYTES( p_box->data.p_sample_soun->i_predefined );
1242     MP4_GET2BYTES( p_box->data.p_sample_soun->i_reserved3 );
1243     MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratehi );
1244     MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratelo );
1245
1246     if( p_box->data.p_sample_soun->i_qt_version == 1 &&
1247         i_read >= 16 )
1248     {
1249         /* qt3+ */
1250         MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
1251         MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_packet );
1252         MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_frame );
1253         MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_sample );
1254
1255 #ifdef MP4_VERBOSE
1256         msg_Dbg( p_stream->p_input,
1257                  "Read Box: \"soun\" qt3+ sample/packet=%d bytes/packet=%d bytes/frame=%d bytes/sample=%d",
1258                  p_box->data.p_sample_soun->i_sample_per_packet, p_box->data.p_sample_soun->i_bytes_per_packet,
1259                  p_box->data.p_sample_soun->i_bytes_per_frame, p_box->data.p_sample_soun->i_bytes_per_sample );
1260 #endif
1261         MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 44 );
1262     }
1263     else
1264     {
1265         p_box->data.p_sample_soun->i_sample_per_packet = 0;
1266         p_box->data.p_sample_soun->i_bytes_per_packet = 0;
1267         p_box->data.p_sample_soun->i_bytes_per_frame = 0;
1268         p_box->data.p_sample_soun->i_bytes_per_sample = 0;
1269
1270         msg_Dbg( p_stream->p_input, "Read Box: \"soun\" mp4 or qt1/2 (rest="I64Fd")", i_read );
1271         MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 28 );
1272     }
1273     MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */
1274
1275 #ifdef MP4_VERBOSE
1276     msg_Dbg( p_stream->p_input, "Read Box: \"soun\" in stsd channel %d sample size %d sampl rate %f",
1277                       p_box->data.p_sample_soun->i_channelcount,
1278                       p_box->data.p_sample_soun->i_samplesize,
1279                       (float)p_box->data.p_sample_soun->i_sampleratehi +
1280                     (float)p_box->data.p_sample_soun->i_sampleratelo / 65536 );
1281
1282 #endif
1283     MP4_READBOX_EXIT( 1 );
1284 }
1285
1286 #if 0
1287 int MP4_ReadBox_sample_mp4a( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1288 {
1289     unsigned int i;
1290
1291     MP4_READBOX_ENTER( MP4_Box_data_sample_mp4a_t );
1292
1293     for( i = 0; i < 6 ; i++ )
1294     {
1295         MP4_GET1BYTE( p_box->data.p_sample_mp4a->i_reserved1[i] );
1296     }
1297
1298     MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_data_reference_index );
1299
1300     for( i = 0; i < 2 ; i++ )
1301     {
1302         MP4_GET4BYTES( p_box->data.p_sample_mp4a->i_reserved2[i] );
1303     }
1304
1305     MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_channelcount );
1306     MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_samplesize );
1307     MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_predefined );
1308     MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_reserved3 );
1309     MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_sampleratehi );
1310     MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_sampleratelo );
1311
1312     MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 28 );
1313     MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */
1314
1315 #ifdef MP4_VERBOSE
1316     msg_Dbg( p_stream->p_input, "Read Box: \"mp4a\" in stsd channel %d sample size %d sampl rate %f",
1317                       p_box->data.p_sample_mp4a->i_channelcount,
1318                       p_box->data.p_sample_mp4a->i_samplesize,
1319                       (float)p_box->data.p_sample_mp4a->i_sampleratehi +
1320                         (float)p_box->data.p_sample_mp4a->i_sampleratelo / 65536 );
1321
1322 #endif
1323     MP4_READBOX_EXIT( 1 );
1324 }
1325 #endif
1326
1327 int MP4_ReadBox_sample_vide( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1328 {
1329     unsigned int i;
1330
1331     MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t );
1332
1333     for( i = 0; i < 6 ; i++ )
1334     {
1335         MP4_GET1BYTE( p_box->data.p_sample_vide->i_reserved1[i] );
1336     }
1337
1338     MP4_GET2BYTES( p_box->data.p_sample_vide->i_data_reference_index );
1339
1340     /*
1341      * XXX hack -> produce a copy of the nearly complete chunk
1342      */
1343     if( i_read > 0 )
1344     {
1345         p_box->data.p_sample_vide->i_qt_image_description = i_read;
1346         p_box->data.p_sample_vide->p_qt_image_description = malloc( i_read );
1347         memcpy( p_box->data.p_sample_vide->p_qt_image_description,
1348                 p_peek,
1349                 i_read );
1350     }
1351     else
1352     {
1353         p_box->data.p_sample_vide->i_qt_image_description = 0;
1354         p_box->data.p_sample_vide->p_qt_image_description = NULL;
1355     }
1356
1357     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_version );
1358     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_revision_level );
1359     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_vendor );
1360
1361     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_temporal_quality );
1362     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_spatial_quality );
1363
1364     MP4_GET2BYTES( p_box->data.p_sample_vide->i_width );
1365     MP4_GET2BYTES( p_box->data.p_sample_vide->i_height );
1366
1367     MP4_GET4BYTES( p_box->data.p_sample_vide->i_horizresolution );
1368     MP4_GET4BYTES( p_box->data.p_sample_vide->i_vertresolution );
1369
1370     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_data_size );
1371     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_frame_count );
1372
1373     memcpy( &p_box->data.p_sample_vide->i_compressorname, p_peek, 32 );
1374     p_peek += 32; i_read -= 32;
1375
1376     MP4_GET2BYTES( p_box->data.p_sample_vide->i_depth );
1377     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_color_table );
1378
1379     MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 78);
1380     MP4_ReadBoxContainerRaw( p_stream, p_box );
1381
1382 #ifdef MP4_VERBOSE
1383     msg_Dbg( p_stream->p_input, "Read Box: \"vide\" in stsd %dx%d depth %d",
1384                       p_box->data.p_sample_vide->i_width,
1385                       p_box->data.p_sample_vide->i_height,
1386                       p_box->data.p_sample_vide->i_depth );
1387
1388 #endif
1389     MP4_READBOX_EXIT( 1 );
1390 }
1391
1392
1393 int MP4_ReadBox_stsd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1394 {
1395
1396     MP4_READBOX_ENTER( MP4_Box_data_stsd_t );
1397
1398     MP4_GETVERSIONFLAGS( p_box->data.p_stsd );
1399
1400     MP4_GET4BYTES( p_box->data.p_stsd->i_entry_count );
1401
1402     MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 8 );
1403
1404     MP4_ReadBoxContainerRaw( p_stream, p_box );
1405
1406 #ifdef MP4_VERBOSE
1407     msg_Dbg( p_stream->p_input, "Read Box: \"stsd\" entry-count %d",
1408                       p_box->data.p_stsd->i_entry_count );
1409
1410 #endif
1411     MP4_READBOX_EXIT( 1 );
1412 }
1413
1414
1415 int MP4_ReadBox_stsz( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1416 {
1417     unsigned int i;
1418
1419     MP4_READBOX_ENTER( MP4_Box_data_stsz_t );
1420
1421     MP4_GETVERSIONFLAGS( p_box->data.p_stsz );
1422
1423     MP4_GET4BYTES( p_box->data.p_stsz->i_sample_size );
1424
1425     MP4_GET4BYTES( p_box->data.p_stsz->i_sample_count );
1426
1427     p_box->data.p_stsz->i_entry_size =
1428         calloc( sizeof( uint32_t ), p_box->data.p_stsz->i_sample_count );
1429
1430     if( !p_box->data.p_stsz->i_sample_size )
1431     {
1432         for( i=0; (i<p_box->data.p_stsz->i_sample_count)&&(i_read >= 4 ); i++ )
1433         {
1434             MP4_GET4BYTES( p_box->data.p_stsz->i_entry_size[i] );
1435         }
1436     }
1437
1438 #ifdef MP4_VERBOSE
1439     msg_Dbg( p_stream->p_input, "Read Box: \"stsz\" sample-size %d sample-count %d",
1440                       p_box->data.p_stsz->i_sample_size,
1441                       p_box->data.p_stsz->i_sample_count );
1442
1443 #endif
1444     MP4_READBOX_EXIT( 1 );
1445 }
1446
1447 void MP4_FreeBox_stsz( input_thread_t *p_input, MP4_Box_t *p_box )
1448 {
1449     FREE( p_box->data.p_stsz->i_entry_size );
1450 }
1451
1452 int MP4_ReadBox_stsc( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1453 {
1454     unsigned int i;
1455
1456     MP4_READBOX_ENTER( MP4_Box_data_stsc_t );
1457
1458     MP4_GETVERSIONFLAGS( p_box->data.p_stsc );
1459
1460     MP4_GET4BYTES( p_box->data.p_stsc->i_entry_count );
1461
1462     p_box->data.p_stsc->i_first_chunk =
1463         calloc( sizeof( uint32_t ), p_box->data.p_stsc->i_entry_count );
1464     p_box->data.p_stsc->i_samples_per_chunk =
1465         calloc( sizeof( uint32_t ), p_box->data.p_stsc->i_entry_count );
1466     p_box->data.p_stsc->i_sample_description_index =
1467         calloc( sizeof( uint32_t ), p_box->data.p_stsc->i_entry_count );
1468
1469     for( i = 0; (i < p_box->data.p_stsc->i_entry_count )&&( i_read >= 12 );i++ )
1470     {
1471         MP4_GET4BYTES( p_box->data.p_stsc->i_first_chunk[i] );
1472         MP4_GET4BYTES( p_box->data.p_stsc->i_samples_per_chunk[i] );
1473         MP4_GET4BYTES( p_box->data.p_stsc->i_sample_description_index[i] );
1474     }
1475
1476 #ifdef MP4_VERBOSE
1477     msg_Dbg( p_stream->p_input, "Read Box: \"stsc\" entry-count %d",
1478                       p_box->data.p_stsc->i_entry_count );
1479
1480 #endif
1481     MP4_READBOX_EXIT( 1 );
1482 }
1483
1484 void MP4_FreeBox_stsc( input_thread_t *p_input, MP4_Box_t *p_box )
1485 {
1486     FREE( p_box->data.p_stsc->i_first_chunk );
1487     FREE( p_box->data.p_stsc->i_samples_per_chunk );
1488     FREE( p_box->data.p_stsc->i_sample_description_index );
1489 }
1490
1491 int MP4_ReadBox_stco_co64( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1492 {
1493     unsigned int i;
1494
1495     MP4_READBOX_ENTER( MP4_Box_data_co64_t );
1496
1497     MP4_GETVERSIONFLAGS( p_box->data.p_co64 );
1498
1499     MP4_GET4BYTES( p_box->data.p_co64->i_entry_count );
1500
1501     p_box->data.p_co64->i_chunk_offset =
1502         calloc( sizeof( uint64_t ), p_box->data.p_co64->i_entry_count );
1503
1504     for( i = 0; i < p_box->data.p_co64->i_entry_count; i++ )
1505     {
1506         if( p_box->i_type == FOURCC_stco )
1507         {
1508             if( i_read < 4 )
1509             {
1510                 break;
1511             }
1512             MP4_GET4BYTES( p_box->data.p_co64->i_chunk_offset[i] );
1513         }
1514         else
1515         {
1516             if( i_read < 8 )
1517             {
1518                 break;
1519             }
1520             MP4_GET8BYTES( p_box->data.p_co64->i_chunk_offset[i] );
1521         }
1522     }
1523
1524 #ifdef MP4_VERBOSE
1525     msg_Dbg( p_stream->p_input, "Read Box: \"co64\" entry-count %d",
1526                       p_box->data.p_co64->i_entry_count );
1527
1528 #endif
1529     MP4_READBOX_EXIT( 1 );
1530 }
1531
1532 void MP4_FreeBox_stco_co64( input_thread_t *p_input, MP4_Box_t *p_box )
1533 {
1534     FREE( p_box->data.p_co64->i_chunk_offset );
1535 }
1536
1537 int MP4_ReadBox_stss( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1538 {
1539     unsigned int i;
1540
1541     MP4_READBOX_ENTER( MP4_Box_data_stss_t );
1542
1543     MP4_GETVERSIONFLAGS( p_box->data.p_stss );
1544
1545     MP4_GET4BYTES( p_box->data.p_stss->i_entry_count );
1546
1547     p_box->data.p_stss->i_sample_number =
1548         calloc( sizeof( uint32_t ), p_box->data.p_stss->i_entry_count );
1549
1550     for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 4 ); i++ )
1551     {
1552
1553         MP4_GET4BYTES( p_box->data.p_stss->i_sample_number[i] );
1554         /* XXX in libmp4 sample begin at 0 */
1555         p_box->data.p_stss->i_sample_number[i]--;
1556     }
1557
1558 #ifdef MP4_VERBOSE
1559     msg_Dbg( p_stream->p_input, "Read Box: \"stss\" entry-count %d",
1560                       p_box->data.p_stss->i_entry_count );
1561
1562 #endif
1563     MP4_READBOX_EXIT( 1 );
1564 }
1565
1566 void MP4_FreeBox_stss( input_thread_t *p_input, MP4_Box_t *p_box )
1567 {
1568     FREE( p_box->data.p_stss->i_sample_number )
1569 }
1570
1571 int MP4_ReadBox_stsh( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1572 {
1573     unsigned int i;
1574
1575     MP4_READBOX_ENTER( MP4_Box_data_stsh_t );
1576
1577     MP4_GETVERSIONFLAGS( p_box->data.p_stsh );
1578
1579
1580     MP4_GET4BYTES( p_box->data.p_stsh->i_entry_count );
1581
1582     p_box->data.p_stsh->i_shadowed_sample_number =
1583         calloc( sizeof( uint32_t ), p_box->data.p_stsh->i_entry_count );
1584
1585     p_box->data.p_stsh->i_sync_sample_number =
1586         calloc( sizeof( uint32_t ), p_box->data.p_stsh->i_entry_count );
1587
1588
1589     for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 8 ); i++ )
1590     {
1591
1592         MP4_GET4BYTES( p_box->data.p_stsh->i_shadowed_sample_number[i] );
1593         MP4_GET4BYTES( p_box->data.p_stsh->i_sync_sample_number[i] );
1594     }
1595
1596 #ifdef MP4_VERBOSE
1597     msg_Dbg( p_stream->p_input, "Read Box: \"stsh\" entry-count %d",
1598                       p_box->data.p_stsh->i_entry_count );
1599 #endif
1600     MP4_READBOX_EXIT( 1 );
1601 }
1602
1603 void MP4_FreeBox_stsh( input_thread_t *p_input, MP4_Box_t *p_box )
1604 {
1605     FREE( p_box->data.p_stsh->i_shadowed_sample_number )
1606     FREE( p_box->data.p_stsh->i_sync_sample_number )
1607 }
1608
1609
1610 int MP4_ReadBox_stdp( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1611 {
1612     unsigned int i;
1613
1614     MP4_READBOX_ENTER( MP4_Box_data_stdp_t );
1615
1616     MP4_GETVERSIONFLAGS( p_box->data.p_stdp );
1617
1618     p_box->data.p_stdp->i_priority =
1619         calloc( sizeof( uint16_t ), i_read / 2 );
1620
1621     for( i = 0; i < i_read / 2 ; i++ )
1622     {
1623
1624         MP4_GET2BYTES( p_box->data.p_stdp->i_priority[i] );
1625     }
1626
1627 #ifdef MP4_VERBOSE
1628     msg_Dbg( p_stream->p_input, "Read Box: \"stdp\" entry-count "I64Fd,
1629                       i_read / 2 );
1630
1631 #endif
1632     MP4_READBOX_EXIT( 1 );
1633 }
1634
1635 void MP4_FreeBox_stdp( input_thread_t *p_input, MP4_Box_t *p_box )
1636 {
1637     FREE( p_box->data.p_stdp->i_priority )
1638 }
1639
1640 int MP4_ReadBox_padb( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1641 {
1642     unsigned int i;
1643
1644     MP4_READBOX_ENTER( MP4_Box_data_padb_t );
1645
1646     MP4_GETVERSIONFLAGS( p_box->data.p_padb );
1647
1648
1649     MP4_GET4BYTES( p_box->data.p_padb->i_sample_count );
1650
1651     p_box->data.p_padb->i_reserved1 =
1652         calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
1653     p_box->data.p_padb->i_pad2 =
1654         calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
1655     p_box->data.p_padb->i_reserved2 =
1656         calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
1657     p_box->data.p_padb->i_pad1 =
1658         calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
1659
1660
1661     for( i = 0; i < i_read / 2 ; i++ )
1662     {
1663         p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 7 )&0x01;
1664         p_box->data.p_padb->i_pad2[i] = ( (*p_peek) >> 4 )&0x07;
1665         p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 3 )&0x01;
1666         p_box->data.p_padb->i_pad1[i] = ( (*p_peek) )&0x07;
1667
1668         p_peek += 1; i_read -= 1;
1669     }
1670
1671 #ifdef MP4_VERBOSE
1672     msg_Dbg( p_stream->p_input, "Read Box: \"stdp\" entry-count "I64Fd,
1673                       i_read / 2 );
1674
1675 #endif
1676     MP4_READBOX_EXIT( 1 );
1677 }
1678
1679 void MP4_FreeBox_padb( input_thread_t *p_input, MP4_Box_t *p_box )
1680 {
1681     FREE( p_box->data.p_padb->i_reserved1 );
1682     FREE( p_box->data.p_padb->i_pad2 );
1683     FREE( p_box->data.p_padb->i_reserved2 );
1684     FREE( p_box->data.p_padb->i_pad1 );
1685 }
1686
1687 int MP4_ReadBox_elst( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1688 {
1689     unsigned int i;
1690
1691     MP4_READBOX_ENTER( MP4_Box_data_padb_t );
1692
1693     MP4_GETVERSIONFLAGS( p_box->data.p_elst );
1694
1695
1696     MP4_GET4BYTES( p_box->data.p_elst->i_entry_count );
1697
1698     p_box->data.p_elst->i_segment_duration =
1699         calloc( sizeof( uint64_t ), p_box->data.p_elst->i_entry_count );
1700     p_box->data.p_elst->i_media_time =
1701         calloc( sizeof( uint64_t ), p_box->data.p_elst->i_entry_count );
1702     p_box->data.p_elst->i_media_rate_integer =
1703         calloc( sizeof( uint16_t ), p_box->data.p_elst->i_entry_count );
1704     p_box->data.p_elst->i_media_rate_fraction=
1705         calloc( sizeof( uint16_t ), p_box->data.p_elst->i_entry_count );
1706
1707
1708     for( i = 0; i < p_box->data.p_elst->i_entry_count; i++ )
1709     {
1710         if( p_box->data.p_elst->i_version == 1 )
1711         {
1712
1713             MP4_GET8BYTES( p_box->data.p_elst->i_segment_duration[i] );
1714
1715             MP4_GET8BYTES( p_box->data.p_elst->i_media_time[i] );
1716         }
1717         else
1718         {
1719
1720             MP4_GET4BYTES( p_box->data.p_elst->i_segment_duration[i] );
1721
1722             MP4_GET4BYTES( p_box->data.p_elst->i_media_time[i] );
1723         }
1724
1725         MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_integer[i] );
1726         MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_fraction[i] );
1727     }
1728
1729 #ifdef MP4_VERBOSE
1730     msg_Dbg( p_stream->p_input, "Read Box: \"elst\" entry-count "I64Fd,
1731                       i_read / 2 );
1732
1733 #endif
1734     MP4_READBOX_EXIT( 1 );
1735 }
1736
1737 void MP4_FreeBox_elst( input_thread_t *p_input, MP4_Box_t *p_box )
1738 {
1739     FREE( p_box->data.p_elst->i_segment_duration );
1740     FREE( p_box->data.p_elst->i_media_time );
1741     FREE( p_box->data.p_elst->i_media_rate_integer );
1742     FREE( p_box->data.p_elst->i_media_rate_fraction );
1743 }
1744
1745 int MP4_ReadBox_cprt( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1746 {
1747     unsigned int i_language;
1748     unsigned int i;
1749
1750     MP4_READBOX_ENTER( MP4_Box_data_cprt_t );
1751
1752     MP4_GETVERSIONFLAGS( p_box->data.p_cprt );
1753
1754     i_language = GetWBE( p_peek );
1755     for( i = 0; i < 3; i++ )
1756     {
1757         p_box->data.p_cprt->i_language[i] =
1758             ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
1759     }
1760     p_peek += 2; i_read -= 2;
1761     MP4_GETSTRINGZ( p_box->data.p_cprt->psz_notice );
1762
1763 #ifdef MP4_VERBOSE
1764     msg_Dbg( p_stream->p_input, "Read Box: \"cprt\" language %c%c%c notice %s",
1765                       p_box->data.p_cprt->i_language[0],
1766                       p_box->data.p_cprt->i_language[1],
1767                       p_box->data.p_cprt->i_language[2],
1768                       p_box->data.p_cprt->psz_notice );
1769
1770 #endif
1771     MP4_READBOX_EXIT( 1 );
1772 }
1773
1774 void MP4_FreeBox_cprt( input_thread_t *p_input, MP4_Box_t *p_box )
1775 {
1776     FREE( p_box->data.p_cprt->psz_notice );
1777 }
1778
1779
1780 int MP4_ReadBox_dcom( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1781 {
1782     MP4_READBOX_ENTER( MP4_Box_data_dcom_t );
1783
1784     MP4_GETFOURCC( p_box->data.p_dcom->i_algorithm );
1785 #ifdef MP4_VERBOSE
1786     msg_Dbg( p_stream->p_input,
1787              "Read Box: \"dcom\" compression algorithm : %4.4s",
1788                       (char*)&p_box->data.p_dcom->i_algorithm );
1789 #endif
1790     MP4_READBOX_EXIT( 1 );
1791 }
1792
1793 int MP4_ReadBox_cmvd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1794 {
1795     MP4_READBOX_ENTER( MP4_Box_data_cmvd_t );
1796
1797     MP4_GET4BYTES( p_box->data.p_cmvd->i_uncompressed_size );
1798
1799     p_box->data.p_cmvd->i_compressed_size = i_read;
1800
1801     if( !( p_box->data.p_cmvd->p_data = malloc( i_read ) ) )
1802     {
1803         msg_Dbg( p_stream->p_input, "Read Box: \"cmvd\" not enough memory to load data" );
1804         return( 1 );
1805     }
1806
1807     /* now copy compressed data */
1808     memcpy( p_box->data.p_cmvd->p_data,
1809             p_peek,
1810             i_read);
1811
1812     p_box->data.p_cmvd->b_compressed = 1;
1813
1814 #ifdef MP4_VERBOSE
1815     msg_Dbg( p_stream->p_input, "Read Box: \"cmvd\" compressed data size %d",
1816                       p_box->data.p_cmvd->i_compressed_size );
1817 #endif
1818
1819     MP4_READBOX_EXIT( 1 );
1820 }
1821 void MP4_FreeBox_cmvd( input_thread_t *p_input, MP4_Box_t *p_box )
1822 {
1823     FREE( p_box->data.p_cmvd->p_data );
1824 }
1825
1826
1827 int MP4_ReadBox_cmov( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1828 {
1829     MP4_Stream_t *p_stream_memory;
1830     MP4_Box_t *p_umov;
1831
1832     MP4_Box_t *p_dcom;
1833     MP4_Box_t *p_cmvd;
1834 #ifdef HAVE_ZLIB_H
1835     z_stream  z_data;
1836 #endif
1837     uint8_t *p_data;
1838
1839     int i_result;
1840
1841     if( !( p_box->data.p_cmov = malloc( sizeof( MP4_Box_data_cmov_t ) ) ) )
1842     {
1843         msg_Err( p_stream->p_input, "out of memory" );
1844         return( 0 );
1845     }
1846     memset( p_box->data.p_cmov, 0, sizeof( MP4_Box_data_cmov_t ) );
1847
1848     if( !( p_box->p_father )||
1849         ( p_box->p_father->i_type != FOURCC_moov ) )
1850     {
1851         msg_Warn( p_stream->p_input, "Read box: \"cmov\" box alone" );
1852         return( 1 );
1853     }
1854
1855     if( !(i_result = MP4_ReadBoxContainer( p_stream, p_box ) ) )
1856     {
1857         return( 0 );
1858     }
1859
1860     if( !( p_dcom = MP4_FindBox( p_box, FOURCC_dcom ) )||
1861         !( p_cmvd = MP4_FindBox( p_box, FOURCC_cmvd ) )||
1862         !( p_cmvd->data.p_cmvd->p_data ) )
1863     {
1864         msg_Warn( p_stream->p_input, "Read Box: \"cmov\" incomplete" );
1865         return( 1 );
1866     }
1867
1868     if( p_dcom->data.p_dcom->i_algorithm != FOURCC_zlib )
1869     {
1870         msg_Dbg( p_stream->p_input, "Read Box: \"cmov\" compression algorithm : %4.4s not supported",
1871                     (char*)&p_dcom->data.p_dcom->i_algorithm );
1872         return( 1 );
1873     }
1874
1875 #ifndef HAVE_ZLIB_H
1876     msg_Dbg( p_stream->p_input,
1877              "Read Box: \"cmov\" zlib unsupported" );
1878     return( 1 );
1879 #else
1880     /* decompress data */
1881     /* allocate a new buffer */
1882     if( !( p_data = malloc( p_cmvd->data.p_cmvd->i_uncompressed_size ) ) )
1883     {
1884         msg_Err( p_stream->p_input,
1885                  "Read Box: \"cmov\" not enough memory to uncompress data" );
1886         return( 1 );
1887     }
1888     /* init default structures */
1889     z_data.next_in   = p_cmvd->data.p_cmvd->p_data;
1890     z_data.avail_in  = p_cmvd->data.p_cmvd->i_compressed_size;
1891     z_data.next_out  = p_data;
1892     z_data.avail_out = p_cmvd->data.p_cmvd->i_uncompressed_size;
1893     z_data.zalloc    = (alloc_func)Z_NULL;
1894     z_data.zfree     = (free_func)Z_NULL;
1895     z_data.opaque    = (voidpf)Z_NULL;
1896
1897     /* init zlib */
1898     if( ( i_result = inflateInit( &z_data ) ) != Z_OK )
1899     {
1900         msg_Err( p_stream->p_input,
1901                  "Read Box: \"cmov\" error while uncompressing data" );
1902         free( p_data );
1903         return( 1 );
1904     }
1905
1906     /* uncompress */
1907     i_result = inflate( &z_data, Z_NO_FLUSH );
1908     if( ( i_result != Z_OK )&&( i_result != Z_STREAM_END ) )
1909     {
1910         msg_Err( p_stream->p_input,
1911                  "Read Box: \"cmov\" error while uncompressing data" );
1912         free( p_data );
1913         return( 1 );
1914     }
1915
1916     if( p_cmvd->data.p_cmvd->i_uncompressed_size != z_data.total_out )
1917     {
1918         msg_Warn( p_stream->p_input,
1919                   "Read Box: \"cmov\" uncompressing data size mismatch" );
1920     }
1921     p_cmvd->data.p_cmvd->i_uncompressed_size = z_data.total_out;
1922
1923     /* close zlib */
1924     i_result = inflateEnd( &z_data );
1925     if( i_result != Z_OK )
1926     {
1927         msg_Warn( p_stream->p_input,
1928            "Read Box: \"cmov\" error while uncompressing data (ignored)" );
1929     }
1930
1931
1932     free( p_cmvd->data.p_cmvd->p_data );
1933     p_cmvd->data.p_cmvd->p_data = p_data;
1934     p_cmvd->data.p_cmvd->b_compressed = 0;
1935
1936     msg_Dbg( p_stream->p_input,
1937              "Read Box: \"cmov\" box succesfully uncompressed" );
1938
1939     //DataDump( p_data, p_cmvd->data.p_cmvd->i_uncompressed_size );
1940     /* now create a memory stream */
1941     p_stream_memory = MP4_MemoryStream( p_stream->p_input,
1942                                         p_cmvd->data.p_cmvd->i_uncompressed_size,
1943                                         p_cmvd->data.p_cmvd->p_data );
1944
1945     //DataDump( p_stream_memory->p_buffer, p_stream_memory->i_stop );
1946
1947     /* and read uncompressd moov */
1948     p_umov = malloc( sizeof( MP4_Box_t ) );
1949
1950     i_result = MP4_ReadBox( p_stream_memory, p_umov, NULL );
1951
1952     p_box->data.p_cmov->p_moov = p_umov;
1953     free( p_stream_memory );
1954
1955 #ifdef MP4_VERBOSE
1956     msg_Dbg( p_stream->p_input,
1957              "Read Box: \"cmov\" compressed movie header completed" );
1958 #endif
1959     return( i_result );
1960 #endif /* HAVE_ZLIB_H */
1961 }
1962
1963 int MP4_ReadBox_rdrf( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
1964 {
1965     uint32_t i_len;
1966     MP4_READBOX_ENTER( MP4_Box_data_rdrf_t );
1967
1968     MP4_GETVERSIONFLAGS( p_box->data.p_rdrf );
1969     MP4_GETFOURCC( p_box->data.p_rdrf->i_ref_type );
1970     MP4_GET4BYTES( i_len );
1971     if( i_len > 0 )
1972     {
1973         uint32_t i;
1974         p_box->data.p_rdrf->psz_ref = malloc( i_len );
1975         for( i = 0; i < i_len; i++ )
1976         {
1977             MP4_GET1BYTE( p_box->data.p_rdrf->psz_ref[i] );
1978         }
1979         p_box->data.p_rdrf->psz_ref[i_len] = '\0';
1980     }
1981     else
1982     {
1983         p_box->data.p_rdrf->psz_ref = NULL;
1984     }
1985
1986 #ifdef MP4_VERBOSE
1987     msg_Dbg( p_stream->p_input,
1988              "Read Box: \"rdrf\" type:%4.4s ref %s",
1989              (char*)&p_box->data.p_rdrf->i_ref_type,
1990              p_box->data.p_rdrf->psz_ref );
1991
1992 #endif
1993     MP4_READBOX_EXIT( 1 );
1994 }
1995 void MP4_FreeBox_rdrf( input_thread_t *p_input, MP4_Box_t *p_box )
1996 {
1997     FREE( p_box->data.p_rdrf->psz_ref )
1998 }
1999
2000
2001 int MP4_ReadBox_rmdr( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
2002 {
2003     MP4_READBOX_ENTER( MP4_Box_data_rmdr_t );
2004
2005     MP4_GETVERSIONFLAGS( p_box->data.p_rmdr );
2006
2007     MP4_GET4BYTES( p_box->data.p_rmdr->i_rate );
2008
2009 #ifdef MP4_VERBOSE
2010     msg_Dbg( p_stream->p_input,
2011              "Read Box: \"rmdr\" rate:%d",
2012              p_box->data.p_rmdr->i_rate );
2013 #endif
2014     MP4_READBOX_EXIT( 1 );
2015 }
2016
2017 int MP4_ReadBox_rmqu( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
2018 {
2019     MP4_READBOX_ENTER( MP4_Box_data_rmqu_t );
2020
2021     MP4_GET4BYTES( p_box->data.p_rmqu->i_quality );
2022
2023 #ifdef MP4_VERBOSE
2024     msg_Dbg( p_stream->p_input,
2025              "Read Box: \"rmqu\" quality:%d",
2026              p_box->data.p_rmqu->i_quality );
2027 #endif
2028     MP4_READBOX_EXIT( 1 );
2029 }
2030
2031 int MP4_ReadBox_rmvc( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
2032 {
2033     MP4_READBOX_ENTER( MP4_Box_data_rmvc_t );
2034     MP4_GETVERSIONFLAGS( p_box->data.p_rmvc );
2035
2036     MP4_GETFOURCC( p_box->data.p_rmvc->i_gestaltType );
2037     MP4_GET4BYTES( p_box->data.p_rmvc->i_val1 );
2038     MP4_GET4BYTES( p_box->data.p_rmvc->i_val2 );
2039     MP4_GET2BYTES( p_box->data.p_rmvc->i_checkType );
2040
2041 #ifdef MP4_VERBOSE
2042     msg_Dbg( p_stream->p_input,
2043              "Read Box: \"rmvc\" gestaltType:%4.4s val1:0x%x val2:0x%x checkType:0x%x",
2044              (char*)&p_box->data.p_rmvc->i_gestaltType,
2045              p_box->data.p_rmvc->i_val1,p_box->data.p_rmvc->i_val2,
2046              p_box->data.p_rmvc->i_checkType );
2047 #endif
2048
2049     MP4_READBOX_EXIT( 1 );
2050 }
2051
2052 /**** ------------------------------------------------------------------- ****/
2053 /****                   "Higher level" Functions                          ****/
2054 /**** ------------------------------------------------------------------- ****/
2055
2056 static struct
2057 {
2058     uint32_t i_type;
2059     int  (*MP4_ReadBox_function )( MP4_Stream_t *p_stream, MP4_Box_t *p_box );
2060     void (*MP4_FreeBox_function )( input_thread_t *p_input, MP4_Box_t *p_box );
2061 } MP4_Box_Function [] =
2062 {
2063     /* Containers */
2064     { FOURCC_moov,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2065     { FOURCC_trak,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2066     { FOURCC_mdia,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2067     { FOURCC_moof,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2068     { FOURCC_minf,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2069     { FOURCC_stbl,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2070     { FOURCC_dinf,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2071     { FOURCC_edts,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2072     { FOURCC_udta,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2073     { FOURCC_nmhd,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2074     { FOURCC_hnti,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2075     { FOURCC_rmra,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2076     { FOURCC_rmda,  MP4_ReadBoxContainer,   MP4_FreeBox_Common },
2077
2078     /* specific box */
2079     { FOURCC_ftyp,  MP4_ReadBox_ftyp,       MP4_FreeBox_ftyp },
2080     { FOURCC_cmov,  MP4_ReadBox_cmov,       MP4_FreeBox_Common },
2081     { FOURCC_mvhd,  MP4_ReadBox_mvhd,       MP4_FreeBox_Common },
2082     { FOURCC_tkhd,  MP4_ReadBox_tkhd,       MP4_FreeBox_Common },
2083     { FOURCC_tref,  MP4_ReadBox_tref,       MP4_FreeBox_Common },
2084     { FOURCC_mdhd,  MP4_ReadBox_mdhd,       MP4_FreeBox_Common },
2085     { FOURCC_hdlr,  MP4_ReadBox_hdlr,       MP4_FreeBox_hdlr },
2086     { FOURCC_vmhd,  MP4_ReadBox_vmhd,       MP4_FreeBox_Common },
2087     { FOURCC_smhd,  MP4_ReadBox_smhd,       MP4_FreeBox_Common },
2088     { FOURCC_hmhd,  MP4_ReadBox_hmhd,       MP4_FreeBox_Common },
2089     { FOURCC_url,   MP4_ReadBox_url,        MP4_FreeBox_url },
2090     { FOURCC_urn,   MP4_ReadBox_urn,        MP4_FreeBox_urn },
2091     { FOURCC_dref,  MP4_ReadBox_dref,       MP4_FreeBox_Common },
2092     { FOURCC_stts,  MP4_ReadBox_stts,       MP4_FreeBox_stts },
2093     { FOURCC_ctts,  MP4_ReadBox_ctts,       MP4_FreeBox_ctts },
2094     { FOURCC_stsd,  MP4_ReadBox_stsd,       MP4_FreeBox_Common },
2095     { FOURCC_stsz,  MP4_ReadBox_stsz,       MP4_FreeBox_stsz },
2096     { FOURCC_stsc,  MP4_ReadBox_stsc,       MP4_FreeBox_stsc },
2097     { FOURCC_stco,  MP4_ReadBox_stco_co64,  MP4_FreeBox_stco_co64 },
2098     { FOURCC_co64,  MP4_ReadBox_stco_co64,  MP4_FreeBox_stco_co64 },
2099     { FOURCC_stss,  MP4_ReadBox_stss,       MP4_FreeBox_stss },
2100     { FOURCC_stsh,  MP4_ReadBox_stsh,       MP4_FreeBox_stsh },
2101     { FOURCC_stdp,  MP4_ReadBox_stdp,       MP4_FreeBox_stdp },
2102     { FOURCC_padb,  MP4_ReadBox_padb,       MP4_FreeBox_padb },
2103     { FOURCC_elst,  MP4_ReadBox_elst,       MP4_FreeBox_elst },
2104     { FOURCC_cprt,  MP4_ReadBox_cprt,       MP4_FreeBox_cprt },
2105     { FOURCC_esds,  MP4_ReadBox_esds,       MP4_FreeBox_esds },
2106     { FOURCC_dcom,  MP4_ReadBox_dcom,       MP4_FreeBox_Common },
2107     { FOURCC_cmvd,  MP4_ReadBox_cmvd,       MP4_FreeBox_cmvd },
2108
2109     /* Nothing to do with this box */
2110     { FOURCC_mdat,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2111     { FOURCC_skip,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2112     { FOURCC_free,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2113     { FOURCC_wide,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
2114
2115     /* for codecs */
2116     { FOURCC_soun,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2117     { FOURCC_ms02,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2118     { FOURCC_ms11,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2119     { FOURCC_ms55,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2120     { FOURCC__mp3,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2121     { FOURCC_mp4a,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2122     { FOURCC_twos,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2123     { FOURCC_sowt,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2124     { FOURCC_QDMC,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2125     { FOURCC_QDM2,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2126     { FOURCC_ima4,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2127     { FOURCC_IMA4,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2128     { FOURCC_dvi,   MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2129     { FOURCC_alaw,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2130     { FOURCC_ulaw,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2131     { FOURCC_raw,   MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2132     { FOURCC_MAC3,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2133     { FOURCC_MAC6,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2134     { FOURCC_Qclp,  MP4_ReadBox_sample_soun,    MP4_FreeBox_Common },
2135
2136     { FOURCC_vide,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2137     { FOURCC_mp4v,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2138     { FOURCC_SVQ1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2139     { FOURCC_SVQ3,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2140     { FOURCC_ZyGo,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2141     { FOURCC_DIVX,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2142     { FOURCC_h263,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2143     { FOURCC_cvid,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2144     { FOURCC_3IV1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2145     { FOURCC_3iv1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2146     { FOURCC_3IV2,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2147     { FOURCC_3iv2,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2148     { FOURCC_3IVD,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2149     { FOURCC_3ivd,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2150     { FOURCC_3VID,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2151     { FOURCC_3vid,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2152     { FOURCC_mjpa,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2153     { FOURCC_mjpb,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2154     { FOURCC_mjqt,  NULL,                       NULL }, /* found in mjpa/b */
2155     { FOURCC_mjht,  NULL,                       NULL },
2156     { FOURCC_dvc,   MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2157     { FOURCC_dvp,   MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2158
2159     { FOURCC_jpeg,  MP4_ReadBox_sample_vide,    MP4_FreeBox_Common },
2160
2161     { FOURCC_mp4s,  NULL,                       MP4_FreeBox_Common },
2162
2163     /* XXX there is 2 box where we could find this entry stbl and tref*/
2164     { FOURCC_hint,  NULL,                       MP4_FreeBox_Common },
2165
2166     /* found in tref box */
2167     { FOURCC_dpnd,  NULL,   NULL },
2168     { FOURCC_ipir,  NULL,   NULL },
2169     { FOURCC_mpod,  NULL,   NULL },
2170
2171     /* found in hnti */
2172     { FOURCC_rtp,   NULL,   NULL },
2173
2174     /* found in rmra */
2175     { FOURCC_rdrf,  MP4_ReadBox_rdrf,           MP4_FreeBox_rdrf   },
2176     { FOURCC_rmdr,  MP4_ReadBox_rmdr,           MP4_FreeBox_Common },
2177     { FOURCC_rmqu,  MP4_ReadBox_rmqu,           MP4_FreeBox_Common },
2178     { FOURCC_rmvc,  MP4_ReadBox_rmvc,           MP4_FreeBox_Common },
2179
2180     /* Last entry */
2181     { 0,            NULL,                   NULL }
2182 };
2183
2184
2185
2186 /*****************************************************************************
2187  * MP4_ReadBox : parse the actual box and the children
2188  *  XXX : Do not go to the next box
2189  *****************************************************************************/
2190 int MP4_ReadBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box, MP4_Box_t *p_father )
2191 {
2192     int i_result;
2193     unsigned int i_index;
2194
2195     if( !MP4_ReadBoxCommon( p_stream, p_box ) )
2196     {
2197         msg_Warn( p_stream->p_input, "Cannot read one box" );
2198         return( 0 );
2199     }
2200     if( !p_box->i_size )
2201     {
2202         msg_Dbg( p_stream->p_input, "Found an empty box (null size)" );
2203         return( 0 );
2204     }
2205     p_box->p_father = p_father;
2206
2207     /* Now search function to call */
2208     for( i_index = 0; ; i_index++ )
2209     {
2210         if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
2211             ( MP4_Box_Function[i_index].i_type == 0 ) )
2212         {
2213             break;
2214         }
2215     }
2216     if( MP4_Box_Function[i_index].MP4_ReadBox_function == NULL )
2217     {
2218         msg_Warn( p_stream->p_input,
2219                   "Unknown box type %4.4s (uncompletetly loaded)",
2220                   (char*)&p_box->i_type );
2221         return( 1 );
2222     }
2223     else
2224     {
2225         i_result =
2226            (MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box );
2227     }
2228
2229     if( !MP4_GotoBox( p_stream, p_box ) )
2230     {
2231         return( 0 );
2232     }
2233     return( i_result );
2234 }
2235 #if 0
2236 /*****************************************************************************
2237  * MP4_CountBox: given a box, count how many child have the requested type
2238  * FIXME : support GUUID
2239  *****************************************************************************/
2240 int MP4_CountBox( MP4_Box_t *p_box, uint32_t i_type )
2241 {
2242     unsigned int i_count;
2243     MP4_Box_t *p_child;
2244
2245     if( !p_box )
2246     {
2247         return( 0 );
2248     }
2249
2250     i_count = 0;
2251     p_child = p_box->p_first;
2252     while( p_child )
2253     {
2254         if( p_child->i_type == i_type )
2255         {
2256             i_count++;
2257         }
2258         p_child = p_child->p_next;
2259     }
2260
2261     return( i_count );
2262 }
2263 #endif
2264
2265 /*****************************************************************************
2266  * MP4_FindBox:  find first box with i_type child of p_box
2267  *      return NULL if not found
2268  *****************************************************************************/
2269
2270 MP4_Box_t *MP4_FindBox( MP4_Box_t *p_box, uint32_t i_type )
2271 {
2272     MP4_Box_t *p_child;
2273
2274     if( !p_box )
2275     {
2276         return( NULL );
2277     }
2278
2279     p_child = p_box->p_first;
2280     while( p_child )
2281     {
2282         if( p_child->i_type == i_type )
2283         {
2284             return( p_child );
2285         }
2286         p_child = p_child->p_next;
2287     }
2288
2289     return( NULL );
2290 }
2291
2292
2293 #if 0
2294 /*****************************************************************************
2295  * MP4_FindNextBox:  find next box with thesame type and at the same level
2296  *                  than p_box
2297  *****************************************************************************/
2298 MP4_Box_t *MP4_FindNextBox( MP4_Box_t *p_box )
2299 {
2300     MP4_Box_t *p_next;
2301
2302     if( !p_box )
2303     {
2304         return( NULL );
2305     }
2306
2307     p_next = p_box->p_next;
2308     while( p_next )
2309     {
2310         if( p_next->i_type == p_box->i_type )
2311         {
2312             return( p_next );
2313         }
2314         p_next = p_next->p_next;
2315     }
2316     return( NULL );
2317 }
2318 /*****************************************************************************
2319  * MP4_FindNbBox:  find the box i_number
2320  *****************************************************************************/
2321 MP4_Box_t *MP4_FindNbBox( MP4_Box_t *p_box, uint32_t i_number )
2322 {
2323     MP4_Box_t *p_child = p_box->p_first;
2324
2325     if( !p_child )
2326     {
2327         return( NULL );
2328     }
2329
2330     while( i_number )
2331     {
2332         if( !( p_child = p_child->p_next ) )
2333         {
2334             return( NULL );
2335         }
2336         i_number--;
2337     }
2338     return( p_child );
2339 }
2340 #endif
2341
2342 /*****************************************************************************
2343  * MP4_FreeBox : free memory after read with MP4_ReadBox and all
2344  * the children
2345  *****************************************************************************/
2346 void MP4_BoxFree( input_thread_t *p_input, MP4_Box_t *p_box )
2347 {
2348     unsigned int i_index;
2349
2350     MP4_Box_t *p_child;
2351     MP4_Box_t *p_next;
2352
2353     if( !p_box )
2354     {
2355         return; /* hehe */
2356     }
2357     p_child = p_box->p_first;
2358     while( p_child )
2359     {
2360         p_next = p_child->p_next;
2361         MP4_BoxFree( p_input, p_child );
2362         /* MP4_FreeBoxChildren have free all data expect p_child itself */
2363         free( p_child );
2364         p_child = p_next;
2365     }
2366
2367     /* Now search function to call */
2368     if( p_box->data.p_data )
2369     {
2370         for( i_index = 0; ; i_index++ )
2371         {
2372             if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
2373                 ( MP4_Box_Function[i_index].i_type == 0 ) )
2374             {
2375                 break;
2376             }
2377         }
2378         if( MP4_Box_Function[i_index].MP4_FreeBox_function == NULL )
2379         {
2380             /* Should not happen */
2381             msg_Warn( p_input,
2382                       "cannot free box %4.4s, type unknown",
2383                       (char*)&p_box->i_type );
2384         }
2385         else
2386         {
2387             MP4_Box_Function[i_index].MP4_FreeBox_function( p_input, p_box );
2388         }
2389
2390         free( p_box->data.p_data );
2391         p_box->data.p_data = NULL;
2392     }
2393
2394     p_box->p_first = NULL;
2395     p_box->p_last = NULL;
2396
2397 }
2398
2399 /*****************************************************************************
2400  * MP4_BoxGetRoot : Parse the entire file, and create all boxes in memory
2401  *****************************************************************************
2402  *  The first box is a virtual box "root" and is the father for all first
2403  *  level boxes for the file, a sort of virtual contener
2404  *****************************************************************************/
2405 int MP4_BoxGetRoot( input_thread_t *p_input, MP4_Box_t *p_root )
2406 {
2407     MP4_Stream_t *p_stream;
2408     int i_result;
2409
2410     MP4_SeekAbsolute( p_input, 0 );     /* Go to the begining */
2411     p_root->i_pos = 0;
2412     p_root->i_type = VLC_FOURCC( 'r', 'o', 'o', 't' );
2413     p_root->i_shortsize = 1;
2414     p_root->i_size = p_input->stream.p_selected_area->i_size;
2415     CreateUUID( &p_root->i_uuid, p_root->i_type );
2416
2417     p_root->data.p_data = NULL;
2418     p_root->p_father = NULL;
2419     p_root->p_first  = NULL;
2420     p_root->p_last  = NULL;
2421     p_root->p_next   = NULL;
2422
2423     p_stream = MP4_InputStream( p_input );
2424
2425     i_result = MP4_ReadBoxContainerRaw( p_stream, p_root );
2426
2427     free( p_stream );
2428
2429     if( i_result )
2430     {
2431         MP4_Box_t *p_child;
2432         MP4_Box_t *p_moov;
2433         MP4_Box_t *p_cmov;
2434
2435         /* check if there is a cmov, if so replace
2436           compressed moov by  uncompressed one */
2437         if( ( p_moov = MP4_FindBox( p_root, FOURCC_moov ) )&&
2438             ( p_cmov = MP4_FindBox( p_moov, FOURCC_cmov ) ) )
2439         {
2440             /* rename the compressed moov as a box to skip */
2441             p_moov->i_type = FOURCC_skip;
2442
2443             /* get uncompressed p_moov */
2444             p_moov = p_cmov->data.p_cmov->p_moov;
2445             p_cmov->data.p_cmov->p_moov = NULL;
2446
2447             /* make p_root father of this new moov */
2448             p_moov->p_father = p_root;
2449
2450             /* insert this new moov box as first child of p_root */
2451             p_moov->p_next = p_child = p_root->p_first;
2452             p_root->p_first = p_moov;
2453         }
2454     }
2455     return( i_result );
2456 }
2457
2458
2459 static void __MP4_BoxDumpStructure( input_thread_t *p_input,
2460                                     MP4_Box_t *p_box, unsigned int i_level )
2461 {
2462     MP4_Box_t *p_child;
2463
2464     if( !i_level )
2465     {
2466         msg_Dbg( p_input, "Dumping root Box \"%4.4s\"",
2467                           (char*)&p_box->i_type );
2468     }
2469     else
2470     {
2471         char str[512];
2472         unsigned int i;
2473         memset( str, (uint8_t)' ', 512 );
2474         for( i = 0; i < i_level; i++ )
2475         {
2476             str[i*5] = '|';
2477         }
2478         sprintf( str + i_level * 5, "+ %4.4s size %d",
2479                       (char*)&p_box->i_type,
2480                       (uint32_t)p_box->i_size );
2481
2482         msg_Dbg( p_input, "%s", str );
2483     }
2484     p_child = p_box->p_first;
2485     while( p_child )
2486     {
2487         __MP4_BoxDumpStructure( p_input, p_child, i_level + 1 );
2488         p_child = p_child->p_next;
2489     }
2490 }
2491
2492 void MP4_BoxDumpStructure( input_thread_t *p_input, MP4_Box_t *p_box )
2493 {
2494     __MP4_BoxDumpStructure( p_input, p_box, 0 );
2495 }
2496
2497
2498
2499 /*****************************************************************************
2500  *****************************************************************************
2501  **
2502  **  High level methods to acces an MP4 file
2503  **
2504  *****************************************************************************
2505  *****************************************************************************/
2506 static void __get_token( char **ppsz_path, char **ppsz_token, int *pi_number )
2507 {
2508     size_t i_len ;
2509     if( !*ppsz_path[0] )
2510     {
2511         *ppsz_token = NULL;
2512         *pi_number = 0;
2513         return;
2514     }
2515     i_len = 0;
2516     while(  (*ppsz_path)[i_len] &&
2517             (*ppsz_path)[i_len] != '/' && (*ppsz_path)[i_len] != '[' )
2518     {
2519         i_len++;
2520     }
2521     if( !i_len && **ppsz_path == '/' )
2522     {
2523         i_len = 1;
2524     }
2525     *ppsz_token = malloc( i_len + 1 );
2526
2527     memcpy( *ppsz_token, *ppsz_path, i_len );
2528
2529     (*ppsz_token)[i_len] = '\0';
2530
2531     *ppsz_path += i_len;
2532
2533     if( **ppsz_path == '[' )
2534     {
2535         (*ppsz_path)++;
2536         *pi_number = strtol( *ppsz_path, NULL, 10 );
2537         while( **ppsz_path && **ppsz_path != ']' )
2538         {
2539             (*ppsz_path)++;
2540         }
2541         if( **ppsz_path == ']' )
2542         {
2543             (*ppsz_path)++;
2544         }
2545     }
2546     else
2547     {
2548         *pi_number = 0;
2549     }
2550     while( **ppsz_path == '/' )
2551     {
2552         (*ppsz_path)++;
2553     }
2554 }
2555
2556 static void __MP4_BoxGet( MP4_Box_t **pp_result,
2557                           MP4_Box_t *p_box, char *psz_fmt, va_list args)
2558 {
2559     char    *psz_path;
2560 #if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN)
2561     size_t  i_size;
2562 #endif
2563
2564     if( !p_box )
2565     {
2566         *pp_result = NULL;
2567         return;
2568     }
2569
2570 #if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN)
2571     vasprintf( &psz_path, psz_fmt, args );
2572 #else
2573     i_size = strlen( psz_fmt ) + 1024;
2574     psz_path = calloc( i_size, sizeof( char ) );
2575     vsnprintf( psz_path, i_size, psz_fmt, args );
2576     psz_path[i_size - 1] = 0;
2577 #endif
2578
2579     if( !psz_path || !psz_path[0] )
2580     {
2581         FREE( psz_path );
2582         *pp_result = NULL;
2583         return;
2584     }
2585
2586 //    fprintf( stderr, "path:'%s'\n", psz_path );
2587     psz_fmt = psz_path; /* keep this pointer, as it need to be unallocated */
2588     for( ; ; )
2589     {
2590         char *psz_token;
2591         int i_number;
2592
2593         __get_token( &psz_path, &psz_token, &i_number );
2594 //        fprintf( stderr, "path:'%s', token:'%s' n:%d\n",
2595 //                 psz_path,psz_token,i_number );
2596         if( !psz_token )
2597         {
2598             FREE( psz_token );
2599             free( psz_fmt );
2600             *pp_result = p_box;
2601             return;
2602         }
2603         else
2604         if( !strcmp( psz_token, "/" ) )
2605         {
2606             /* Find root box */
2607             while( p_box && p_box->i_type != VLC_FOURCC( 'r', 'o', 'o', 't' ) )
2608             {
2609                 p_box = p_box->p_father;
2610             }
2611             if( !p_box )
2612             {
2613                 free( psz_token );
2614                 free( psz_fmt );
2615                 *pp_result = NULL;
2616                 return;
2617             }
2618         }
2619         else
2620         if( !strcmp( psz_token, "." ) )
2621         {
2622             /* Do nothing */
2623         }
2624         else
2625         if( !strcmp( psz_token, ".." ) )
2626         {
2627             p_box = p_box->p_father;
2628             if( !p_box )
2629             {
2630                 free( psz_token );
2631                 free( psz_fmt );
2632                 *pp_result = NULL;
2633                 return;
2634             }
2635         }
2636         else
2637         if( strlen( psz_token ) == 4 )
2638         {
2639             uint32_t i_fourcc;
2640             i_fourcc = VLC_FOURCC( psz_token[0], psz_token[1],
2641                                    psz_token[2], psz_token[3] );
2642             p_box = p_box->p_first;
2643             for( ; ; )
2644             {
2645                 if( !p_box )
2646                 {
2647                     free( psz_token );
2648                     free( psz_fmt );
2649                     *pp_result = NULL;
2650                     return;
2651                 }
2652                 if( p_box->i_type == i_fourcc )
2653                 {
2654                     if( !i_number )
2655                     {
2656                         break;
2657                     }
2658                     i_number--;
2659                 }
2660                 p_box = p_box->p_next;
2661             }
2662         }
2663         else
2664         if( strlen( psz_token ) == 0 )
2665         {
2666             p_box = p_box->p_first;
2667             for( ; ; )
2668             {
2669                 if( !p_box )
2670                 {
2671                     free( psz_token );
2672                     free( psz_fmt );
2673                     *pp_result = NULL;
2674                     return;
2675                 }
2676                 if( !i_number )
2677                 {
2678                     break;
2679                 }
2680                 i_number--;
2681                 p_box = p_box->p_next;
2682             }
2683         }
2684         else
2685         {
2686 //            fprintf( stderr, "Argg malformed token \"%s\"",psz_token );
2687             FREE( psz_token );
2688             free( psz_fmt );
2689             *pp_result = NULL;
2690             return;
2691         }
2692
2693         free( psz_token );
2694     }
2695 }
2696
2697 /*****************************************************************************
2698  * MP4_BoxGet: find a box given a path relative to p_box
2699  *****************************************************************************
2700  * Path Format: . .. / as usual
2701  *              [number] to specifie box number ex: trak[12]
2702  *
2703  * ex: /moov/trak[12]
2704  *     ../mdia
2705  *****************************************************************************/
2706 MP4_Box_t *MP4_BoxGet( MP4_Box_t *p_box, char *psz_fmt, ... )
2707 {
2708     va_list args;
2709     MP4_Box_t *p_result;
2710
2711     va_start( args, psz_fmt );
2712     __MP4_BoxGet( &p_result, p_box, psz_fmt, args );
2713     va_end( args );
2714
2715     return( p_result );
2716 }
2717
2718 /*****************************************************************************
2719  * MP4_BoxCount: count box given a path relative to p_box
2720  *****************************************************************************
2721  * Path Format: . .. / as usual
2722  *              [number] to specifie box number ex: trak[12]
2723  *
2724  * ex: /moov/trak[12]
2725  *     ../mdia
2726  *****************************************************************************/
2727 int MP4_BoxCount( MP4_Box_t *p_box, char *psz_fmt, ... )
2728 {
2729     va_list args;
2730     int     i_count;
2731     MP4_Box_t *p_result, *p_next;
2732
2733     va_start( args, psz_fmt );
2734     __MP4_BoxGet( &p_result, p_box, psz_fmt, args );
2735     va_end( args );
2736     if( !p_result )
2737     {
2738         return( 0 );
2739     }
2740
2741     i_count = 1;
2742     for( p_next = p_result->p_next; p_next != NULL; p_next = p_next->p_next)
2743     {
2744         if( p_next->i_type == p_result->i_type)
2745         {
2746             i_count++;
2747         }
2748     }
2749     return( i_count );
2750 }
2751