Qt: do not show open options in both normal and advanced UI
[vlc.git] / modules / demux / mp4 / libmp4.c
blobd26da3de8e04c551fd76f36735165f9b45674ce5
1 /*****************************************************************************
2 * libmp4.c : LibMP4 library for mp4 module for vlc
3 *****************************************************************************
4 * Copyright (C) 2001-2004, 2010 the VideoLAN team
6 * Author: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <vlc_common.h>
28 #include <vlc_demux.h>
30 #ifdef HAVE_ZLIB_H
31 # include <zlib.h> /* for compressed moov */
32 #endif
34 #include "libmp4.h"
35 #include "drms.h"
37 /*****************************************************************************
38 * Here are defined some macro to make life simpler but before using it
39 * *look* at the code.
41 *****************************************************************************/
43 static inline size_t mp4_box_headersize( MP4_Box_t *p_box )
45 return 8
46 + ( p_box->i_shortsize == 1 ? 8 : 0 )
47 + ( p_box->i_type == ATOM_uuid ? 16 : 0 );
50 #define MP4_GETX_PRIVATE(dst, code, size) do { \
51 if( (i_read) >= (size) ) { dst = (code); p_peek += (size); } \
52 else { dst = 0; } \
53 i_read -= (size); \
54 } while(0)
56 #define MP4_GET1BYTE( dst ) MP4_GETX_PRIVATE( dst, *p_peek, 1 )
57 #define MP4_GET2BYTES( dst ) MP4_GETX_PRIVATE( dst, GetWBE(p_peek), 2 )
58 #define MP4_GET3BYTES( dst ) MP4_GETX_PRIVATE( dst, Get24bBE(p_peek), 3 )
59 #define MP4_GET4BYTES( dst ) MP4_GETX_PRIVATE( dst, GetDWBE(p_peek), 4 )
60 #define MP4_GET8BYTES( dst ) MP4_GETX_PRIVATE( dst, GetQWBE(p_peek), 8 )
61 #define MP4_GETFOURCC( dst ) MP4_GETX_PRIVATE( dst, \
62 VLC_FOURCC(p_peek[0],p_peek[1],p_peek[2],p_peek[3]), 4)
64 #define MP4_GETVERSIONFLAGS( p_void ) \
65 MP4_GET1BYTE( p_void->i_version ); \
66 MP4_GET3BYTES( p_void->i_flags )
68 #define MP4_GETSTRINGZ( p_str ) \
69 if( (i_read > 0) && (p_peek[0]) ) \
70 { \
71 const int __i_copy__ = strnlen( (char*)p_peek, i_read-1 ); \
72 p_str = malloc( __i_copy__+1 ); \
73 if( p_str ) \
74 { \
75 memcpy( p_str, p_peek, __i_copy__ ); \
76 p_str[__i_copy__] = 0; \
77 } \
78 p_peek += __i_copy__ + 1; \
79 i_read -= __i_copy__ + 1; \
80 } \
81 else \
82 { \
83 p_str = NULL; \
86 #define MP4_READBOX_ENTER( MP4_Box_data_TYPE_t ) \
87 int64_t i_read = p_box->i_size; \
88 uint8_t *p_peek, *p_buff; \
89 int i_actually_read; \
90 if( !( p_peek = p_buff = malloc( i_read ) ) ) \
91 { \
92 return( 0 ); \
93 } \
94 i_actually_read = stream_Read( p_stream, p_peek, i_read ); \
95 if( i_actually_read < 0 || (int64_t)i_actually_read < i_read )\
96 { \
97 free( p_buff ); \
98 return( 0 ); \
99 } \
100 p_peek += mp4_box_headersize( p_box ); \
101 i_read -= mp4_box_headersize( p_box ); \
102 if( !( p_box->data.p_data = calloc( 1, sizeof( MP4_Box_data_TYPE_t ) ) ) ) \
104 free( p_buff ); \
105 return( 0 ); \
108 #define MP4_READBOX_EXIT( i_code ) \
109 do \
111 free( p_buff ); \
112 if( i_read < 0 ) \
113 msg_Warn( p_stream, "Not enough data" ); \
114 return( i_code ); \
115 } while (0)
118 /* Some assumptions:
119 * The input method HAS to be seekable
123 /* This macro is used when we want to printf the box type
124 * APPLE annotation box is :
125 * either 0xA9 + 24-bit ASCII text string (and 0xA9 isn't printable)
126 * either 32-bit ASCII text string
128 #define MP4_BOX_TYPE_ASCII() ( ((char*)&p_box->i_type)[0] != (char)0xA9 )
130 static uint32_t Get24bBE( const uint8_t *p )
132 return( ( p[0] <<16 ) + ( p[1] <<8 ) + p[2] );
135 static void GetUUID( UUID_t *p_uuid, const uint8_t *p_buff )
137 memcpy( p_uuid, p_buff, 16 );
140 static void CreateUUID( UUID_t *p_uuid, uint32_t i_fourcc )
142 /* made by 0xXXXXXXXX-0011-0010-8000-00aa00389b71
143 where XXXXXXXX is the fourcc */
144 /* FIXME implement this */
145 (void)p_uuid;
146 (void)i_fourcc;
149 /* some functions for mp4 encoding of variables */
150 #ifdef MP4_VERBOSE
151 static void MP4_ConvertDate2Str( char *psz, uint64_t i_date )
153 int i_day;
154 int i_hour;
155 int i_min;
156 int i_sec;
158 /* date begin at 1 jan 1904 */
159 i_date += ((INT64_C(1904) * 365) + 17) * 24 * 60 * 60;
161 i_day = i_date / ( 60*60*24);
162 i_hour = ( i_date /( 60*60 ) ) % 60;
163 i_min = ( i_date / 60 ) % 60;
164 i_sec = i_date % 60;
165 sprintf( psz, "%dd-%2.2dh:%2.2dm:%2.2ds", i_day, i_hour, i_min, i_sec );
167 #endif
169 /*****************************************************************************
170 * Some prototypes.
171 *****************************************************************************/
172 static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father );
175 /*****************************************************************************
176 * MP4_ReadBoxCommon : Load only common parameters for all boxes
177 *****************************************************************************
178 * p_box need to be an already allocated MP4_Box_t, and all data
179 * will only be peek not read
181 * RETURN : 0 if it fail, 1 otherwise
182 *****************************************************************************/
183 int MP4_ReadBoxCommon( stream_t *p_stream, MP4_Box_t *p_box )
185 int i_read;
186 const uint8_t *p_peek;
188 if( ( ( i_read = stream_Peek( p_stream, &p_peek, 32 ) ) < 8 ) )
190 return 0;
192 p_box->i_pos = stream_Tell( p_stream );
194 p_box->data.p_data = NULL;
195 p_box->p_father = NULL;
196 p_box->p_first = NULL;
197 p_box->p_last = NULL;
198 p_box->p_next = NULL;
200 MP4_GET4BYTES( p_box->i_shortsize );
201 MP4_GETFOURCC( p_box->i_type );
203 /* Now special case */
205 if( p_box->i_shortsize == 1 )
207 /* get the true size on 64 bits */
208 MP4_GET8BYTES( p_box->i_size );
210 else
212 p_box->i_size = p_box->i_shortsize;
213 /* XXX size of 0 means that the box extends to end of file */
216 if( p_box->i_type == ATOM_uuid )
218 /* get extented type on 16 bytes */
219 GetUUID( &p_box->i_uuid, p_peek );
220 p_peek += 16; i_read -= 16;
222 else
224 CreateUUID( &p_box->i_uuid, p_box->i_type );
226 #ifdef MP4_VERBOSE
227 if( p_box->i_size )
229 if MP4_BOX_TYPE_ASCII()
230 msg_Dbg( p_stream, "found Box: %4.4s size %"PRId64,
231 (char*)&p_box->i_type, p_box->i_size );
232 else
233 msg_Dbg( p_stream, "found Box: c%3.3s size %"PRId64,
234 (char*)&p_box->i_type+1, p_box->i_size );
236 #endif
238 return 1;
241 /*****************************************************************************
242 * MP4_NextBox : Go to the next box
243 *****************************************************************************
244 * if p_box == NULL, go to the next box in which we are( at the begining ).
245 *****************************************************************************/
246 static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
248 MP4_Box_t box;
250 if( !p_box )
252 MP4_ReadBoxCommon( p_stream, &box );
253 p_box = &box;
256 if( !p_box->i_size )
258 return 2; /* Box with infinite size */
261 if( p_box->p_father )
263 const off_t i_box_end = p_box->i_size + p_box->i_pos;
264 const off_t i_father_end = p_box->p_father->i_size + p_box->p_father->i_pos;
266 /* check if it's within p-father */
267 if( i_box_end >= i_father_end )
269 if( i_box_end > i_father_end )
270 msg_Dbg( p_stream, "out of bound child" );
271 return 0; /* out of bound */
274 if( stream_Seek( p_stream, p_box->i_size + p_box->i_pos ) )
276 return 0;
279 return 1;
282 /*****************************************************************************
283 * For all known box a loader is given,
284 * XXX: all common struct have to be already read by MP4_ReadBoxCommon
285 * after called one of theses functions, file position is unknown
286 * you need to call MP4_GotoBox to go where you want
287 *****************************************************************************/
288 static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container )
290 MP4_Box_t *p_box;
292 if( stream_Tell( p_stream ) + 8 >
293 (off_t)(p_container->i_pos + p_container->i_size) )
295 /* there is no box to load */
296 return 0;
301 if( ( p_box = MP4_ReadBox( p_stream, p_container ) ) == NULL ) break;
303 /* chain this box with the father and the other at same level */
304 if( !p_container->p_first ) p_container->p_first = p_box;
305 else p_container->p_last->p_next = p_box;
306 p_container->p_last = p_box;
308 } while( MP4_NextBox( p_stream, p_box ) == 1 );
310 return 1;
313 static int MP4_ReadBoxContainer( stream_t *p_stream, MP4_Box_t *p_container )
315 if( p_container->i_size <= (size_t)mp4_box_headersize(p_container ) + 8 )
317 /* container is empty, 8 stand for the first header in this box */
318 return 1;
321 /* enter box */
322 stream_Seek( p_stream, p_container->i_pos +
323 mp4_box_headersize( p_container ) );
325 return MP4_ReadBoxContainerRaw( p_stream, p_container );
328 static void MP4_FreeBox_Common( MP4_Box_t *p_box )
330 /* Up to now do nothing */
331 (void)p_box;
334 static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box )
336 /* XXX sometime moov is hiden in a free box */
337 if( p_box->p_father &&
338 p_box->p_father->i_type == ATOM_root &&
339 p_box->i_type == ATOM_free )
341 const uint8_t *p_peek;
342 int i_read;
343 vlc_fourcc_t i_fcc;
345 i_read = stream_Peek( p_stream, &p_peek, 44 );
347 p_peek += mp4_box_headersize( p_box ) + 4;
348 i_read -= mp4_box_headersize( p_box ) + 4;
350 if( i_read >= 8 )
352 i_fcc = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
354 if( i_fcc == ATOM_cmov || i_fcc == ATOM_mvhd )
356 msg_Warn( p_stream, "detected moov hidden in a free box ..." );
358 p_box->i_type = ATOM_foov;
359 return MP4_ReadBoxContainer( p_stream, p_box );
364 /* Nothing to do */
365 #ifdef MP4_VERBOSE
366 if MP4_BOX_TYPE_ASCII()
367 msg_Dbg( p_stream, "skip box: \"%4.4s\"", (char*)&p_box->i_type );
368 else
369 msg_Dbg( p_stream, "skip box: \"c%3.3s\"", (char*)&p_box->i_type+1 );
370 #endif
371 return 1;
374 static int MP4_ReadBox_ftyp( stream_t *p_stream, MP4_Box_t *p_box )
376 MP4_READBOX_ENTER( MP4_Box_data_ftyp_t );
378 MP4_GETFOURCC( p_box->data.p_ftyp->i_major_brand );
379 MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version );
381 if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) )
383 unsigned int i;
384 uint32_t *tab = p_box->data.p_ftyp->i_compatible_brands =
385 calloc( p_box->data.p_ftyp->i_compatible_brands_count,
386 sizeof(uint32_t));
388 if( tab == NULL )
389 MP4_READBOX_EXIT( 0 );
391 for( i =0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )
393 MP4_GETFOURCC( tab[i] );
396 else
398 p_box->data.p_ftyp->i_compatible_brands = NULL;
401 MP4_READBOX_EXIT( 1 );
404 static void MP4_FreeBox_ftyp( MP4_Box_t *p_box )
406 FREENULL( p_box->data.p_ftyp->i_compatible_brands );
410 static int MP4_ReadBox_mvhd( stream_t *p_stream, MP4_Box_t *p_box )
412 unsigned int i;
413 #ifdef MP4_VERBOSE
414 char s_creation_time[128];
415 char s_modification_time[128];
416 char s_duration[128];
417 #endif
418 MP4_READBOX_ENTER( MP4_Box_data_mvhd_t );
420 MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );
422 if( p_box->data.p_mvhd->i_version )
424 MP4_GET8BYTES( p_box->data.p_mvhd->i_creation_time );
425 MP4_GET8BYTES( p_box->data.p_mvhd->i_modification_time );
426 MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
427 MP4_GET8BYTES( p_box->data.p_mvhd->i_duration );
429 else
431 MP4_GET4BYTES( p_box->data.p_mvhd->i_creation_time );
432 MP4_GET4BYTES( p_box->data.p_mvhd->i_modification_time );
433 MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
434 MP4_GET4BYTES( p_box->data.p_mvhd->i_duration );
436 MP4_GET4BYTES( p_box->data.p_mvhd->i_rate );
437 MP4_GET2BYTES( p_box->data.p_mvhd->i_volume );
438 MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 );
441 for( i = 0; i < 2; i++ )
443 MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] );
445 for( i = 0; i < 9; i++ )
447 MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] );
449 for( i = 0; i < 6; i++ )
451 MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] );
454 MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id );
457 #ifdef MP4_VERBOSE
458 MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
459 MP4_ConvertDate2Str( s_modification_time,
460 p_box->data.p_mvhd->i_modification_time );
461 if( p_box->data.p_mvhd->i_rate )
463 MP4_ConvertDate2Str( s_duration,
464 p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate );
466 else
468 s_duration[0] = 0;
470 msg_Dbg( p_stream, "read box: \"mvhd\" creation %s modification %s time scale %d duration %s rate %f volume %f next track id %d",
471 s_creation_time,
472 s_modification_time,
473 (uint32_t)p_box->data.p_mvhd->i_timescale,
474 s_duration,
475 (float)p_box->data.p_mvhd->i_rate / (1<<16 ),
476 (float)p_box->data.p_mvhd->i_volume / 256 ,
477 (uint32_t)p_box->data.p_mvhd->i_next_track_id );
478 #endif
479 MP4_READBOX_EXIT( 1 );
482 static int MP4_ReadBox_mfhd( stream_t *p_stream, MP4_Box_t *p_box )
484 MP4_READBOX_ENTER( MP4_Box_data_mfhd_t );
486 MP4_GET4BYTES( p_box->data.p_mfhd->i_sequence_number );
488 #ifdef MP4_VERBOSE
489 msg_Dbg( p_stream, "read box: \"mfhd\" sequence number %d",
490 p_box->data.p_mfhd->i_sequence_number );
491 #endif
492 MP4_READBOX_EXIT( 1 );
495 static int MP4_ReadBox_tfhd( stream_t *p_stream, MP4_Box_t *p_box )
497 MP4_READBOX_ENTER( MP4_Box_data_tfhd_t );
499 MP4_GETVERSIONFLAGS( p_box->data.p_tfhd );
501 MP4_GET4BYTES( p_box->data.p_tfhd->i_track_ID );
503 if( p_box->data.p_tfhd->i_version == 0 )
505 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
506 MP4_GET8BYTES( p_box->data.p_tfhd->i_base_data_offset );
507 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
508 MP4_GET4BYTES( p_box->data.p_tfhd->i_sample_description_index );
509 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
510 MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_duration );
511 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
512 MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_size );
513 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
514 MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_flags );
516 #ifdef MP4_VERBOSE
517 char psz_base[128] = "\0";
518 char psz_desc[128] = "\0";
519 char psz_dura[128] = "\0";
520 char psz_size[128] = "\0";
521 char psz_flag[128] = "\0";
522 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
523 snprintf(psz_base, sizeof(psz_base), "base offset %"PRId64, p_box->data.p_tfhd->i_base_data_offset);
524 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
525 snprintf(psz_desc, sizeof(psz_desc), "sample description index %d", p_box->data.p_tfhd->i_sample_description_index);
526 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
527 snprintf(psz_dura, sizeof(psz_dura), "sample duration %d", p_box->data.p_tfhd->i_default_sample_duration);
528 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
529 snprintf(psz_size, sizeof(psz_size), "sample size %d", p_box->data.p_tfhd->i_default_sample_size);
530 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
531 snprintf(psz_flag, sizeof(psz_flag), "sample flags 0x%x", p_box->data.p_tfhd->i_default_sample_flags);
533 msg_Dbg( p_stream, "read box: \"tfhd\" version %d flags 0x%x track ID %d %s %s %s %s %s",
534 p_box->data.p_tfhd->i_version,
535 p_box->data.p_tfhd->i_flags,
536 p_box->data.p_tfhd->i_track_ID,
537 psz_base, psz_desc, psz_dura, psz_size, psz_flag );
538 #endif
541 MP4_READBOX_EXIT( 1 );
544 static int MP4_ReadBox_trun( stream_t *p_stream, MP4_Box_t *p_box )
546 MP4_READBOX_ENTER( MP4_Box_data_trun_t );
548 MP4_GETVERSIONFLAGS( p_box->data.p_trun );
550 MP4_GET4BYTES( p_box->data.p_trun->i_sample_count );
552 if( p_box->data.p_trun->i_flags & MP4_TRUN_DATA_OFFSET )
553 MP4_GET8BYTES( p_box->data.p_trun->i_data_offset );
554 if( p_box->data.p_trun->i_flags & MP4_TRUN_FIRST_FLAGS )
555 MP4_GET4BYTES( p_box->data.p_trun->i_first_sample_flags );
557 p_box->data.p_trun->p_samples =
558 calloc( p_box->data.p_trun->i_sample_count, sizeof(MP4_descriptor_trun_sample_t) );
559 if ( p_box->data.p_trun->p_samples == NULL )
560 MP4_READBOX_EXIT( 0 );
562 for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
564 MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
565 if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION )
566 MP4_GET4BYTES( p_sample->i_duration );
567 if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE )
568 MP4_GET4BYTES( p_sample->i_size );
569 if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_FLAGS )
570 MP4_GET4BYTES( p_sample->i_flags );
571 if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET )
572 MP4_GET4BYTES( p_sample->i_composition_time_offset );
575 #ifdef MP4_VERBOSE
576 msg_Dbg( p_stream, "read box: \"trun\" version %d flags 0x%x sample count %d",
577 p_box->data.p_trun->i_version,
578 p_box->data.p_trun->i_flags,
579 p_box->data.p_trun->i_sample_count );
581 for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
583 MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
584 msg_Dbg( p_stream, "read box: \"trun\" sample %4.4d flags 0x%x duration %d size %d composition time offset %d",
585 i, p_sample->i_flags, p_sample->i_duration,
586 p_sample->i_size, p_sample->i_composition_time_offset );
588 #endif
590 MP4_READBOX_EXIT( 1 );
593 static void MP4_FreeBox_trun( MP4_Box_t *p_box )
595 FREENULL( p_box->data.p_trun->p_samples );
600 static int MP4_ReadBox_tkhd( stream_t *p_stream, MP4_Box_t *p_box )
602 unsigned int i;
603 #ifdef MP4_VERBOSE
604 char s_creation_time[128];
605 char s_modification_time[128];
606 char s_duration[128];
607 #endif
608 MP4_READBOX_ENTER( MP4_Box_data_tkhd_t );
610 MP4_GETVERSIONFLAGS( p_box->data.p_tkhd );
612 if( p_box->data.p_tkhd->i_version )
614 MP4_GET8BYTES( p_box->data.p_tkhd->i_creation_time );
615 MP4_GET8BYTES( p_box->data.p_tkhd->i_modification_time );
616 MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
617 MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
618 MP4_GET8BYTES( p_box->data.p_tkhd->i_duration );
620 else
622 MP4_GET4BYTES( p_box->data.p_tkhd->i_creation_time );
623 MP4_GET4BYTES( p_box->data.p_tkhd->i_modification_time );
624 MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
625 MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
626 MP4_GET4BYTES( p_box->data.p_tkhd->i_duration );
629 for( i = 0; i < 2; i++ )
631 MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved2[i] );
633 MP4_GET2BYTES( p_box->data.p_tkhd->i_layer );
634 MP4_GET2BYTES( p_box->data.p_tkhd->i_predefined );
635 MP4_GET2BYTES( p_box->data.p_tkhd->i_volume );
636 MP4_GET2BYTES( p_box->data.p_tkhd->i_reserved3 );
638 for( i = 0; i < 9; i++ )
640 MP4_GET4BYTES( p_box->data.p_tkhd->i_matrix[i] );
642 MP4_GET4BYTES( p_box->data.p_tkhd->i_width );
643 MP4_GET4BYTES( p_box->data.p_tkhd->i_height );
645 #ifdef MP4_VERBOSE
646 MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
647 MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time );
648 MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration );
650 msg_Dbg( p_stream, "read box: \"tkhd\" creation %s modification %s duration %s track ID %d layer %d volume %f width %f height %f",
651 s_creation_time,
652 s_modification_time,
653 s_duration,
654 p_box->data.p_tkhd->i_track_ID,
655 p_box->data.p_tkhd->i_layer,
656 (float)p_box->data.p_tkhd->i_volume / 256 ,
657 (float)p_box->data.p_tkhd->i_width / 65536,
658 (float)p_box->data.p_tkhd->i_height / 65536 );
659 #endif
660 MP4_READBOX_EXIT( 1 );
664 static int MP4_ReadBox_mdhd( stream_t *p_stream, MP4_Box_t *p_box )
666 unsigned int i;
667 uint16_t i_language;
668 #ifdef MP4_VERBOSE
669 char s_creation_time[128];
670 char s_modification_time[128];
671 char s_duration[128];
672 #endif
673 MP4_READBOX_ENTER( MP4_Box_data_mdhd_t );
675 MP4_GETVERSIONFLAGS( p_box->data.p_mdhd );
677 if( p_box->data.p_mdhd->i_version )
679 MP4_GET8BYTES( p_box->data.p_mdhd->i_creation_time );
680 MP4_GET8BYTES( p_box->data.p_mdhd->i_modification_time );
681 MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
682 MP4_GET8BYTES( p_box->data.p_mdhd->i_duration );
684 else
686 MP4_GET4BYTES( p_box->data.p_mdhd->i_creation_time );
687 MP4_GET4BYTES( p_box->data.p_mdhd->i_modification_time );
688 MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
689 MP4_GET4BYTES( p_box->data.p_mdhd->i_duration );
691 p_box->data.p_mdhd->i_language_code = i_language = GetWBE( p_peek );
692 for( i = 0; i < 3; i++ )
694 p_box->data.p_mdhd->i_language[i] =
695 ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
698 MP4_GET2BYTES( p_box->data.p_mdhd->i_predefined );
700 #ifdef MP4_VERBOSE
701 MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time );
702 MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time );
703 MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration );
704 msg_Dbg( p_stream, "read box: \"mdhd\" creation %s modification %s time scale %d duration %s language %c%c%c",
705 s_creation_time,
706 s_modification_time,
707 (uint32_t)p_box->data.p_mdhd->i_timescale,
708 s_duration,
709 p_box->data.p_mdhd->i_language[0],
710 p_box->data.p_mdhd->i_language[1],
711 p_box->data.p_mdhd->i_language[2] );
712 #endif
713 MP4_READBOX_EXIT( 1 );
717 static int MP4_ReadBox_hdlr( stream_t *p_stream, MP4_Box_t *p_box )
719 int32_t i_reserved;
721 MP4_READBOX_ENTER( MP4_Box_data_hdlr_t );
723 MP4_GETVERSIONFLAGS( p_box->data.p_hdlr );
725 MP4_GETFOURCC( p_box->data.p_hdlr->i_predefined );
726 MP4_GETFOURCC( p_box->data.p_hdlr->i_handler_type );
728 MP4_GET4BYTES( i_reserved );
729 MP4_GET4BYTES( i_reserved );
730 MP4_GET4BYTES( i_reserved );
731 p_box->data.p_hdlr->psz_name = NULL;
733 if( i_read > 0 )
735 uint8_t *psz = p_box->data.p_hdlr->psz_name = malloc( i_read + 1 );
736 if( psz == NULL )
737 MP4_READBOX_EXIT( 0 );
739 /* Yes, I love .mp4 :( */
740 if( p_box->data.p_hdlr->i_predefined == VLC_FOURCC( 'm', 'h', 'l', 'r' ) )
742 uint8_t i_len;
743 int i_copy;
745 MP4_GET1BYTE( i_len );
746 i_copy = __MIN( i_read, i_len );
748 memcpy( psz, p_peek, i_copy );
749 p_box->data.p_hdlr->psz_name[i_copy] = '\0';
751 else
753 memcpy( psz, p_peek, i_read );
754 p_box->data.p_hdlr->psz_name[i_read] = '\0';
758 #ifdef MP4_VERBOSE
759 msg_Dbg( p_stream, "read box: \"hdlr\" handler type: \"%4.4s\" name: \"%s\"",
760 (char*)&p_box->data.p_hdlr->i_handler_type,
761 p_box->data.p_hdlr->psz_name );
763 #endif
764 MP4_READBOX_EXIT( 1 );
767 static void MP4_FreeBox_hdlr( MP4_Box_t *p_box )
769 FREENULL( p_box->data.p_hdlr->psz_name );
772 static int MP4_ReadBox_vmhd( stream_t *p_stream, MP4_Box_t *p_box )
774 unsigned int i;
776 MP4_READBOX_ENTER( MP4_Box_data_vmhd_t );
778 MP4_GETVERSIONFLAGS( p_box->data.p_vmhd );
780 MP4_GET2BYTES( p_box->data.p_vmhd->i_graphics_mode );
781 for( i = 0; i < 3; i++ )
783 MP4_GET2BYTES( p_box->data.p_vmhd->i_opcolor[i] );
786 #ifdef MP4_VERBOSE
787 msg_Dbg( p_stream, "read box: \"vmhd\" graphics-mode %d opcolor (%d, %d, %d)",
788 p_box->data.p_vmhd->i_graphics_mode,
789 p_box->data.p_vmhd->i_opcolor[0],
790 p_box->data.p_vmhd->i_opcolor[1],
791 p_box->data.p_vmhd->i_opcolor[2] );
792 #endif
793 MP4_READBOX_EXIT( 1 );
796 static int MP4_ReadBox_smhd( stream_t *p_stream, MP4_Box_t *p_box )
798 MP4_READBOX_ENTER( MP4_Box_data_smhd_t );
800 MP4_GETVERSIONFLAGS( p_box->data.p_smhd );
804 MP4_GET2BYTES( p_box->data.p_smhd->i_balance );
806 MP4_GET2BYTES( p_box->data.p_smhd->i_reserved );
808 #ifdef MP4_VERBOSE
809 msg_Dbg( p_stream, "read box: \"smhd\" balance %f",
810 (float)p_box->data.p_smhd->i_balance / 256 );
811 #endif
812 MP4_READBOX_EXIT( 1 );
816 static int MP4_ReadBox_hmhd( stream_t *p_stream, MP4_Box_t *p_box )
818 MP4_READBOX_ENTER( MP4_Box_data_hmhd_t );
820 MP4_GETVERSIONFLAGS( p_box->data.p_hmhd );
822 MP4_GET2BYTES( p_box->data.p_hmhd->i_max_PDU_size );
823 MP4_GET2BYTES( p_box->data.p_hmhd->i_avg_PDU_size );
825 MP4_GET4BYTES( p_box->data.p_hmhd->i_max_bitrate );
826 MP4_GET4BYTES( p_box->data.p_hmhd->i_avg_bitrate );
828 MP4_GET4BYTES( p_box->data.p_hmhd->i_reserved );
830 #ifdef MP4_VERBOSE
831 msg_Dbg( p_stream, "read box: \"hmhd\" maxPDU-size %d avgPDU-size %d max-bitrate %d avg-bitrate %d",
832 p_box->data.p_hmhd->i_max_PDU_size,
833 p_box->data.p_hmhd->i_avg_PDU_size,
834 p_box->data.p_hmhd->i_max_bitrate,
835 p_box->data.p_hmhd->i_avg_bitrate );
836 #endif
837 MP4_READBOX_EXIT( 1 );
840 static int MP4_ReadBox_url( stream_t *p_stream, MP4_Box_t *p_box )
842 MP4_READBOX_ENTER( MP4_Box_data_url_t );
844 MP4_GETVERSIONFLAGS( p_box->data.p_url );
845 MP4_GETSTRINGZ( p_box->data.p_url->psz_location );
847 #ifdef MP4_VERBOSE
848 msg_Dbg( p_stream, "read box: \"url\" url: %s",
849 p_box->data.p_url->psz_location );
851 #endif
852 MP4_READBOX_EXIT( 1 );
856 static void MP4_FreeBox_url( MP4_Box_t *p_box )
858 FREENULL( p_box->data.p_url->psz_location );
861 static int MP4_ReadBox_urn( stream_t *p_stream, MP4_Box_t *p_box )
863 MP4_READBOX_ENTER( MP4_Box_data_urn_t );
865 MP4_GETVERSIONFLAGS( p_box->data.p_urn );
867 MP4_GETSTRINGZ( p_box->data.p_urn->psz_name );
868 MP4_GETSTRINGZ( p_box->data.p_urn->psz_location );
870 #ifdef MP4_VERBOSE
871 msg_Dbg( p_stream, "read box: \"urn\" name %s location %s",
872 p_box->data.p_urn->psz_name,
873 p_box->data.p_urn->psz_location );
874 #endif
875 MP4_READBOX_EXIT( 1 );
877 static void MP4_FreeBox_urn( MP4_Box_t *p_box )
879 FREENULL( p_box->data.p_urn->psz_name );
880 FREENULL( p_box->data.p_urn->psz_location );
884 static int MP4_ReadBox_dref( stream_t *p_stream, MP4_Box_t *p_box )
886 MP4_READBOX_ENTER( MP4_Box_data_dref_t );
888 MP4_GETVERSIONFLAGS( p_box->data.p_dref );
890 MP4_GET4BYTES( p_box->data.p_dref->i_entry_count );
892 stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
893 MP4_ReadBoxContainerRaw( p_stream, p_box );
895 #ifdef MP4_VERBOSE
896 msg_Dbg( p_stream, "read box: \"dref\" entry-count %d",
897 p_box->data.p_dref->i_entry_count );
899 #endif
900 MP4_READBOX_EXIT( 1 );
903 static void MP4_FreeBox_stts( MP4_Box_t *p_box )
905 FREENULL( p_box->data.p_stts->i_sample_count );
906 FREENULL( p_box->data.p_stts->i_sample_delta );
909 static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box )
911 unsigned int i;
912 MP4_READBOX_ENTER( MP4_Box_data_stts_t );
914 MP4_GETVERSIONFLAGS( p_box->data.p_stts );
915 MP4_GET4BYTES( p_box->data.p_stts->i_entry_count );
917 p_box->data.p_stts->i_sample_count =
918 calloc( p_box->data.p_stts->i_entry_count, sizeof(uint32_t) );
919 p_box->data.p_stts->i_sample_delta =
920 calloc( p_box->data.p_stts->i_entry_count, sizeof(uint32_t) );
921 if( p_box->data.p_stts->i_sample_count == NULL
922 || p_box->data.p_stts->i_sample_delta == NULL )
924 MP4_READBOX_EXIT( 0 );
927 for( i = 0; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ )
929 MP4_GET4BYTES( p_box->data.p_stts->i_sample_count[i] );
930 MP4_GET4BYTES( p_box->data.p_stts->i_sample_delta[i] );
933 #ifdef MP4_VERBOSE
934 msg_Dbg( p_stream, "read box: \"stts\" entry-count %d",
935 p_box->data.p_stts->i_entry_count );
937 #endif
938 MP4_READBOX_EXIT( 1 );
942 static void MP4_FreeBox_ctts( MP4_Box_t *p_box )
944 FREENULL( p_box->data.p_ctts->i_sample_count );
945 FREENULL( p_box->data.p_ctts->i_sample_offset );
948 static int MP4_ReadBox_ctts( stream_t *p_stream, MP4_Box_t *p_box )
950 unsigned int i;
951 MP4_READBOX_ENTER( MP4_Box_data_ctts_t );
953 MP4_GETVERSIONFLAGS( p_box->data.p_ctts );
955 MP4_GET4BYTES( p_box->data.p_ctts->i_entry_count );
957 p_box->data.p_ctts->i_sample_count =
958 calloc( p_box->data.p_ctts->i_entry_count, sizeof(uint32_t) );
959 p_box->data.p_ctts->i_sample_offset =
960 calloc( p_box->data.p_ctts->i_entry_count, sizeof(uint32_t) );
961 if( ( p_box->data.p_ctts->i_sample_count == NULL )
962 || ( p_box->data.p_ctts->i_sample_offset == NULL ) )
964 MP4_READBOX_EXIT( 0 );
967 for( i = 0; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ )
969 MP4_GET4BYTES( p_box->data.p_ctts->i_sample_count[i] );
970 MP4_GET4BYTES( p_box->data.p_ctts->i_sample_offset[i] );
973 #ifdef MP4_VERBOSE
974 msg_Dbg( p_stream, "read box: \"ctts\" entry-count %d",
975 p_box->data.p_ctts->i_entry_count );
977 #endif
978 MP4_READBOX_EXIT( 1 );
982 static int MP4_ReadLengthDescriptor( uint8_t **pp_peek, int64_t *i_read )
984 unsigned int i_b;
985 unsigned int i_len = 0;
988 i_b = **pp_peek;
990 (*pp_peek)++;
991 (*i_read)--;
992 i_len = ( i_len << 7 ) + ( i_b&0x7f );
993 } while( i_b&0x80 );
994 return( i_len );
998 static void MP4_FreeBox_esds( MP4_Box_t *p_box )
1000 FREENULL( p_box->data.p_esds->es_descriptor.psz_URL );
1001 if( p_box->data.p_esds->es_descriptor.p_decConfigDescr )
1003 FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info );
1004 FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr );
1008 static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
1010 #define es_descriptor p_box->data.p_esds->es_descriptor
1011 unsigned int i_len;
1012 unsigned int i_flags;
1013 unsigned int i_type;
1015 MP4_READBOX_ENTER( MP4_Box_data_esds_t );
1017 MP4_GETVERSIONFLAGS( p_box->data.p_esds );
1020 MP4_GET1BYTE( i_type );
1021 if( i_type == 0x03 ) /* MP4ESDescrTag */
1023 i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1025 #ifdef MP4_VERBOSE
1026 msg_Dbg( p_stream, "found esds MPEG4ESDescr (%dBytes)",
1027 i_len );
1028 #endif
1030 MP4_GET2BYTES( es_descriptor.i_ES_ID );
1031 MP4_GET1BYTE( i_flags );
1032 es_descriptor.b_stream_dependence = ( (i_flags&0x80) != 0);
1033 es_descriptor.b_url = ( (i_flags&0x40) != 0);
1034 es_descriptor.b_OCRstream = ( (i_flags&0x20) != 0);
1036 es_descriptor.i_stream_priority = i_flags&0x1f;
1037 if( es_descriptor.b_stream_dependence )
1039 MP4_GET2BYTES( es_descriptor.i_depend_on_ES_ID );
1041 if( es_descriptor.b_url )
1043 unsigned int i_len;
1045 MP4_GET1BYTE( i_len );
1046 es_descriptor.psz_URL = malloc( i_len + 1 );
1047 if( es_descriptor.psz_URL )
1049 memcpy( es_descriptor.psz_URL, p_peek, i_len );
1050 es_descriptor.psz_URL[i_len] = 0;
1052 p_peek += i_len;
1053 i_read -= i_len;
1055 else
1057 es_descriptor.psz_URL = NULL;
1059 if( es_descriptor.b_OCRstream )
1061 MP4_GET2BYTES( es_descriptor.i_OCR_ES_ID );
1063 MP4_GET1BYTE( i_type ); /* get next type */
1066 if( i_type != 0x04)/* MP4DecConfigDescrTag */
1068 es_descriptor.p_decConfigDescr = NULL;
1069 MP4_READBOX_EXIT( 1 ); /* rest isn't interesting up to now */
1072 i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1074 #ifdef MP4_VERBOSE
1075 msg_Dbg( p_stream, "found esds MP4DecConfigDescr (%dBytes)",
1076 i_len );
1077 #endif
1079 es_descriptor.p_decConfigDescr =
1080 calloc( 1, sizeof( MP4_descriptor_decoder_config_t ));
1081 if( es_descriptor.p_decConfigDescr == NULL )
1082 MP4_READBOX_EXIT( 0 );
1084 MP4_GET1BYTE( es_descriptor.p_decConfigDescr->i_objectTypeIndication );
1085 MP4_GET1BYTE( i_flags );
1086 es_descriptor.p_decConfigDescr->i_streamType = i_flags >> 2;
1087 es_descriptor.p_decConfigDescr->b_upStream = ( i_flags >> 1 )&0x01;
1088 MP4_GET3BYTES( es_descriptor.p_decConfigDescr->i_buffer_sizeDB );
1089 MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_max_bitrate );
1090 MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_avg_bitrate );
1091 MP4_GET1BYTE( i_type );
1092 if( i_type != 0x05 )/* MP4DecSpecificDescrTag */
1094 es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = 0;
1095 es_descriptor.p_decConfigDescr->p_decoder_specific_info = NULL;
1096 MP4_READBOX_EXIT( 1 );
1099 i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1101 #ifdef MP4_VERBOSE
1102 msg_Dbg( p_stream, "found esds MP4DecSpecificDescr (%dBytes)",
1103 i_len );
1104 #endif
1105 if( i_len > i_read )
1106 MP4_READBOX_EXIT( 0 );
1108 es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = i_len;
1109 es_descriptor.p_decConfigDescr->p_decoder_specific_info = malloc( i_len );
1110 if( es_descriptor.p_decConfigDescr->p_decoder_specific_info == NULL )
1111 MP4_READBOX_EXIT( 0 );
1113 memcpy( es_descriptor.p_decConfigDescr->p_decoder_specific_info,
1114 p_peek, i_len );
1116 MP4_READBOX_EXIT( 1 );
1117 #undef es_descriptor
1120 static void MP4_FreeBox_avcC( MP4_Box_t *p_box )
1122 MP4_Box_data_avcC_t *p_avcC = p_box->data.p_avcC;
1123 int i;
1125 if( p_avcC->i_avcC > 0 ) FREENULL( p_avcC->p_avcC );
1127 if( p_avcC->sps )
1129 for( i = 0; i < p_avcC->i_sps; i++ )
1130 FREENULL( p_avcC->sps[i] );
1132 if( p_avcC->pps )
1134 for( i = 0; i < p_avcC->i_pps; i++ )
1135 FREENULL( p_avcC->pps[i] );
1137 if( p_avcC->i_sps > 0 ) FREENULL( p_avcC->sps );
1138 if( p_avcC->i_sps > 0 ) FREENULL( p_avcC->i_sps_length );
1139 if( p_avcC->i_pps > 0 ) FREENULL( p_avcC->pps );
1140 if( p_avcC->i_pps > 0 ) FREENULL( p_avcC->i_pps_length );
1143 static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box )
1145 MP4_Box_data_avcC_t *p_avcC;
1146 int i;
1148 MP4_READBOX_ENTER( MP4_Box_data_avcC_t );
1149 p_avcC = p_box->data.p_avcC;
1151 p_avcC->i_avcC = i_read;
1152 if( p_avcC->i_avcC > 0 )
1154 uint8_t * p = p_avcC->p_avcC = malloc( p_avcC->i_avcC );
1155 if( p )
1156 memcpy( p, p_peek, i_read );
1159 MP4_GET1BYTE( p_avcC->i_version );
1160 MP4_GET1BYTE( p_avcC->i_profile );
1161 MP4_GET1BYTE( p_avcC->i_profile_compatibility );
1162 MP4_GET1BYTE( p_avcC->i_level );
1163 MP4_GET1BYTE( p_avcC->i_reserved1 );
1164 p_avcC->i_length_size = (p_avcC->i_reserved1&0x03) + 1;
1165 p_avcC->i_reserved1 >>= 2;
1167 MP4_GET1BYTE( p_avcC->i_reserved2 );
1168 p_avcC->i_sps = p_avcC->i_reserved2&0x1f;
1169 p_avcC->i_reserved2 >>= 5;
1171 if( p_avcC->i_sps > 0 )
1173 p_avcC->i_sps_length = calloc( p_avcC->i_sps, sizeof( uint16_t ) );
1174 p_avcC->sps = calloc( p_avcC->i_sps, sizeof( uint8_t* ) );
1176 if( !p_avcC->i_sps_length || !p_avcC->sps )
1177 goto error;
1179 for( i = 0; i < p_avcC->i_sps; i++ )
1181 MP4_GET2BYTES( p_avcC->i_sps_length[i] );
1182 p_avcC->sps[i] = malloc( p_avcC->i_sps_length[i] );
1183 if( p_avcC->sps[i] )
1184 memcpy( p_avcC->sps[i], p_peek, p_avcC->i_sps_length[i] );
1186 p_peek += p_avcC->i_sps_length[i];
1187 i_read -= p_avcC->i_sps_length[i];
1191 MP4_GET1BYTE( p_avcC->i_pps );
1192 if( p_avcC->i_pps > 0 )
1194 p_avcC->i_pps_length = calloc( p_avcC->i_pps, sizeof( uint16_t ) );
1195 p_avcC->pps = calloc( p_avcC->i_pps, sizeof( uint8_t* ) );
1197 if( !p_avcC->i_pps_length || !p_avcC->pps )
1198 goto error;
1200 for( i = 0; i < p_avcC->i_pps; i++ )
1202 MP4_GET2BYTES( p_avcC->i_pps_length[i] );
1203 p_avcC->pps[i] = malloc( p_avcC->i_pps_length[i] );
1204 if( p_avcC->pps[i] )
1205 memcpy( p_avcC->pps[i], p_peek, p_avcC->i_pps_length[i] );
1207 p_peek += p_avcC->i_pps_length[i];
1208 i_read -= p_avcC->i_pps_length[i];
1211 #ifdef MP4_VERBOSE
1212 msg_Dbg( p_stream,
1213 "read box: \"avcC\" version=%d profile=0x%x level=0x%x length size=%d sps=%d pps=%d",
1214 p_avcC->i_version, p_avcC->i_profile, p_avcC->i_level,
1215 p_avcC->i_length_size,
1216 p_avcC->i_sps, p_avcC->i_pps );
1217 for( i = 0; i < p_avcC->i_sps; i++ )
1219 msg_Dbg( p_stream, " - sps[%d] length=%d",
1220 i, p_avcC->i_sps_length[i] );
1222 for( i = 0; i < p_avcC->i_pps; i++ )
1224 msg_Dbg( p_stream, " - pps[%d] length=%d",
1225 i, p_avcC->i_pps_length[i] );
1228 #endif
1229 MP4_READBOX_EXIT( 1 );
1231 error:
1232 MP4_READBOX_EXIT( 0 );
1235 static int MP4_ReadBox_dac3( stream_t *p_stream, MP4_Box_t *p_box )
1237 MP4_Box_data_dac3_t *p_dac3;
1238 MP4_READBOX_ENTER( MP4_Box_data_dac3_t );
1240 p_dac3 = p_box->data.p_dac3;
1242 unsigned i_header;
1243 MP4_GET3BYTES( i_header );
1245 p_dac3->i_fscod = ( i_header >> 22 ) & 0x03;
1246 p_dac3->i_bsid = ( i_header >> 17 ) & 0x01f;
1247 p_dac3->i_bsmod = ( i_header >> 14 ) & 0x07;
1248 p_dac3->i_acmod = ( i_header >> 11 ) & 0x07;
1249 p_dac3->i_lfeon = ( i_header >> 10 ) & 0x01;
1250 p_dac3->i_bitrate_code = ( i_header >> 5) & 0x1f;
1252 #ifdef MP4_VERBOSE
1253 msg_Dbg( p_stream,
1254 "read box: \"dac3\" fscod=0x%x bsid=0x%x bsmod=0x%x acmod=0x%x lfeon=0x%x bitrate_code=0x%x",
1255 p_dac3->i_fscod, p_dac3->i_bsid, p_dac3->i_bsmod, p_dac3->i_acmod, p_dac3->i_lfeon, p_dac3->i_bitrate_code );
1256 #endif
1257 MP4_READBOX_EXIT( 1 );
1260 static int MP4_ReadBox_enda( stream_t *p_stream, MP4_Box_t *p_box )
1262 MP4_Box_data_enda_t *p_enda;
1263 MP4_READBOX_ENTER( MP4_Box_data_enda_t );
1265 p_enda = p_box->data.p_enda;
1267 MP4_GET2BYTES( p_enda->i_little_endian );
1269 #ifdef MP4_VERBOSE
1270 msg_Dbg( p_stream,
1271 "read box: \"enda\" little_endian=%d", p_enda->i_little_endian );
1272 #endif
1273 MP4_READBOX_EXIT( 1 );
1276 static int MP4_ReadBox_gnre( stream_t *p_stream, MP4_Box_t *p_box )
1278 MP4_Box_data_gnre_t *p_gnre;
1279 MP4_READBOX_ENTER( MP4_Box_data_gnre_t );
1281 p_gnre = p_box->data.p_gnre;
1283 uint32_t i_data_len;
1284 uint32_t i_data_tag;
1286 MP4_GET4BYTES( i_data_len );
1287 MP4_GETFOURCC( i_data_tag );
1288 if( i_data_len < 10 || i_data_tag != ATOM_data )
1289 MP4_READBOX_EXIT( 0 );
1291 uint32_t i_version;
1292 uint32_t i_reserved;
1293 MP4_GET4BYTES( i_version );
1294 MP4_GET4BYTES( i_reserved );
1295 MP4_GET2BYTES( p_gnre->i_genre );
1296 if( p_gnre->i_genre == 0 )
1297 MP4_READBOX_EXIT( 0 );
1298 #ifdef MP4_VERBOSE
1299 msg_Dbg( p_stream, "read box: \"gnre\" genre=%i", p_gnre->i_genre );
1300 #endif
1302 MP4_READBOX_EXIT( 1 );
1305 static int MP4_ReadBox_trkn( stream_t *p_stream, MP4_Box_t *p_box )
1307 MP4_Box_data_trkn_t *p_trkn;
1308 MP4_READBOX_ENTER( MP4_Box_data_trkn_t );
1310 p_trkn = p_box->data.p_trkn;
1312 uint32_t i_data_len;
1313 uint32_t i_data_tag;
1315 MP4_GET4BYTES( i_data_len );
1316 MP4_GETFOURCC( i_data_tag );
1317 if( i_data_len < 12 || i_data_tag != ATOM_data )
1318 MP4_READBOX_EXIT( 0 );
1320 uint32_t i_version;
1321 uint32_t i_reserved;
1322 MP4_GET4BYTES( i_version );
1323 MP4_GET4BYTES( i_reserved );
1324 MP4_GET4BYTES( p_trkn->i_track_number );
1325 #ifdef MP4_VERBOSE
1326 msg_Dbg( p_stream, "read box: \"trkn\" number=%i", p_trkn->i_track_number );
1327 #endif
1328 if( i_data_len > 15 )
1330 MP4_GET4BYTES( p_trkn->i_track_total );
1331 #ifdef MP4_VERBOSE
1332 msg_Dbg( p_stream, "read box: \"trkn\" total=%i", p_trkn->i_track_total );
1333 #endif
1336 MP4_READBOX_EXIT( 1 );
1340 static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
1342 unsigned int i;
1344 MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t );
1345 p_box->data.p_sample_soun->p_qt_description = NULL;
1347 /* Sanity check needed because the "wave" box does also contain an
1348 * "mp4a" box that we don't understand. */
1349 if( i_read < 28 )
1351 i_read -= 30;
1352 MP4_READBOX_EXIT( 1 );
1355 for( i = 0; i < 6 ; i++ )
1357 MP4_GET1BYTE( p_box->data.p_sample_soun->i_reserved1[i] );
1360 MP4_GET2BYTES( p_box->data.p_sample_soun->i_data_reference_index );
1363 * XXX hack -> produce a copy of the nearly complete chunk
1365 p_box->data.p_sample_soun->i_qt_description = 0;
1366 p_box->data.p_sample_soun->p_qt_description = NULL;
1367 if( i_read > 0 )
1369 p_box->data.p_sample_soun->p_qt_description = malloc( i_read );
1370 if( p_box->data.p_sample_soun->p_qt_description )
1372 p_box->data.p_sample_soun->i_qt_description = i_read;
1373 memcpy( p_box->data.p_sample_soun->p_qt_description, p_peek, i_read );
1377 MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_version );
1378 MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_revision_level );
1379 MP4_GET4BYTES( p_box->data.p_sample_soun->i_qt_vendor );
1381 MP4_GET2BYTES( p_box->data.p_sample_soun->i_channelcount );
1382 MP4_GET2BYTES( p_box->data.p_sample_soun->i_samplesize );
1383 MP4_GET2BYTES( p_box->data.p_sample_soun->i_predefined );
1384 MP4_GET2BYTES( p_box->data.p_sample_soun->i_reserved3 );
1385 MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratehi );
1386 MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratelo );
1388 if( p_box->data.p_sample_soun->i_qt_version == 1 && i_read >= 16 )
1390 /* SoundDescriptionV1 */
1391 MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
1392 MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_packet );
1393 MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_frame );
1394 MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_sample );
1396 #ifdef MP4_VERBOSE
1397 msg_Dbg( p_stream,
1398 "read box: \"soun\" qt3+ sample/packet=%d bytes/packet=%d "
1399 "bytes/frame=%d bytes/sample=%d",
1400 p_box->data.p_sample_soun->i_sample_per_packet,
1401 p_box->data.p_sample_soun->i_bytes_per_packet,
1402 p_box->data.p_sample_soun->i_bytes_per_frame,
1403 p_box->data.p_sample_soun->i_bytes_per_sample );
1404 #endif
1405 stream_Seek( p_stream, p_box->i_pos +
1406 mp4_box_headersize( p_box ) + 44 );
1408 else if( p_box->data.p_sample_soun->i_qt_version == 2 && i_read >= 36 )
1410 /* SoundDescriptionV2 */
1411 double f_sample_rate;
1412 int64_t dummy;
1413 uint32_t i_channel;
1415 MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
1416 MP4_GET8BYTES( dummy );
1417 memcpy( &f_sample_rate, &dummy, 8 );
1419 msg_Dbg( p_stream, "read box: %f Hz", f_sample_rate );
1420 p_box->data.p_sample_soun->i_sampleratehi = (int)f_sample_rate % 65536;
1421 p_box->data.p_sample_soun->i_sampleratelo = f_sample_rate / 65536;
1423 MP4_GET4BYTES( i_channel );
1424 p_box->data.p_sample_soun->i_channelcount = i_channel;
1426 #ifdef MP4_VERBOSE
1427 msg_Dbg( p_stream, "read box: \"soun\" V2" );
1428 #endif
1429 stream_Seek( p_stream, p_box->i_pos +
1430 mp4_box_headersize( p_box ) + 28 + 36 );
1432 else
1434 p_box->data.p_sample_soun->i_sample_per_packet = 0;
1435 p_box->data.p_sample_soun->i_bytes_per_packet = 0;
1436 p_box->data.p_sample_soun->i_bytes_per_frame = 0;
1437 p_box->data.p_sample_soun->i_bytes_per_sample = 0;
1439 #ifdef MP4_VERBOSE
1440 msg_Dbg( p_stream, "read box: \"soun\" mp4 or qt1/2 (rest=%"PRId64")",
1441 i_read );
1442 #endif
1443 stream_Seek( p_stream, p_box->i_pos +
1444 mp4_box_headersize( p_box ) + 28 );
1447 if( p_box->i_type == ATOM_drms )
1449 char *home = config_GetUserDir( VLC_HOME_DIR );
1450 if( home != NULL )
1452 p_box->data.p_sample_soun->p_drms = drms_alloc( home );
1453 if( p_box->data.p_sample_soun->p_drms == NULL )
1454 msg_Err( p_stream, "drms_alloc() failed" );
1458 if( p_box->i_type == ATOM_samr || p_box->i_type == ATOM_sawb )
1460 /* Ignore channelcount for AMR (3gpp AMRSpecificBox) */
1461 p_box->data.p_sample_soun->i_channelcount = 1;
1464 MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds/wave/... */
1466 #ifdef MP4_VERBOSE
1467 msg_Dbg( p_stream, "read box: \"soun\" in stsd channel %d "
1468 "sample size %d sample rate %f",
1469 p_box->data.p_sample_soun->i_channelcount,
1470 p_box->data.p_sample_soun->i_samplesize,
1471 (float)p_box->data.p_sample_soun->i_sampleratehi +
1472 (float)p_box->data.p_sample_soun->i_sampleratelo / 65536 );
1474 #endif
1475 MP4_READBOX_EXIT( 1 );
1479 static void MP4_FreeBox_sample_soun( MP4_Box_t *p_box )
1481 FREENULL( p_box->data.p_sample_soun->p_qt_description );
1483 if( p_box->i_type == ATOM_drms )
1485 if( p_box->data.p_sample_soun->p_drms )
1487 drms_free( p_box->data.p_sample_soun->p_drms );
1493 int MP4_ReadBox_sample_vide( stream_t *p_stream, MP4_Box_t *p_box )
1495 unsigned int i;
1497 MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t );
1499 for( i = 0; i < 6 ; i++ )
1501 MP4_GET1BYTE( p_box->data.p_sample_vide->i_reserved1[i] );
1504 MP4_GET2BYTES( p_box->data.p_sample_vide->i_data_reference_index );
1507 * XXX hack -> produce a copy of the nearly complete chunk
1509 if( i_read > 0 )
1511 p_box->data.p_sample_vide->p_qt_image_description = malloc( i_read );
1512 if( p_box->data.p_sample_vide->p_qt_image_description == NULL )
1513 MP4_READBOX_EXIT( 0 );
1514 p_box->data.p_sample_vide->i_qt_image_description = i_read;
1515 memcpy( p_box->data.p_sample_vide->p_qt_image_description,
1516 p_peek, i_read );
1518 else
1520 p_box->data.p_sample_vide->i_qt_image_description = 0;
1521 p_box->data.p_sample_vide->p_qt_image_description = NULL;
1524 MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_version );
1525 MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_revision_level );
1526 MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_vendor );
1528 MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_temporal_quality );
1529 MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_spatial_quality );
1531 MP4_GET2BYTES( p_box->data.p_sample_vide->i_width );
1532 MP4_GET2BYTES( p_box->data.p_sample_vide->i_height );
1534 MP4_GET4BYTES( p_box->data.p_sample_vide->i_horizresolution );
1535 MP4_GET4BYTES( p_box->data.p_sample_vide->i_vertresolution );
1537 MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_data_size );
1538 MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_frame_count );
1540 memcpy( &p_box->data.p_sample_vide->i_compressorname, p_peek, 32 );
1541 p_peek += 32; i_read -= 32;
1543 MP4_GET2BYTES( p_box->data.p_sample_vide->i_depth );
1544 MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_color_table );
1546 stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 78);
1548 if( p_box->i_type == ATOM_drmi )
1550 char *home = config_GetUserDir( VLC_HOME_DIR );
1551 if( home != NULL )
1553 p_box->data.p_sample_vide->p_drms = drms_alloc( home );
1554 if( p_box->data.p_sample_vide->p_drms == NULL )
1555 msg_Err( p_stream, "drms_alloc() failed" );
1559 MP4_ReadBoxContainerRaw( p_stream, p_box );
1561 #ifdef MP4_VERBOSE
1562 msg_Dbg( p_stream, "read box: \"vide\" in stsd %dx%d depth %d",
1563 p_box->data.p_sample_vide->i_width,
1564 p_box->data.p_sample_vide->i_height,
1565 p_box->data.p_sample_vide->i_depth );
1567 #endif
1568 MP4_READBOX_EXIT( 1 );
1572 void MP4_FreeBox_sample_vide( MP4_Box_t *p_box )
1574 FREENULL( p_box->data.p_sample_vide->p_qt_image_description );
1576 if( p_box->i_type == ATOM_drmi )
1578 if( p_box->data.p_sample_vide->p_drms )
1580 drms_free( p_box->data.p_sample_vide->p_drms );
1585 static int MP4_ReadBox_sample_mp4s( stream_t *p_stream, MP4_Box_t *p_box )
1587 stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
1588 MP4_ReadBoxContainerRaw( p_stream, p_box );
1589 return 1;
1592 static int MP4_ReadBox_sample_text( stream_t *p_stream, MP4_Box_t *p_box )
1594 int32_t t;
1596 MP4_READBOX_ENTER( MP4_Box_data_sample_text_t );
1598 MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved1 );
1599 MP4_GET2BYTES( p_box->data.p_sample_text->i_reserved2 );
1601 MP4_GET2BYTES( p_box->data.p_sample_text->i_data_reference_index );
1603 MP4_GET4BYTES( p_box->data.p_sample_text->i_display_flags );
1605 MP4_GET4BYTES( t );
1606 switch( t )
1608 /* FIXME search right signification */
1609 case 1: // Center
1610 p_box->data.p_sample_text->i_justification_horizontal = 1;
1611 p_box->data.p_sample_text->i_justification_vertical = 1;
1612 break;
1613 case -1: // Flush Right
1614 p_box->data.p_sample_text->i_justification_horizontal = -1;
1615 p_box->data.p_sample_text->i_justification_vertical = -1;
1616 break;
1617 case -2: // Flush Left
1618 p_box->data.p_sample_text->i_justification_horizontal = 0;
1619 p_box->data.p_sample_text->i_justification_vertical = 0;
1620 break;
1621 case 0: // Flush Default
1622 default:
1623 p_box->data.p_sample_text->i_justification_horizontal = 1;
1624 p_box->data.p_sample_text->i_justification_vertical = -1;
1625 break;
1628 MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[0] );
1629 MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[1] );
1630 MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[2] );
1631 p_box->data.p_sample_text->i_background_color[3] = 0;
1633 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_top );
1634 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_left );
1635 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_bottom );
1636 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_right );
1638 #ifdef MP4_VERBOSE
1639 msg_Dbg( p_stream, "read box: \"text\" in stsd text" );
1640 #endif
1641 MP4_READBOX_EXIT( 1 );
1644 static int MP4_ReadBox_sample_tx3g( stream_t *p_stream, MP4_Box_t *p_box )
1646 MP4_READBOX_ENTER( MP4_Box_data_sample_text_t );
1648 MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved1 );
1649 MP4_GET2BYTES( p_box->data.p_sample_text->i_reserved2 );
1651 MP4_GET2BYTES( p_box->data.p_sample_text->i_data_reference_index );
1653 MP4_GET4BYTES( p_box->data.p_sample_text->i_display_flags );
1655 MP4_GET1BYTE ( p_box->data.p_sample_text->i_justification_horizontal );
1656 MP4_GET1BYTE ( p_box->data.p_sample_text->i_justification_vertical );
1658 MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[0] );
1659 MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[1] );
1660 MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[2] );
1661 MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[3] );
1663 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_top );
1664 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_left );
1665 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_bottom );
1666 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_right );
1668 #ifdef MP4_VERBOSE
1669 msg_Dbg( p_stream, "read box: \"tx3g\" in stsd text" );
1670 #endif
1671 MP4_READBOX_EXIT( 1 );
1675 #if 0
1676 /* We can't easily call it, and anyway ~ 20 bytes lost isn't a real problem */
1677 static void MP4_FreeBox_sample_text( MP4_Box_t *p_box )
1679 FREENULL( p_box->data.p_sample_text->psz_text_name );
1681 #endif
1684 static int MP4_ReadBox_stsd( stream_t *p_stream, MP4_Box_t *p_box )
1687 MP4_READBOX_ENTER( MP4_Box_data_stsd_t );
1689 MP4_GETVERSIONFLAGS( p_box->data.p_stsd );
1691 MP4_GET4BYTES( p_box->data.p_stsd->i_entry_count );
1693 stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
1695 MP4_ReadBoxContainerRaw( p_stream, p_box );
1697 #ifdef MP4_VERBOSE
1698 msg_Dbg( p_stream, "read box: \"stsd\" entry-count %d",
1699 p_box->data.p_stsd->i_entry_count );
1701 #endif
1702 MP4_READBOX_EXIT( 1 );
1706 static int MP4_ReadBox_stsz( stream_t *p_stream, MP4_Box_t *p_box )
1708 unsigned int i;
1710 MP4_READBOX_ENTER( MP4_Box_data_stsz_t );
1712 MP4_GETVERSIONFLAGS( p_box->data.p_stsz );
1714 MP4_GET4BYTES( p_box->data.p_stsz->i_sample_size );
1716 MP4_GET4BYTES( p_box->data.p_stsz->i_sample_count );
1718 p_box->data.p_stsz->i_entry_size =
1719 calloc( p_box->data.p_stsz->i_sample_count, sizeof(uint32_t) );
1720 if( p_box->data.p_stsz->i_entry_size == NULL )
1721 MP4_READBOX_EXIT( 0 );
1723 if( !p_box->data.p_stsz->i_sample_size )
1725 for( i=0; (i<p_box->data.p_stsz->i_sample_count)&&(i_read >= 4 ); i++ )
1727 MP4_GET4BYTES( p_box->data.p_stsz->i_entry_size[i] );
1731 #ifdef MP4_VERBOSE
1732 msg_Dbg( p_stream, "read box: \"stsz\" sample-size %d sample-count %d",
1733 p_box->data.p_stsz->i_sample_size,
1734 p_box->data.p_stsz->i_sample_count );
1736 #endif
1737 MP4_READBOX_EXIT( 1 );
1740 static void MP4_FreeBox_stsz( MP4_Box_t *p_box )
1742 FREENULL( p_box->data.p_stsz->i_entry_size );
1745 static void MP4_FreeBox_stsc( MP4_Box_t *p_box )
1747 FREENULL( p_box->data.p_stsc->i_first_chunk );
1748 FREENULL( p_box->data.p_stsc->i_samples_per_chunk );
1749 FREENULL( p_box->data.p_stsc->i_sample_description_index );
1752 static int MP4_ReadBox_stsc( stream_t *p_stream, MP4_Box_t *p_box )
1754 unsigned int i;
1756 MP4_READBOX_ENTER( MP4_Box_data_stsc_t );
1758 MP4_GETVERSIONFLAGS( p_box->data.p_stsc );
1760 MP4_GET4BYTES( p_box->data.p_stsc->i_entry_count );
1762 p_box->data.p_stsc->i_first_chunk =
1763 calloc( p_box->data.p_stsc->i_entry_count, sizeof(uint32_t) );
1764 p_box->data.p_stsc->i_samples_per_chunk =
1765 calloc( p_box->data.p_stsc->i_entry_count, sizeof(uint32_t) );
1766 p_box->data.p_stsc->i_sample_description_index =
1767 calloc( p_box->data.p_stsc->i_entry_count, sizeof(uint32_t) );
1768 if( p_box->data.p_stsc->i_first_chunk == NULL
1769 || p_box->data.p_stsc->i_samples_per_chunk == NULL
1770 || p_box->data.p_stsc->i_sample_description_index == NULL )
1772 MP4_READBOX_EXIT( 0 );
1775 for( i = 0; (i < p_box->data.p_stsc->i_entry_count )&&( i_read >= 12 );i++ )
1777 MP4_GET4BYTES( p_box->data.p_stsc->i_first_chunk[i] );
1778 MP4_GET4BYTES( p_box->data.p_stsc->i_samples_per_chunk[i] );
1779 MP4_GET4BYTES( p_box->data.p_stsc->i_sample_description_index[i] );
1782 #ifdef MP4_VERBOSE
1783 msg_Dbg( p_stream, "read box: \"stsc\" entry-count %d",
1784 p_box->data.p_stsc->i_entry_count );
1786 #endif
1787 MP4_READBOX_EXIT( 1 );
1790 static int MP4_ReadBox_stco_co64( stream_t *p_stream, MP4_Box_t *p_box )
1792 unsigned int i;
1794 MP4_READBOX_ENTER( MP4_Box_data_co64_t );
1796 MP4_GETVERSIONFLAGS( p_box->data.p_co64 );
1798 MP4_GET4BYTES( p_box->data.p_co64->i_entry_count );
1800 p_box->data.p_co64->i_chunk_offset =
1801 calloc( p_box->data.p_co64->i_entry_count, sizeof(uint64_t) );
1802 if( p_box->data.p_co64->i_chunk_offset == NULL )
1803 MP4_READBOX_EXIT( 0 );
1805 for( i = 0; i < p_box->data.p_co64->i_entry_count; i++ )
1807 if( p_box->i_type == ATOM_stco )
1809 if( i_read < 4 )
1811 break;
1813 MP4_GET4BYTES( p_box->data.p_co64->i_chunk_offset[i] );
1815 else
1817 if( i_read < 8 )
1819 break;
1821 MP4_GET8BYTES( p_box->data.p_co64->i_chunk_offset[i] );
1825 #ifdef MP4_VERBOSE
1826 msg_Dbg( p_stream, "read box: \"co64\" entry-count %d",
1827 p_box->data.p_co64->i_entry_count );
1829 #endif
1830 MP4_READBOX_EXIT( 1 );
1833 static void MP4_FreeBox_stco_co64( MP4_Box_t *p_box )
1835 FREENULL( p_box->data.p_co64->i_chunk_offset );
1838 static int MP4_ReadBox_stss( stream_t *p_stream, MP4_Box_t *p_box )
1840 unsigned int i;
1842 MP4_READBOX_ENTER( MP4_Box_data_stss_t );
1844 MP4_GETVERSIONFLAGS( p_box->data.p_stss );
1846 MP4_GET4BYTES( p_box->data.p_stss->i_entry_count );
1848 p_box->data.p_stss->i_sample_number =
1849 calloc( p_box->data.p_stss->i_entry_count, sizeof(uint32_t) );
1850 if( p_box->data.p_stss->i_sample_number == NULL )
1851 MP4_READBOX_EXIT( 0 );
1853 for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 4 ); i++ )
1856 MP4_GET4BYTES( p_box->data.p_stss->i_sample_number[i] );
1857 /* XXX in libmp4 sample begin at 0 */
1858 p_box->data.p_stss->i_sample_number[i]--;
1861 #ifdef MP4_VERBOSE
1862 msg_Dbg( p_stream, "read box: \"stss\" entry-count %d",
1863 p_box->data.p_stss->i_entry_count );
1865 #endif
1866 MP4_READBOX_EXIT( 1 );
1869 static void MP4_FreeBox_stss( MP4_Box_t *p_box )
1871 FREENULL( p_box->data.p_stss->i_sample_number );
1874 static void MP4_FreeBox_stsh( MP4_Box_t *p_box )
1876 FREENULL( p_box->data.p_stsh->i_shadowed_sample_number );
1877 FREENULL( p_box->data.p_stsh->i_sync_sample_number );
1880 static int MP4_ReadBox_stsh( stream_t *p_stream, MP4_Box_t *p_box )
1882 unsigned int i;
1884 MP4_READBOX_ENTER( MP4_Box_data_stsh_t );
1886 MP4_GETVERSIONFLAGS( p_box->data.p_stsh );
1889 MP4_GET4BYTES( p_box->data.p_stsh->i_entry_count );
1891 p_box->data.p_stsh->i_shadowed_sample_number =
1892 calloc( p_box->data.p_stsh->i_entry_count, sizeof(uint32_t) );
1893 p_box->data.p_stsh->i_sync_sample_number =
1894 calloc( p_box->data.p_stsh->i_entry_count, sizeof(uint32_t) );
1896 if( p_box->data.p_stsh->i_shadowed_sample_number == NULL
1897 || p_box->data.p_stsh->i_sync_sample_number == NULL )
1899 MP4_READBOX_EXIT( 0 );
1902 for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 8 ); i++ )
1905 MP4_GET4BYTES( p_box->data.p_stsh->i_shadowed_sample_number[i] );
1906 MP4_GET4BYTES( p_box->data.p_stsh->i_sync_sample_number[i] );
1909 #ifdef MP4_VERBOSE
1910 msg_Dbg( p_stream, "read box: \"stsh\" entry-count %d",
1911 p_box->data.p_stsh->i_entry_count );
1912 #endif
1913 MP4_READBOX_EXIT( 1 );
1917 static int MP4_ReadBox_stdp( stream_t *p_stream, MP4_Box_t *p_box )
1919 unsigned int i;
1921 MP4_READBOX_ENTER( MP4_Box_data_stdp_t );
1923 MP4_GETVERSIONFLAGS( p_box->data.p_stdp );
1925 p_box->data.p_stdp->i_priority =
1926 calloc( i_read / 2, sizeof(uint16_t) );
1928 for( i = 0; i < i_read / 2 ; i++ )
1931 MP4_GET2BYTES( p_box->data.p_stdp->i_priority[i] );
1934 #ifdef MP4_VERBOSE
1935 msg_Dbg( p_stream, "read box: \"stdp\" entry-count %"PRId64,
1936 i_read / 2 );
1938 #endif
1939 MP4_READBOX_EXIT( 1 );
1942 static void MP4_FreeBox_stdp( MP4_Box_t *p_box )
1944 FREENULL( p_box->data.p_stdp->i_priority );
1947 static void MP4_FreeBox_padb( MP4_Box_t *p_box )
1949 FREENULL( p_box->data.p_padb->i_reserved1 );
1950 FREENULL( p_box->data.p_padb->i_pad2 );
1951 FREENULL( p_box->data.p_padb->i_reserved2 );
1952 FREENULL( p_box->data.p_padb->i_pad1 );
1955 static int MP4_ReadBox_padb( stream_t *p_stream, MP4_Box_t *p_box )
1957 unsigned int i;
1958 uint32_t count;
1960 MP4_READBOX_ENTER( MP4_Box_data_padb_t );
1962 MP4_GETVERSIONFLAGS( p_box->data.p_padb );
1964 MP4_GET4BYTES( p_box->data.p_padb->i_sample_count );
1965 count = (p_box->data.p_padb->i_sample_count + 1) / 2;
1967 p_box->data.p_padb->i_reserved1 = calloc( count, sizeof(uint16_t) );
1968 p_box->data.p_padb->i_pad2 = calloc( count, sizeof(uint16_t) );
1969 p_box->data.p_padb->i_reserved2 = calloc( count, sizeof(uint16_t) );
1970 p_box->data.p_padb->i_pad1 = calloc( count, sizeof(uint16_t) );
1971 if( p_box->data.p_padb->i_reserved1 == NULL
1972 || p_box->data.p_padb->i_pad2 == NULL
1973 || p_box->data.p_padb->i_reserved2 == NULL
1974 || p_box->data.p_padb->i_pad1 == NULL )
1976 MP4_READBOX_EXIT( 0 );
1979 for( i = 0; i < i_read / 2 ; i++ )
1981 if( i >= count )
1983 MP4_READBOX_EXIT( 0 );
1985 p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 7 )&0x01;
1986 p_box->data.p_padb->i_pad2[i] = ( (*p_peek) >> 4 )&0x07;
1987 p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 3 )&0x01;
1988 p_box->data.p_padb->i_pad1[i] = ( (*p_peek) )&0x07;
1990 p_peek += 1; i_read -= 1;
1993 #ifdef MP4_VERBOSE
1994 msg_Dbg( p_stream, "read box: \"stdp\" entry-count %"PRId64,
1995 i_read / 2 );
1997 #endif
1998 MP4_READBOX_EXIT( 1 );
2001 static void MP4_FreeBox_elst( MP4_Box_t *p_box )
2003 FREENULL( p_box->data.p_elst->i_segment_duration );
2004 FREENULL( p_box->data.p_elst->i_media_time );
2005 FREENULL( p_box->data.p_elst->i_media_rate_integer );
2006 FREENULL( p_box->data.p_elst->i_media_rate_fraction );
2009 static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box )
2011 unsigned int i;
2013 MP4_READBOX_ENTER( MP4_Box_data_elst_t );
2015 MP4_GETVERSIONFLAGS( p_box->data.p_elst );
2018 MP4_GET4BYTES( p_box->data.p_elst->i_entry_count );
2020 p_box->data.p_elst->i_segment_duration =
2021 calloc( p_box->data.p_elst->i_entry_count, sizeof(uint64_t) );
2022 p_box->data.p_elst->i_media_time =
2023 calloc( p_box->data.p_elst->i_entry_count, sizeof(uint64_t) );
2024 p_box->data.p_elst->i_media_rate_integer =
2025 calloc( p_box->data.p_elst->i_entry_count, sizeof(uint16_t) );
2026 p_box->data.p_elst->i_media_rate_fraction =
2027 calloc( p_box->data.p_elst->i_entry_count, sizeof(uint16_t) );
2028 if( p_box->data.p_elst->i_segment_duration == NULL
2029 || p_box->data.p_elst->i_media_time == NULL
2030 || p_box->data.p_elst->i_media_rate_integer == NULL
2031 || p_box->data.p_elst->i_media_rate_fraction == NULL )
2033 MP4_READBOX_EXIT( 0 );
2037 for( i = 0; i < p_box->data.p_elst->i_entry_count; i++ )
2039 if( p_box->data.p_elst->i_version == 1 )
2042 MP4_GET8BYTES( p_box->data.p_elst->i_segment_duration[i] );
2044 MP4_GET8BYTES( p_box->data.p_elst->i_media_time[i] );
2046 else
2049 MP4_GET4BYTES( p_box->data.p_elst->i_segment_duration[i] );
2051 MP4_GET4BYTES( p_box->data.p_elst->i_media_time[i] );
2052 p_box->data.p_elst->i_media_time[i] = (int32_t)p_box->data.p_elst->i_media_time[i];
2055 MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_integer[i] );
2056 MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_fraction[i] );
2059 #ifdef MP4_VERBOSE
2060 msg_Dbg( p_stream, "read box: \"elst\" entry-count %lu",
2061 (unsigned long)p_box->data.p_elst->i_entry_count );
2062 #endif
2063 MP4_READBOX_EXIT( 1 );
2066 static int MP4_ReadBox_cprt( stream_t *p_stream, MP4_Box_t *p_box )
2068 unsigned int i_language;
2069 unsigned int i;
2071 MP4_READBOX_ENTER( MP4_Box_data_cprt_t );
2073 MP4_GETVERSIONFLAGS( p_box->data.p_cprt );
2075 i_language = GetWBE( p_peek );
2076 for( i = 0; i < 3; i++ )
2078 p_box->data.p_cprt->i_language[i] =
2079 ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
2081 p_peek += 2; i_read -= 2;
2082 MP4_GETSTRINGZ( p_box->data.p_cprt->psz_notice );
2084 #ifdef MP4_VERBOSE
2085 msg_Dbg( p_stream, "read box: \"cprt\" language %c%c%c notice %s",
2086 p_box->data.p_cprt->i_language[0],
2087 p_box->data.p_cprt->i_language[1],
2088 p_box->data.p_cprt->i_language[2],
2089 p_box->data.p_cprt->psz_notice );
2091 #endif
2092 MP4_READBOX_EXIT( 1 );
2095 static void MP4_FreeBox_cprt( MP4_Box_t *p_box )
2097 FREENULL( p_box->data.p_cprt->psz_notice );
2101 static int MP4_ReadBox_dcom( stream_t *p_stream, MP4_Box_t *p_box )
2103 MP4_READBOX_ENTER( MP4_Box_data_dcom_t );
2105 MP4_GETFOURCC( p_box->data.p_dcom->i_algorithm );
2106 #ifdef MP4_VERBOSE
2107 msg_Dbg( p_stream,
2108 "read box: \"dcom\" compression algorithm : %4.4s",
2109 (char*)&p_box->data.p_dcom->i_algorithm );
2110 #endif
2111 MP4_READBOX_EXIT( 1 );
2114 static int MP4_ReadBox_cmvd( stream_t *p_stream, MP4_Box_t *p_box )
2116 MP4_READBOX_ENTER( MP4_Box_data_cmvd_t );
2118 MP4_GET4BYTES( p_box->data.p_cmvd->i_uncompressed_size );
2120 p_box->data.p_cmvd->i_compressed_size = i_read;
2122 if( !( p_box->data.p_cmvd->p_data = malloc( i_read ) ) )
2123 return( 1 );
2125 /* now copy compressed data */
2126 memcpy( p_box->data.p_cmvd->p_data,
2127 p_peek,
2128 i_read);
2130 p_box->data.p_cmvd->b_compressed = 1;
2132 #ifdef MP4_VERBOSE
2133 msg_Dbg( p_stream, "read box: \"cmvd\" compressed data size %d",
2134 p_box->data.p_cmvd->i_compressed_size );
2135 #endif
2137 MP4_READBOX_EXIT( 1 );
2139 static void MP4_FreeBox_cmvd( MP4_Box_t *p_box )
2141 FREENULL( p_box->data.p_cmvd->p_data );
2145 static int MP4_ReadBox_cmov( stream_t *p_stream, MP4_Box_t *p_box )
2147 MP4_Box_t *p_dcom;
2148 MP4_Box_t *p_cmvd;
2150 #ifdef HAVE_ZLIB_H
2151 stream_t *p_stream_memory;
2152 z_stream z_data;
2153 uint8_t *p_data;
2154 int i_result;
2155 #endif
2157 if( !( p_box->data.p_cmov = malloc( sizeof( MP4_Box_data_cmov_t ) ) ) )
2158 return 0;
2159 memset( p_box->data.p_cmov, 0, sizeof( MP4_Box_data_cmov_t ) );
2161 if( !p_box->p_father ||
2162 ( p_box->p_father->i_type != ATOM_moov &&
2163 p_box->p_father->i_type != ATOM_foov ) )
2165 msg_Warn( p_stream, "Read box: \"cmov\" box alone" );
2166 return 1;
2169 if( !MP4_ReadBoxContainer( p_stream, p_box ) )
2171 return 0;
2174 if( ( p_dcom = MP4_BoxGet( p_box, "dcom" ) ) == NULL ||
2175 ( p_cmvd = MP4_BoxGet( p_box, "cmvd" ) ) == NULL ||
2176 p_cmvd->data.p_cmvd->p_data == NULL )
2178 msg_Warn( p_stream, "read box: \"cmov\" incomplete" );
2179 return 0;
2182 if( p_dcom->data.p_dcom->i_algorithm != ATOM_zlib )
2184 msg_Dbg( p_stream, "read box: \"cmov\" compression algorithm : %4.4s "
2185 "not supported", (char*)&p_dcom->data.p_dcom->i_algorithm );
2186 return 0;
2189 #ifndef HAVE_ZLIB_H
2190 msg_Dbg( p_stream, "read box: \"cmov\" zlib unsupported" );
2191 return 0;
2193 #else
2194 /* decompress data */
2195 /* allocate a new buffer */
2196 if( !( p_data = malloc( p_cmvd->data.p_cmvd->i_uncompressed_size ) ) )
2197 return 0;
2198 /* init default structures */
2199 z_data.next_in = p_cmvd->data.p_cmvd->p_data;
2200 z_data.avail_in = p_cmvd->data.p_cmvd->i_compressed_size;
2201 z_data.next_out = p_data;
2202 z_data.avail_out = p_cmvd->data.p_cmvd->i_uncompressed_size;
2203 z_data.zalloc = (alloc_func)Z_NULL;
2204 z_data.zfree = (free_func)Z_NULL;
2205 z_data.opaque = (voidpf)Z_NULL;
2207 /* init zlib */
2208 if( inflateInit( &z_data ) != Z_OK )
2210 msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
2211 free( p_data );
2212 return 0;
2215 /* uncompress */
2216 i_result = inflate( &z_data, Z_NO_FLUSH );
2217 if( i_result != Z_OK && i_result != Z_STREAM_END )
2219 msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
2220 free( p_data );
2221 return 0;
2224 if( p_cmvd->data.p_cmvd->i_uncompressed_size != z_data.total_out )
2226 msg_Warn( p_stream, "read box: \"cmov\" uncompressing data size "
2227 "mismatch" );
2229 p_cmvd->data.p_cmvd->i_uncompressed_size = z_data.total_out;
2231 /* close zlib */
2232 if( inflateEnd( &z_data ) != Z_OK )
2234 msg_Warn( p_stream, "read box: \"cmov\" error while uncompressing "
2235 "data (ignored)" );
2238 free( p_cmvd->data.p_cmvd->p_data );
2239 p_cmvd->data.p_cmvd->p_data = p_data;
2240 p_cmvd->data.p_cmvd->b_compressed = 0;
2242 msg_Dbg( p_stream, "read box: \"cmov\" box successfully uncompressed" );
2244 /* now create a memory stream */
2245 p_stream_memory =
2246 stream_MemoryNew( VLC_OBJECT(p_stream), p_cmvd->data.p_cmvd->p_data,
2247 p_cmvd->data.p_cmvd->i_uncompressed_size, true );
2249 /* and read uncompressd moov */
2250 p_box->data.p_cmov->p_moov = MP4_ReadBox( p_stream_memory, NULL );
2252 stream_Delete( p_stream_memory );
2254 #ifdef MP4_VERBOSE
2255 msg_Dbg( p_stream, "read box: \"cmov\" compressed movie header completed");
2256 #endif
2258 return p_box->data.p_cmov->p_moov ? 1 : 0;
2259 #endif /* HAVE_ZLIB_H */
2262 static int MP4_ReadBox_rdrf( stream_t *p_stream, MP4_Box_t *p_box )
2264 uint32_t i_len;
2265 MP4_READBOX_ENTER( MP4_Box_data_rdrf_t );
2267 MP4_GETVERSIONFLAGS( p_box->data.p_rdrf );
2268 MP4_GETFOURCC( p_box->data.p_rdrf->i_ref_type );
2269 MP4_GET4BYTES( i_len );
2270 i_len++;
2272 if( i_len > 0 )
2274 uint32_t i;
2275 p_box->data.p_rdrf->psz_ref = malloc( i_len );
2276 if( p_box->data.p_rdrf->psz_ref == NULL )
2277 MP4_READBOX_EXIT( 0 );
2278 i_len--;
2280 for( i = 0; i < i_len; i++ )
2282 MP4_GET1BYTE( p_box->data.p_rdrf->psz_ref[i] );
2284 p_box->data.p_rdrf->psz_ref[i_len] = '\0';
2286 else
2288 p_box->data.p_rdrf->psz_ref = NULL;
2291 #ifdef MP4_VERBOSE
2292 msg_Dbg( p_stream,
2293 "read box: \"rdrf\" type:%4.4s ref %s",
2294 (char*)&p_box->data.p_rdrf->i_ref_type,
2295 p_box->data.p_rdrf->psz_ref );
2296 #endif
2297 MP4_READBOX_EXIT( 1 );
2300 static void MP4_FreeBox_rdrf( MP4_Box_t *p_box )
2302 FREENULL( p_box->data.p_rdrf->psz_ref );
2306 static int MP4_ReadBox_rmdr( stream_t *p_stream, MP4_Box_t *p_box )
2308 MP4_READBOX_ENTER( MP4_Box_data_rmdr_t );
2310 MP4_GETVERSIONFLAGS( p_box->data.p_rmdr );
2312 MP4_GET4BYTES( p_box->data.p_rmdr->i_rate );
2314 #ifdef MP4_VERBOSE
2315 msg_Dbg( p_stream,
2316 "read box: \"rmdr\" rate:%d",
2317 p_box->data.p_rmdr->i_rate );
2318 #endif
2319 MP4_READBOX_EXIT( 1 );
2322 static int MP4_ReadBox_rmqu( stream_t *p_stream, MP4_Box_t *p_box )
2324 MP4_READBOX_ENTER( MP4_Box_data_rmqu_t );
2326 MP4_GET4BYTES( p_box->data.p_rmqu->i_quality );
2328 #ifdef MP4_VERBOSE
2329 msg_Dbg( p_stream,
2330 "read box: \"rmqu\" quality:%d",
2331 p_box->data.p_rmqu->i_quality );
2332 #endif
2333 MP4_READBOX_EXIT( 1 );
2336 static int MP4_ReadBox_rmvc( stream_t *p_stream, MP4_Box_t *p_box )
2338 MP4_READBOX_ENTER( MP4_Box_data_rmvc_t );
2339 MP4_GETVERSIONFLAGS( p_box->data.p_rmvc );
2341 MP4_GETFOURCC( p_box->data.p_rmvc->i_gestaltType );
2342 MP4_GET4BYTES( p_box->data.p_rmvc->i_val1 );
2343 MP4_GET4BYTES( p_box->data.p_rmvc->i_val2 );
2344 MP4_GET2BYTES( p_box->data.p_rmvc->i_checkType );
2346 #ifdef MP4_VERBOSE
2347 msg_Dbg( p_stream,
2348 "read box: \"rmvc\" gestaltType:%4.4s val1:0x%x val2:0x%x checkType:0x%x",
2349 (char*)&p_box->data.p_rmvc->i_gestaltType,
2350 p_box->data.p_rmvc->i_val1,p_box->data.p_rmvc->i_val2,
2351 p_box->data.p_rmvc->i_checkType );
2352 #endif
2354 MP4_READBOX_EXIT( 1 );
2357 static int MP4_ReadBox_frma( stream_t *p_stream, MP4_Box_t *p_box )
2359 MP4_READBOX_ENTER( MP4_Box_data_frma_t );
2361 MP4_GETFOURCC( p_box->data.p_frma->i_type );
2363 #ifdef MP4_VERBOSE
2364 msg_Dbg( p_stream, "read box: \"frma\" i_type:%4.4s",
2365 (char *)&p_box->data.p_frma->i_type );
2366 #endif
2368 MP4_READBOX_EXIT( 1 );
2371 static int MP4_ReadBox_skcr( stream_t *p_stream, MP4_Box_t *p_box )
2373 MP4_READBOX_ENTER( MP4_Box_data_skcr_t );
2375 MP4_GET4BYTES( p_box->data.p_skcr->i_init );
2376 MP4_GET4BYTES( p_box->data.p_skcr->i_encr );
2377 MP4_GET4BYTES( p_box->data.p_skcr->i_decr );
2379 #ifdef MP4_VERBOSE
2380 msg_Dbg( p_stream, "read box: \"skcr\" i_init:%d i_encr:%d i_decr:%d",
2381 p_box->data.p_skcr->i_init,
2382 p_box->data.p_skcr->i_encr,
2383 p_box->data.p_skcr->i_decr );
2384 #endif
2386 MP4_READBOX_EXIT( 1 );
2389 static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box )
2391 MP4_Box_t *p_drms_box = p_box;
2392 void *p_drms = NULL;
2394 MP4_READBOX_ENTER( uint8_t );
2398 p_drms_box = p_drms_box->p_father;
2399 } while( p_drms_box && p_drms_box->i_type != ATOM_drms
2400 && p_drms_box->i_type != ATOM_drmi );
2402 if( p_drms_box && p_drms_box->i_type == ATOM_drms )
2403 p_drms = p_drms_box->data.p_sample_soun->p_drms;
2404 else if( p_drms_box && p_drms_box->i_type == ATOM_drmi )
2405 p_drms = p_drms_box->data.p_sample_vide->p_drms;
2407 if( p_drms_box && p_drms )
2409 int i_ret = drms_init( p_drms, p_box->i_type, p_peek, i_read );
2410 if( i_ret )
2412 const char *psz_error;
2414 switch( i_ret )
2416 case -1: psz_error = "unimplemented"; break;
2417 case -2: psz_error = "invalid argument"; break;
2418 case -3: psz_error = "could not get system key"; break;
2419 case -4: psz_error = "could not get SCI data"; break;
2420 case -5: psz_error = "no user key found in SCI data"; break;
2421 case -6: psz_error = "invalid user key"; break;
2422 default: psz_error = "unknown error"; break;
2424 if MP4_BOX_TYPE_ASCII()
2425 msg_Err( p_stream, "drms_init(%4.4s) failed (%s)",
2426 (char *)&p_box->i_type, psz_error );
2427 else
2428 msg_Err( p_stream, "drms_init(c%3.3s) failed (%s)",
2429 (char *)&p_box->i_type+1, psz_error );
2431 drms_free( p_drms );
2433 if( p_drms_box->i_type == ATOM_drms )
2434 p_drms_box->data.p_sample_soun->p_drms = NULL;
2435 else if( p_drms_box->i_type == ATOM_drmi )
2436 p_drms_box->data.p_sample_vide->p_drms = NULL;
2440 MP4_READBOX_EXIT( 1 );
2443 static int MP4_ReadBox_name( stream_t *p_stream, MP4_Box_t *p_box )
2445 MP4_READBOX_ENTER( MP4_Box_data_name_t );
2447 p_box->data.p_name->psz_text = malloc( p_box->i_size + 1 - 8 ); /* +\0, -name, -size */
2448 if( p_box->data.p_name->psz_text == NULL )
2449 MP4_READBOX_EXIT( 0 );
2451 memcpy( p_box->data.p_name->psz_text, p_peek, p_box->i_size - 8 );
2452 p_box->data.p_name->psz_text[p_box->i_size - 8] = '\0';
2454 #ifdef MP4_VERBOSE
2455 msg_Dbg( p_stream, "read box: \"name\" text=`%s'",
2456 p_box->data.p_name->psz_text );
2457 #endif
2458 MP4_READBOX_EXIT( 1 );
2461 static void MP4_FreeBox_name( MP4_Box_t *p_box )
2463 FREENULL( p_box->data.p_name->psz_text );
2466 static int MP4_ReadBox_0xa9xxx( stream_t *p_stream, MP4_Box_t *p_box )
2468 uint16_t i16;
2470 MP4_READBOX_ENTER( MP4_Box_data_0xa9xxx_t );
2472 p_box->data.p_0xa9xxx->psz_text = NULL;
2474 MP4_GET2BYTES( i16 );
2476 if( i16 > 0 )
2478 int i_length = i16;
2480 MP4_GET2BYTES( i16 );
2481 if( i_length >= i_read ) i_length = i_read + 1;
2483 p_box->data.p_0xa9xxx->psz_text = malloc( i_length );
2484 if( p_box->data.p_0xa9xxx->psz_text == NULL )
2485 MP4_READBOX_EXIT( 0 );
2487 i_length--;
2488 memcpy( p_box->data.p_0xa9xxx->psz_text,
2489 p_peek, i_length );
2490 p_box->data.p_0xa9xxx->psz_text[i_length] = '\0';
2492 #ifdef MP4_VERBOSE
2493 msg_Dbg( p_stream,
2494 "read box: \"c%3.3s\" text=`%s'",
2495 ((char*)&p_box->i_type + 1),
2496 p_box->data.p_0xa9xxx->psz_text );
2497 #endif
2499 else
2501 /* try iTune/Quicktime format, rewind to start */
2502 p_peek -= 2; i_read += 2;
2503 // we are expecting a 'data' box
2504 uint32_t i_data_len;
2505 uint32_t i_data_tag;
2507 MP4_GET4BYTES( i_data_len );
2508 if( i_data_len > i_read ) i_data_len = i_read;
2509 MP4_GETFOURCC( i_data_tag );
2510 if( (i_data_len > 0) && (i_data_tag == ATOM_data) )
2512 /* data box contains a version/flags field */
2513 uint32_t i_version;
2514 uint32_t i_reserved;
2515 MP4_GET4BYTES( i_version );
2516 MP4_GET4BYTES( i_reserved );
2517 // version should be 0, flags should be 1 for text, 0 for data
2518 if( ( i_version == 0x00000001 ) && (i_data_len >= 12 ) )
2520 // the rest is the text
2521 i_data_len -= 12;
2522 p_box->data.p_0xa9xxx->psz_text = malloc( i_data_len + 1 );
2523 if( p_box->data.p_0xa9xxx->psz_text == NULL )
2524 MP4_READBOX_EXIT( 0 );
2526 memcpy( p_box->data.p_0xa9xxx->psz_text,
2527 p_peek, i_data_len );
2528 p_box->data.p_0xa9xxx->psz_text[i_data_len] = '\0';
2529 #ifdef MP4_VERBOSE
2530 msg_Dbg( p_stream,
2531 "read box: \"c%3.3s\" text=`%s'",
2532 ((char*)&p_box->i_type+1),
2533 p_box->data.p_0xa9xxx->psz_text );
2534 #endif
2536 else
2538 // TODO: handle data values for ID3 tag values, track num or cover art,etc...
2543 MP4_READBOX_EXIT( 1 );
2545 static void MP4_FreeBox_0xa9xxx( MP4_Box_t *p_box )
2547 FREENULL( p_box->data.p_0xa9xxx->psz_text );
2550 /* Chapter support */
2551 static void MP4_FreeBox_chpl( MP4_Box_t *p_box )
2553 MP4_Box_data_chpl_t *p_chpl = p_box->data.p_chpl;
2554 int i;
2555 for( i = 0; i < p_chpl->i_chapter; i++ )
2556 free( p_chpl->chapter[i].psz_name );
2559 static int MP4_ReadBox_chpl( stream_t *p_stream, MP4_Box_t *p_box )
2561 MP4_Box_data_chpl_t *p_chpl;
2562 uint32_t i_dummy;
2563 int i;
2564 MP4_READBOX_ENTER( MP4_Box_data_chpl_t );
2566 p_chpl = p_box->data.p_chpl;
2568 MP4_GETVERSIONFLAGS( p_chpl );
2570 MP4_GET4BYTES( i_dummy );
2572 MP4_GET1BYTE( p_chpl->i_chapter );
2574 for( i = 0; i < p_chpl->i_chapter; i++ )
2576 uint64_t i_start;
2577 uint8_t i_len;
2578 int i_copy;
2579 MP4_GET8BYTES( i_start );
2580 MP4_GET1BYTE( i_len );
2582 p_chpl->chapter[i].psz_name = malloc( i_len + 1 );
2583 if( !p_chpl->chapter[i].psz_name )
2584 goto error;
2586 i_copy = __MIN( i_len, i_read );
2587 if( i_copy > 0 )
2588 memcpy( p_chpl->chapter[i].psz_name, p_peek, i_copy );
2589 p_chpl->chapter[i].psz_name[i_copy] = '\0';
2590 p_chpl->chapter[i].i_start = i_start;
2592 p_peek += i_copy;
2593 i_read -= i_copy;
2595 /* Bubble sort by increasing start date */
2598 for( i = 0; i < p_chpl->i_chapter - 1; i++ )
2600 if( p_chpl->chapter[i].i_start > p_chpl->chapter[i+1].i_start )
2602 char *psz = p_chpl->chapter[i+1].psz_name;
2603 int64_t i64 = p_chpl->chapter[i+1].i_start;
2605 p_chpl->chapter[i+1].psz_name = p_chpl->chapter[i].psz_name;
2606 p_chpl->chapter[i+1].i_start = p_chpl->chapter[i].i_start;
2608 p_chpl->chapter[i].psz_name = psz;
2609 p_chpl->chapter[i].i_start = i64;
2611 i = -1;
2612 break;
2615 } while( i == -1 );
2617 #ifdef MP4_VERBOSE
2618 msg_Dbg( p_stream, "read box: \"chpl\" %d chapters",
2619 p_chpl->i_chapter );
2620 #endif
2621 MP4_READBOX_EXIT( 1 );
2623 error:
2624 MP4_READBOX_EXIT( 0 );
2627 static int MP4_ReadBox_tref_generic( stream_t *p_stream, MP4_Box_t *p_box )
2629 unsigned int i;
2630 MP4_READBOX_ENTER( MP4_Box_data_tref_generic_t );
2632 p_box->data.p_tref_generic->i_track_ID = NULL;
2633 p_box->data.p_tref_generic->i_entry_count = i_read / sizeof(uint32_t);
2634 if( p_box->data.p_tref_generic->i_entry_count > 0 )
2635 p_box->data.p_tref_generic->i_track_ID = calloc( p_box->data.p_tref_generic->i_entry_count, sizeof(uint32_t) );
2636 if( p_box->data.p_tref_generic->i_track_ID == NULL )
2637 MP4_READBOX_EXIT( 0 );
2639 for( i = 0; i < p_box->data.p_tref_generic->i_entry_count; i++ )
2641 MP4_GET4BYTES( p_box->data.p_tref_generic->i_track_ID[i] );
2643 #ifdef MP4_VERBOSE
2644 msg_Dbg( p_stream, "read box: \"chap\" %d references",
2645 p_box->data.p_tref_generic->i_entry_count );
2646 #endif
2648 MP4_READBOX_EXIT( 1 );
2650 static void MP4_FreeBox_tref_generic( MP4_Box_t *p_box )
2652 FREENULL( p_box->data.p_tref_generic->i_track_ID );
2655 static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
2657 uint8_t meta_data[8];
2658 int i_actually_read;
2660 // skip over box header
2661 i_actually_read = stream_Read( p_stream, meta_data, 8 );
2662 if( i_actually_read < 8 )
2663 return 0;
2665 /* meta content starts with a 4 byte version/flags value (should be 0) */
2666 i_actually_read = stream_Read( p_stream, meta_data, 4 );
2667 if( i_actually_read < 4 )
2668 return 0;
2670 /* then it behaves like a container */
2671 return MP4_ReadBoxContainerRaw( p_stream, p_box );
2674 static int MP4_ReadBox_iods( stream_t *p_stream, MP4_Box_t *p_box )
2676 char i_unused;
2678 MP4_READBOX_ENTER( MP4_Box_data_iods_t );
2679 MP4_GETVERSIONFLAGS( p_box->data.p_iods );
2681 MP4_GET1BYTE( i_unused ); /* tag */
2682 MP4_GET1BYTE( i_unused ); /* length */
2684 MP4_GET2BYTES( p_box->data.p_iods->i_object_descriptor ); /* 10bits, 6 other bits
2685 are used for other flags */
2686 MP4_GET1BYTE( p_box->data.p_iods->i_OD_profile_level );
2687 MP4_GET1BYTE( p_box->data.p_iods->i_scene_profile_level );
2688 MP4_GET1BYTE( p_box->data.p_iods->i_audio_profile_level );
2689 MP4_GET1BYTE( p_box->data.p_iods->i_visual_profile_level );
2690 MP4_GET1BYTE( p_box->data.p_iods->i_graphics_profile_level );
2692 #ifdef MP4_VERBOSE
2693 msg_Dbg( p_stream,
2694 "read box: \"iods\" objectDescriptorId: %i, OD: %i, scene: %i, audio: %i, "
2695 "visual: %i, graphics: %i",
2696 p_box->data.p_iods->i_object_descriptor >> 6,
2697 p_box->data.p_iods->i_OD_profile_level,
2698 p_box->data.p_iods->i_scene_profile_level,
2699 p_box->data.p_iods->i_audio_profile_level,
2700 p_box->data.p_iods->i_visual_profile_level,
2701 p_box->data.p_iods->i_graphics_profile_level );
2702 #endif
2704 MP4_READBOX_EXIT( 1 );
2707 static int MP4_ReadBox_pasp( stream_t *p_stream, MP4_Box_t *p_box )
2709 MP4_READBOX_ENTER( MP4_Box_data_pasp_t );
2711 MP4_GET4BYTES( p_box->data.p_pasp->i_horizontal_spacing );
2712 MP4_GET4BYTES( p_box->data.p_pasp->i_vertical_spacing );
2714 #ifdef MP4_VERBOSE
2715 msg_Dbg( p_stream,
2716 "read box: \"paps\" %dx%d",
2717 p_box->data.p_pasp->i_horizontal_spacing,
2718 p_box->data.p_pasp->i_vertical_spacing);
2719 #endif
2721 MP4_READBOX_EXIT( 1 );
2725 /* For generic */
2726 static int MP4_ReadBox_default( stream_t *p_stream, MP4_Box_t *p_box )
2728 if( !p_box->p_father )
2730 goto unknown;
2732 if( p_box->p_father->i_type == ATOM_stsd )
2734 MP4_Box_t *p_mdia = MP4_BoxGet( p_box, "../../../.." );
2735 MP4_Box_t *p_hdlr;
2737 if( p_mdia == NULL || p_mdia->i_type != ATOM_mdia ||
2738 (p_hdlr = MP4_BoxGet( p_mdia, "hdlr" )) == NULL )
2740 goto unknown;
2742 switch( p_hdlr->data.p_hdlr->i_handler_type )
2744 case ATOM_soun:
2745 return MP4_ReadBox_sample_soun( p_stream, p_box );
2746 case ATOM_vide:
2747 return MP4_ReadBox_sample_vide( p_stream, p_box );
2748 case ATOM_text:
2749 return MP4_ReadBox_sample_text( p_stream, p_box );
2750 case ATOM_tx3g:
2751 case ATOM_sbtl:
2752 return MP4_ReadBox_sample_tx3g( p_stream, p_box );
2753 default:
2754 msg_Warn( p_stream,
2755 "unknown handler type in stsd (incompletely loaded)" );
2756 return 1;
2760 unknown:
2761 if MP4_BOX_TYPE_ASCII()
2762 msg_Warn( p_stream,
2763 "unknown box type %4.4s (incompletely loaded)",
2764 (char*)&p_box->i_type );
2765 else
2766 msg_Warn( p_stream,
2767 "unknown box type c%3.3s (incompletely loaded)",
2768 (char*)&p_box->i_type+1 );
2770 return 1;
2773 /**** ------------------------------------------------------------------- ****/
2774 /**** "Higher level" Functions ****/
2775 /**** ------------------------------------------------------------------- ****/
2777 static const struct
2779 uint32_t i_type;
2780 int (*MP4_ReadBox_function )( stream_t *p_stream, MP4_Box_t *p_box );
2781 void (*MP4_FreeBox_function )( MP4_Box_t *p_box );
2782 } MP4_Box_Function [] =
2784 /* Containers */
2785 { ATOM_moov, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2786 { ATOM_trak, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2787 { ATOM_mdia, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2788 { ATOM_moof, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2789 { ATOM_minf, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2790 { ATOM_stbl, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2791 { ATOM_dinf, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2792 { ATOM_edts, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2793 { ATOM_udta, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2794 { ATOM_nmhd, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2795 { ATOM_hnti, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2796 { ATOM_rmra, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2797 { ATOM_rmda, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2798 { ATOM_tref, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2799 { ATOM_gmhd, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2800 { ATOM_wave, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2801 { ATOM_ilst, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2803 /* specific box */
2804 { ATOM_ftyp, MP4_ReadBox_ftyp, MP4_FreeBox_ftyp },
2805 { ATOM_cmov, MP4_ReadBox_cmov, MP4_FreeBox_Common },
2806 { ATOM_mvhd, MP4_ReadBox_mvhd, MP4_FreeBox_Common },
2807 { ATOM_tkhd, MP4_ReadBox_tkhd, MP4_FreeBox_Common },
2808 { ATOM_mdhd, MP4_ReadBox_mdhd, MP4_FreeBox_Common },
2809 { ATOM_hdlr, MP4_ReadBox_hdlr, MP4_FreeBox_hdlr },
2810 { ATOM_vmhd, MP4_ReadBox_vmhd, MP4_FreeBox_Common },
2811 { ATOM_smhd, MP4_ReadBox_smhd, MP4_FreeBox_Common },
2812 { ATOM_hmhd, MP4_ReadBox_hmhd, MP4_FreeBox_Common },
2813 { ATOM_url, MP4_ReadBox_url, MP4_FreeBox_url },
2814 { ATOM_urn, MP4_ReadBox_urn, MP4_FreeBox_urn },
2815 { ATOM_dref, MP4_ReadBox_dref, MP4_FreeBox_Common },
2816 { ATOM_stts, MP4_ReadBox_stts, MP4_FreeBox_stts },
2817 { ATOM_ctts, MP4_ReadBox_ctts, MP4_FreeBox_ctts },
2818 { ATOM_stsd, MP4_ReadBox_stsd, MP4_FreeBox_Common },
2819 { ATOM_stsz, MP4_ReadBox_stsz, MP4_FreeBox_stsz },
2820 { ATOM_stsc, MP4_ReadBox_stsc, MP4_FreeBox_stsc },
2821 { ATOM_stco, MP4_ReadBox_stco_co64, MP4_FreeBox_stco_co64 },
2822 { ATOM_co64, MP4_ReadBox_stco_co64, MP4_FreeBox_stco_co64 },
2823 { ATOM_stss, MP4_ReadBox_stss, MP4_FreeBox_stss },
2824 { ATOM_stsh, MP4_ReadBox_stsh, MP4_FreeBox_stsh },
2825 { ATOM_stdp, MP4_ReadBox_stdp, MP4_FreeBox_stdp },
2826 { ATOM_padb, MP4_ReadBox_padb, MP4_FreeBox_padb },
2827 { ATOM_elst, MP4_ReadBox_elst, MP4_FreeBox_elst },
2828 { ATOM_cprt, MP4_ReadBox_cprt, MP4_FreeBox_cprt },
2829 { ATOM_esds, MP4_ReadBox_esds, MP4_FreeBox_esds },
2830 { ATOM_dcom, MP4_ReadBox_dcom, MP4_FreeBox_Common },
2831 { ATOM_cmvd, MP4_ReadBox_cmvd, MP4_FreeBox_cmvd },
2832 { ATOM_avcC, MP4_ReadBox_avcC, MP4_FreeBox_avcC },
2833 { ATOM_dac3, MP4_ReadBox_dac3, MP4_FreeBox_Common },
2834 { ATOM_enda, MP4_ReadBox_enda, MP4_FreeBox_Common },
2835 { ATOM_gnre, MP4_ReadBox_gnre, MP4_FreeBox_Common },
2836 { ATOM_trkn, MP4_ReadBox_trkn, MP4_FreeBox_Common },
2837 { ATOM_iods, MP4_ReadBox_iods, MP4_FreeBox_Common },
2838 { ATOM_pasp, MP4_ReadBox_pasp, MP4_FreeBox_Common },
2840 /* Nothing to do with this box */
2841 { ATOM_mdat, MP4_ReadBoxSkip, MP4_FreeBox_Common },
2842 { ATOM_skip, MP4_ReadBoxSkip, MP4_FreeBox_Common },
2843 { ATOM_free, MP4_ReadBoxSkip, MP4_FreeBox_Common },
2844 { ATOM_wide, MP4_ReadBoxSkip, MP4_FreeBox_Common },
2846 /* for codecs */
2847 { ATOM_soun, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2848 { ATOM_ms02, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2849 { ATOM_ms11, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2850 { ATOM_ms55, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2851 { ATOM__mp3, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2852 { ATOM_mp4a, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2853 { ATOM_twos, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2854 { ATOM_sowt, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2855 { ATOM_QDMC, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2856 { ATOM_QDM2, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2857 { ATOM_ima4, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2858 { ATOM_IMA4, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2859 { ATOM_dvi, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2860 { ATOM_alaw, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2861 { ATOM_ulaw, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2862 { ATOM_raw, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2863 { ATOM_MAC3, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2864 { ATOM_MAC6, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2865 { ATOM_Qclp, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2866 { ATOM_samr, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2867 { ATOM_sawb, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2868 { ATOM_OggS, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2869 { ATOM_alac, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2871 { ATOM_drmi, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2872 { ATOM_vide, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2873 { ATOM_mp4v, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2874 { ATOM_SVQ1, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2875 { ATOM_SVQ3, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2876 { ATOM_ZyGo, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2877 { ATOM_DIVX, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2878 { ATOM_XVID, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2879 { ATOM_h263, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2880 { ATOM_s263, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2881 { ATOM_cvid, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2882 { ATOM_3IV1, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2883 { ATOM_3iv1, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2884 { ATOM_3IV2, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2885 { ATOM_3iv2, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2886 { ATOM_3IVD, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2887 { ATOM_3ivd, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2888 { ATOM_3VID, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2889 { ATOM_3vid, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2890 { ATOM_mjpa, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2891 { ATOM_mjpb, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2892 { ATOM_qdrw, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2893 { ATOM_mp2v, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2894 { ATOM_hdv2, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2896 { ATOM_mjqt, MP4_ReadBox_default, NULL }, /* found in mjpa/b */
2897 { ATOM_mjht, MP4_ReadBox_default, NULL },
2899 { ATOM_dvc, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2900 { ATOM_dvp, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2901 { ATOM_dv5n, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2902 { ATOM_dv5p, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2903 { ATOM_VP31, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2904 { ATOM_vp31, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2905 { ATOM_h264, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2907 { ATOM_jpeg, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2908 { ATOM_avc1, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2910 { ATOM_yv12, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2911 { ATOM_yuv2, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
2913 { ATOM_mp4s, MP4_ReadBox_sample_mp4s, MP4_FreeBox_Common },
2915 /* XXX there is 2 box where we could find this entry stbl and tref*/
2916 { ATOM_hint, MP4_ReadBox_default, MP4_FreeBox_Common },
2918 /* found in tref box */
2919 { ATOM_dpnd, MP4_ReadBox_default, NULL },
2920 { ATOM_ipir, MP4_ReadBox_default, NULL },
2921 { ATOM_mpod, MP4_ReadBox_default, NULL },
2922 { ATOM_chap, MP4_ReadBox_tref_generic, MP4_FreeBox_tref_generic },
2924 /* found in hnti */
2925 { ATOM_rtp, MP4_ReadBox_default, NULL },
2927 /* found in rmra */
2928 { ATOM_rdrf, MP4_ReadBox_rdrf, MP4_FreeBox_rdrf },
2929 { ATOM_rmdr, MP4_ReadBox_rmdr, MP4_FreeBox_Common },
2930 { ATOM_rmqu, MP4_ReadBox_rmqu, MP4_FreeBox_Common },
2931 { ATOM_rmvc, MP4_ReadBox_rmvc, MP4_FreeBox_Common },
2933 { ATOM_drms, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
2934 { ATOM_sinf, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2935 { ATOM_schi, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2936 { ATOM_user, MP4_ReadBox_drms, MP4_FreeBox_Common },
2937 { ATOM_key, MP4_ReadBox_drms, MP4_FreeBox_Common },
2938 { ATOM_iviv, MP4_ReadBox_drms, MP4_FreeBox_Common },
2939 { ATOM_priv, MP4_ReadBox_drms, MP4_FreeBox_Common },
2940 { ATOM_frma, MP4_ReadBox_frma, MP4_FreeBox_Common },
2941 { ATOM_skcr, MP4_ReadBox_skcr, MP4_FreeBox_Common },
2943 /* found in udta */
2944 { ATOM_0xa9nam, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2945 { ATOM_0xa9aut, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2946 { ATOM_0xa9cpy, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2947 { ATOM_0xa9swr, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2948 { ATOM_0xa9inf, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2949 { ATOM_0xa9ART, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2950 { ATOM_0xa9dir, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2951 { ATOM_0xa9cmt, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2952 { ATOM_0xa9req, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2953 { ATOM_0xa9day, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2954 { ATOM_0xa9des, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2955 { ATOM_0xa9fmt, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2956 { ATOM_0xa9prd, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2957 { ATOM_0xa9prf, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2958 { ATOM_0xa9src, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2959 { ATOM_0xa9alb, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2960 { ATOM_0xa9dis, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2961 { ATOM_0xa9enc, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2962 { ATOM_0xa9gen, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2963 { ATOM_0xa9trk, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2964 { ATOM_0xa9dsa, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2965 { ATOM_0xa9hst, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2966 { ATOM_0xa9url, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2967 { ATOM_0xa9ope, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2968 { ATOM_0xa9com, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2969 { ATOM_0xa9wrt, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2970 { ATOM_0xa9too, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2971 { ATOM_0xa9wrn, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2972 { ATOM_0xa9mak, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2973 { ATOM_0xa9mod, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2974 { ATOM_0xa9PRD, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2975 { ATOM_0xa9grp, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2976 { ATOM_0xa9lyr, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
2978 { ATOM_chpl, MP4_ReadBox_chpl, MP4_FreeBox_chpl },
2980 /* iTunes/Quicktime meta info */
2981 { ATOM_meta, MP4_ReadBox_meta, MP4_FreeBox_Common },
2982 { ATOM_name, MP4_ReadBox_name, MP4_FreeBox_name },
2984 /* found in smoothstreaming */
2985 { ATOM_traf, MP4_ReadBoxContainer, MP4_FreeBox_Common },
2986 { ATOM_mfhd, MP4_ReadBox_mfhd, MP4_FreeBox_Common },
2987 { ATOM_tfhd, MP4_ReadBox_tfhd, MP4_FreeBox_Common },
2988 { ATOM_trun, MP4_ReadBox_trun, MP4_FreeBox_trun },
2990 /* Last entry */
2991 { 0, MP4_ReadBox_default, NULL }
2995 /*****************************************************************************
2996 * MP4_ReadBox : parse the actual box and the children
2997 * XXX : Do not go to the next box
2998 *****************************************************************************/
2999 static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father )
3001 MP4_Box_t *p_box = calloc( 1, sizeof( MP4_Box_t ) ); /* Needed to ensure simple on error handler */
3002 unsigned int i_index;
3004 if( p_box == NULL )
3005 return NULL;
3007 if( !MP4_ReadBoxCommon( p_stream, p_box ) )
3009 msg_Warn( p_stream, "cannot read one box" );
3010 free( p_box );
3011 return NULL;
3013 if( !p_box->i_size )
3015 msg_Dbg( p_stream, "found an empty box (null size)" );
3016 free( p_box );
3017 return NULL;
3019 p_box->p_father = p_father;
3021 /* Now search function to call */
3022 for( i_index = 0; ; i_index++ )
3024 if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
3025 ( MP4_Box_Function[i_index].i_type == 0 ) )
3027 break;
3031 if( !(MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box ) )
3033 MP4_BoxFree( p_stream, p_box );
3034 return NULL;
3037 return p_box;
3040 /*****************************************************************************
3041 * MP4_FreeBox : free memory after read with MP4_ReadBox and all
3042 * the children
3043 *****************************************************************************/
3044 void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
3046 unsigned int i_index;
3047 MP4_Box_t *p_child;
3049 if( !p_box )
3050 return; /* hehe */
3052 for( p_child = p_box->p_first; p_child != NULL; )
3054 MP4_Box_t *p_next;
3056 p_next = p_child->p_next;
3057 MP4_BoxFree( s, p_child );
3058 p_child = p_next;
3061 /* Now search function to call */
3062 if( p_box->data.p_data )
3064 for( i_index = 0; ; i_index++ )
3066 if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
3067 ( MP4_Box_Function[i_index].i_type == 0 ) )
3069 break;
3072 if( MP4_Box_Function[i_index].MP4_FreeBox_function == NULL )
3074 /* Should not happen */
3075 if MP4_BOX_TYPE_ASCII()
3076 msg_Warn( s,
3077 "cannot free box %4.4s, type unknown",
3078 (char*)&p_box->i_type );
3079 else
3080 msg_Warn( s,
3081 "cannot free box c%3.3s, type unknown",
3082 (char*)&p_box->i_type+1 );
3084 else
3086 MP4_Box_Function[i_index].MP4_FreeBox_function( p_box );
3088 free( p_box->data.p_data );
3090 free( p_box );
3093 /*****************************************************************************
3094 * MP4_BoxGetRoot : Parse the entire file, and create all boxes in memory
3095 *****************************************************************************
3096 * The first box is a virtual box "root" and is the father for all first
3097 * level boxes for the file, a sort of virtual contener
3098 *****************************************************************************/
3099 MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
3101 MP4_Box_t *p_root;
3102 stream_t *p_stream;
3103 int i_result;
3105 p_root = malloc( sizeof( MP4_Box_t ) );
3106 if( p_root == NULL )
3107 return NULL;
3109 p_root->i_pos = 0;
3110 p_root->i_type = ATOM_root;
3111 p_root->i_shortsize = 1;
3112 p_root->i_size = stream_Size( s );
3113 CreateUUID( &p_root->i_uuid, p_root->i_type );
3115 p_root->data.p_data = NULL;
3116 p_root->p_father = NULL;
3117 p_root->p_first = NULL;
3118 p_root->p_last = NULL;
3119 p_root->p_next = NULL;
3121 p_stream = s;
3123 i_result = MP4_ReadBoxContainerRaw( p_stream, p_root );
3125 if( i_result )
3127 MP4_Box_t *p_moov;
3128 MP4_Box_t *p_cmov;
3130 /* check if there is a cmov, if so replace
3131 compressed moov by uncompressed one */
3132 if( ( ( p_moov = MP4_BoxGet( p_root, "moov" ) ) &&
3133 ( p_cmov = MP4_BoxGet( p_root, "moov/cmov" ) ) ) ||
3134 ( ( p_moov = MP4_BoxGet( p_root, "foov" ) ) &&
3135 ( p_cmov = MP4_BoxGet( p_root, "foov/cmov" ) ) ) )
3137 /* rename the compressed moov as a box to skip */
3138 p_moov->i_type = ATOM_skip;
3140 /* get uncompressed p_moov */
3141 p_moov = p_cmov->data.p_cmov->p_moov;
3142 p_cmov->data.p_cmov->p_moov = NULL;
3144 /* make p_root father of this new moov */
3145 p_moov->p_father = p_root;
3147 /* insert this new moov box as first child of p_root */
3148 p_moov->p_next = p_root->p_first;
3149 p_root->p_first = p_moov;
3153 return p_root;
3157 static void MP4_BoxDumpStructure_Internal( stream_t *s,
3158 MP4_Box_t *p_box, unsigned int i_level )
3160 MP4_Box_t *p_child;
3162 if( !i_level )
3164 if MP4_BOX_TYPE_ASCII()
3165 msg_Dbg( s, "dumping root Box \"%4.4s\"",
3166 (char*)&p_box->i_type );
3167 else
3168 msg_Dbg( s, "dumping root Box \"c%3.3s\"",
3169 (char*)&p_box->i_type+1 );
3171 else
3173 unsigned int i;
3175 char str[512];
3176 if( i_level >= (sizeof(str) - 1)/4 )
3177 return;
3179 memset( str, ' ', sizeof(str) );
3180 for( i = 0; i < i_level; i++ )
3182 str[i*4] = '|';
3184 if( MP4_BOX_TYPE_ASCII() )
3185 snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
3186 "+ %4.4s size %d",
3187 (char*)&p_box->i_type, (uint32_t)p_box->i_size );
3188 else
3189 snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
3190 "+ c%3.3s size %d",
3191 (char*)&p_box->i_type+1, (uint32_t)p_box->i_size );
3192 msg_Dbg( s, "%s", str );
3194 p_child = p_box->p_first;
3195 while( p_child )
3197 MP4_BoxDumpStructure_Internal( s, p_child, i_level + 1 );
3198 p_child = p_child->p_next;
3202 void MP4_BoxDumpStructure( stream_t *s, MP4_Box_t *p_box )
3204 MP4_BoxDumpStructure_Internal( s, p_box, 0 );
3208 /*****************************************************************************
3209 *****************************************************************************
3211 ** High level methods to acces an MP4 file
3213 *****************************************************************************
3214 *****************************************************************************/
3215 static void get_token( char **ppsz_path, char **ppsz_token, int *pi_number )
3217 size_t i_len ;
3218 if( !*ppsz_path[0] )
3220 *ppsz_token = NULL;
3221 *pi_number = 0;
3222 return;
3224 i_len = strcspn( *ppsz_path, "/[" );
3225 if( !i_len && **ppsz_path == '/' )
3227 i_len = 1;
3229 *ppsz_token = xmalloc( i_len + 1 );
3231 memcpy( *ppsz_token, *ppsz_path, i_len );
3233 (*ppsz_token)[i_len] = '\0';
3235 *ppsz_path += i_len;
3237 if( **ppsz_path == '[' )
3239 (*ppsz_path)++;
3240 *pi_number = strtol( *ppsz_path, NULL, 10 );
3241 while( **ppsz_path && **ppsz_path != ']' )
3243 (*ppsz_path)++;
3245 if( **ppsz_path == ']' )
3247 (*ppsz_path)++;
3250 else
3252 *pi_number = 0;
3254 while( **ppsz_path == '/' )
3256 (*ppsz_path)++;
3260 static void MP4_BoxGet_Internal( MP4_Box_t **pp_result,
3261 MP4_Box_t *p_box, const char *psz_fmt, va_list args)
3263 char *psz_dup;
3264 char *psz_path;
3265 char *psz_token;
3267 if( !p_box )
3269 *pp_result = NULL;
3270 return;
3273 if( vasprintf( &psz_path, psz_fmt, args ) == -1 )
3274 psz_path = NULL;
3276 if( !psz_path || !psz_path[0] )
3278 free( psz_path );
3279 *pp_result = NULL;
3280 return;
3283 // fprintf( stderr, "path:'%s'\n", psz_path );
3284 psz_dup = psz_path; /* keep this pointer, as it need to be unallocated */
3285 for( ; ; )
3287 int i_number;
3289 get_token( &psz_path, &psz_token, &i_number );
3290 // fprintf( stderr, "path:'%s', token:'%s' n:%d\n",
3291 // psz_path,psz_token,i_number );
3292 if( !psz_token )
3294 free( psz_dup );
3295 *pp_result = p_box;
3296 return;
3298 else
3299 if( !strcmp( psz_token, "/" ) )
3301 /* Find root box */
3302 while( p_box && p_box->i_type != ATOM_root )
3304 p_box = p_box->p_father;
3306 if( !p_box )
3308 goto error_box;
3311 else
3312 if( !strcmp( psz_token, "." ) )
3314 /* Do nothing */
3316 else
3317 if( !strcmp( psz_token, ".." ) )
3319 p_box = p_box->p_father;
3320 if( !p_box )
3322 goto error_box;
3325 else
3326 if( strlen( psz_token ) == 4 )
3328 uint32_t i_fourcc;
3329 i_fourcc = VLC_FOURCC( psz_token[0], psz_token[1],
3330 psz_token[2], psz_token[3] );
3331 p_box = p_box->p_first;
3332 for( ; ; )
3334 if( !p_box )
3336 goto error_box;
3338 if( p_box->i_type == i_fourcc )
3340 if( !i_number )
3342 break;
3344 i_number--;
3346 p_box = p_box->p_next;
3349 else
3350 if( *psz_token == '\0' )
3352 p_box = p_box->p_first;
3353 for( ; ; )
3355 if( !p_box )
3357 goto error_box;
3359 if( !i_number )
3361 break;
3363 i_number--;
3364 p_box = p_box->p_next;
3367 else
3369 // fprintf( stderr, "Argg malformed token \"%s\"",psz_token );
3370 goto error_box;
3373 FREENULL( psz_token );
3376 return;
3378 error_box:
3379 free( psz_token );
3380 free( psz_dup );
3381 *pp_result = NULL;
3382 return;
3385 /*****************************************************************************
3386 * MP4_BoxGet: find a box given a path relative to p_box
3387 *****************************************************************************
3388 * Path Format: . .. / as usual
3389 * [number] to specifie box number ex: trak[12]
3391 * ex: /moov/trak[12]
3392 * ../mdia
3393 *****************************************************************************/
3394 MP4_Box_t *MP4_BoxGet( MP4_Box_t *p_box, const char *psz_fmt, ... )
3396 va_list args;
3397 MP4_Box_t *p_result;
3399 va_start( args, psz_fmt );
3400 MP4_BoxGet_Internal( &p_result, p_box, psz_fmt, args );
3401 va_end( args );
3403 return( p_result );
3406 /*****************************************************************************
3407 * MP4_BoxCount: count box given a path relative to p_box
3408 *****************************************************************************
3409 * Path Format: . .. / as usual
3410 * [number] to specifie box number ex: trak[12]
3412 * ex: /moov/trak[12]
3413 * ../mdia
3414 *****************************************************************************/
3415 int MP4_BoxCount( MP4_Box_t *p_box, const char *psz_fmt, ... )
3417 va_list args;
3418 int i_count;
3419 MP4_Box_t *p_result, *p_next;
3421 va_start( args, psz_fmt );
3422 MP4_BoxGet_Internal( &p_result, p_box, psz_fmt, args );
3423 va_end( args );
3424 if( !p_result )
3426 return( 0 );
3429 i_count = 1;
3430 for( p_next = p_result->p_next; p_next != NULL; p_next = p_next->p_next)
3432 if( p_next->i_type == p_result->i_type)
3434 i_count++;
3437 return( i_count );