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 *****************************************************************************/
27 #include <vlc_common.h>
28 #include <vlc_stream.h> /* stream_Peek*/
31 # include <zlib.h> /* for compressed moov */
38 * The input method HAS to be seekable
41 /* convert 16.16 fixed point to floating point */
42 static double conv_fx( int32_t fx ) {
48 /* some functions for mp4 encoding of variables */
50 static void MP4_ConvertDate2Str( char *psz, uint64_t i_date )
57 /* date begin at 1 jan 1904 */
58 i_date += ((INT64_C(1904) * 365) + 17) * 24 * 60 * 60;
60 i_day = i_date / ( 60*60*24);
61 i_hour = ( i_date /( 60*60 ) ) % 60;
62 i_min = ( i_date / 60 ) % 60;
64 sprintf( psz, "%dd-%2.2dh:%2.2dm:%2.2ds", i_day, i_hour, i_min, i_sec );
68 /*****************************************************************************
70 *****************************************************************************/
71 static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father );
74 /*****************************************************************************
75 * MP4_ReadBoxCommon : Load only common parameters for all boxes
76 *****************************************************************************
77 * p_box need to be an already allocated MP4_Box_t, and all data
78 * will only be peek not read
80 * RETURN : 0 if it fail, 1 otherwise
81 *****************************************************************************/
82 int MP4_ReadBoxCommon( stream_t *p_stream, MP4_Box_t *p_box )
85 const uint8_t *p_peek;
87 if( ( ( i_read = stream_Peek( p_stream, &p_peek, 32 ) ) < 8 ) )
91 p_box->i_pos = stream_Tell( p_stream );
93 p_box->data.p_data = NULL;
94 p_box->p_father = NULL;
95 p_box->p_first = NULL;
99 MP4_GET4BYTES( p_box->i_shortsize );
100 MP4_GETFOURCC( p_box->i_type );
102 /* Now special case */
104 if( p_box->i_shortsize == 1 )
106 /* get the true size on 64 bits */
107 MP4_GET8BYTES( p_box->i_size );
111 p_box->i_size = p_box->i_shortsize;
112 /* XXX size of 0 means that the box extends to end of file */
115 if( p_box->i_type == ATOM_uuid )
117 /* get extented type on 16 bytes */
118 GetUUID( &p_box->i_uuid, p_peek );
119 p_peek += 16; i_read -= 16;
123 CreateUUID( &p_box->i_uuid, p_box->i_type );
128 if MP4_BOX_TYPE_ASCII()
129 msg_Dbg( p_stream, "found Box: %4.4s size %"PRId64,
130 (char*)&p_box->i_type, p_box->i_size );
132 msg_Dbg( p_stream, "found Box: c%3.3s size %"PRId64,
133 (char*)&p_box->i_type+1, p_box->i_size );
140 /*****************************************************************************
141 * MP4_NextBox : Go to the next box
142 *****************************************************************************
143 * if p_box == NULL, go to the next box in which we are( at the begining ).
144 *****************************************************************************/
145 static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
151 MP4_ReadBoxCommon( p_stream, &box );
157 return 2; /* Box with infinite size */
160 if( p_box->p_father )
162 /* if father's size == 0, it means unknown or infinite size,
163 * and we skip the followong check */
164 if( p_box->p_father->i_size > 0 )
166 const off_t i_box_end = p_box->i_size + p_box->i_pos;
167 const off_t i_father_end = p_box->p_father->i_size + p_box->p_father->i_pos;
169 /* check if it's within p-father */
170 if( i_box_end >= i_father_end )
172 if( i_box_end > i_father_end )
173 msg_Dbg( p_stream, "out of bound child" );
174 return 0; /* out of bound */
178 if( stream_Seek( p_stream, p_box->i_size + p_box->i_pos ) )
186 /*****************************************************************************
187 * For all known box a loader is given,
188 * XXX: all common struct have to be already read by MP4_ReadBoxCommon
189 * after called one of theses functions, file position is unknown
190 * you need to call MP4_GotoBox to go where you want
191 *****************************************************************************/
192 static int MP4_ReadBoxContainerChildren( stream_t *p_stream,
193 MP4_Box_t *p_container, uint32_t i_last_child )
197 /* Size of root container is set to 0 when unknown, for exemple
198 * with a DASH stream. In that case, we skip the following check */
199 if( p_container->i_size
200 && ( stream_Tell( p_stream ) + 8 >
201 (off_t)(p_container->i_pos + p_container->i_size) )
204 /* there is no box to load */
210 if( ( p_box = MP4_ReadBox( p_stream, p_container ) ) == NULL ) break;
212 /* chain this box with the father and the other at same level */
213 if( !p_container->p_first ) p_container->p_first = p_box;
214 else p_container->p_last->p_next = p_box;
215 p_container->p_last = p_box;
217 if( p_box->i_type == i_last_child )
220 } while( MP4_NextBox( p_stream, p_box ) == 1 );
225 static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container )
227 return MP4_ReadBoxContainerChildren( p_stream, p_container, 0 );
230 static int MP4_ReadBoxContainer( stream_t *p_stream, MP4_Box_t *p_container )
232 if( p_container->i_size &&
233 ( p_container->i_size <= (size_t)mp4_box_headersize(p_container ) + 8 ) )
235 /* container is empty, 8 stand for the first header in this box */
240 stream_Seek( p_stream, p_container->i_pos +
241 mp4_box_headersize( p_container ) );
243 return MP4_ReadBoxContainerRaw( p_stream, p_container );
246 static void MP4_FreeBox_Common( MP4_Box_t *p_box )
248 /* Up to now do nothing */
252 static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box )
254 /* XXX sometime moov is hiden in a free box */
255 if( p_box->p_father &&
256 p_box->p_father->i_type == ATOM_root &&
257 p_box->i_type == ATOM_free )
259 const uint8_t *p_peek;
263 i_read = stream_Peek( p_stream, &p_peek, 44 );
265 p_peek += mp4_box_headersize( p_box ) + 4;
266 i_read -= mp4_box_headersize( p_box ) + 4;
270 i_fcc = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
272 if( i_fcc == ATOM_cmov || i_fcc == ATOM_mvhd )
274 msg_Warn( p_stream, "detected moov hidden in a free box ..." );
276 p_box->i_type = ATOM_foov;
277 return MP4_ReadBoxContainer( p_stream, p_box );
284 if MP4_BOX_TYPE_ASCII()
285 msg_Dbg( p_stream, "skip box: \"%4.4s\"", (char*)&p_box->i_type );
287 msg_Dbg( p_stream, "skip box: \"c%3.3s\"", (char*)&p_box->i_type+1 );
292 static int MP4_ReadBox_ftyp( stream_t *p_stream, MP4_Box_t *p_box )
294 MP4_READBOX_ENTER( MP4_Box_data_ftyp_t );
296 MP4_GETFOURCC( p_box->data.p_ftyp->i_major_brand );
297 MP4_GET4BYTES( p_box->data.p_ftyp->i_minor_version );
299 if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) )
301 uint32_t *tab = p_box->data.p_ftyp->i_compatible_brands =
302 calloc( p_box->data.p_ftyp->i_compatible_brands_count,
305 if( unlikely( tab == NULL ) )
306 MP4_READBOX_EXIT( 0 );
308 for( unsigned i = 0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )
310 MP4_GETFOURCC( tab[i] );
315 p_box->data.p_ftyp->i_compatible_brands = NULL;
318 MP4_READBOX_EXIT( 1 );
321 static void MP4_FreeBox_ftyp( MP4_Box_t *p_box )
323 FREENULL( p_box->data.p_ftyp->i_compatible_brands );
327 static int MP4_ReadBox_mvhd( stream_t *p_stream, MP4_Box_t *p_box )
330 char s_creation_time[128];
331 char s_modification_time[128];
332 char s_duration[128];
334 MP4_READBOX_ENTER( MP4_Box_data_mvhd_t );
336 MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );
338 if( p_box->data.p_mvhd->i_version )
340 MP4_GET8BYTES( p_box->data.p_mvhd->i_creation_time );
341 MP4_GET8BYTES( p_box->data.p_mvhd->i_modification_time );
342 MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
343 MP4_GET8BYTES( p_box->data.p_mvhd->i_duration );
347 MP4_GET4BYTES( p_box->data.p_mvhd->i_creation_time );
348 MP4_GET4BYTES( p_box->data.p_mvhd->i_modification_time );
349 MP4_GET4BYTES( p_box->data.p_mvhd->i_timescale );
350 MP4_GET4BYTES( p_box->data.p_mvhd->i_duration );
352 MP4_GET4BYTES( p_box->data.p_mvhd->i_rate );
353 MP4_GET2BYTES( p_box->data.p_mvhd->i_volume );
354 MP4_GET2BYTES( p_box->data.p_mvhd->i_reserved1 );
357 for( unsigned i = 0; i < 2; i++ )
359 MP4_GET4BYTES( p_box->data.p_mvhd->i_reserved2[i] );
361 for( unsigned i = 0; i < 9; i++ )
363 MP4_GET4BYTES( p_box->data.p_mvhd->i_matrix[i] );
365 for( unsigned i = 0; i < 6; i++ )
367 MP4_GET4BYTES( p_box->data.p_mvhd->i_predefined[i] );
370 MP4_GET4BYTES( p_box->data.p_mvhd->i_next_track_id );
374 MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
375 MP4_ConvertDate2Str( s_modification_time,
376 p_box->data.p_mvhd->i_modification_time );
377 if( p_box->data.p_mvhd->i_rate )
379 MP4_ConvertDate2Str( s_duration,
380 p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate );
386 msg_Dbg( p_stream, "read box: \"mvhd\" creation %s modification %s time scale %d duration %s rate %f volume %f next track id %d",
389 (uint32_t)p_box->data.p_mvhd->i_timescale,
391 (float)p_box->data.p_mvhd->i_rate / (1<<16 ),
392 (float)p_box->data.p_mvhd->i_volume / 256 ,
393 (uint32_t)p_box->data.p_mvhd->i_next_track_id );
395 MP4_READBOX_EXIT( 1 );
398 static int MP4_ReadBox_mfhd( stream_t *p_stream, MP4_Box_t *p_box )
400 MP4_READBOX_ENTER( MP4_Box_data_mfhd_t );
402 MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );
404 MP4_GET4BYTES( p_box->data.p_mfhd->i_sequence_number );
407 msg_Dbg( p_stream, "read box: \"mfhd\" sequence number %d",
408 p_box->data.p_mfhd->i_sequence_number );
410 MP4_READBOX_EXIT( 1 );
413 static int MP4_ReadBox_tfxd( stream_t *p_stream, MP4_Box_t *p_box )
415 MP4_READBOX_ENTER( MP4_Box_data_tfxd_t );
417 MP4_Box_data_tfxd_t *p_tfxd_data = p_box->data.p_tfxd;
418 MP4_GETVERSIONFLAGS( p_tfxd_data );
420 if( p_tfxd_data->i_version == 0 )
422 MP4_GET4BYTES( p_tfxd_data->i_fragment_abs_time );
423 MP4_GET4BYTES( p_tfxd_data->i_fragment_duration );
427 MP4_GET8BYTES( p_tfxd_data->i_fragment_abs_time );
428 MP4_GET8BYTES( p_tfxd_data->i_fragment_duration );
432 msg_Dbg( p_stream, "read box: \"tfxd\" version %d, flags 0x%x, "\
433 "fragment duration %"PRIu64", fragment abs time %"PRIu64,
434 p_tfxd_data->i_version,
435 p_tfxd_data->i_flags,
436 p_tfxd_data->i_fragment_duration,
437 p_tfxd_data->i_fragment_abs_time
441 MP4_READBOX_EXIT( 1 );
444 static int MP4_ReadBox_tfrf( stream_t *p_stream, MP4_Box_t *p_box )
446 MP4_READBOX_ENTER( MP4_Box_data_tfxd_t );
448 MP4_Box_data_tfrf_t *p_tfrf_data = p_box->data.p_tfrf;
449 MP4_GETVERSIONFLAGS( p_tfrf_data );
451 MP4_GET1BYTE( p_tfrf_data->i_fragment_count );
453 p_tfrf_data->p_tfrf_data_fields = calloc( p_tfrf_data->i_fragment_count,
454 sizeof( TfrfBoxDataFields_t ) );
455 if( !p_tfrf_data->p_tfrf_data_fields )
456 MP4_READBOX_EXIT( 0 );
458 for( uint8_t i = 0; i < p_tfrf_data->i_fragment_count; i++ )
460 TfrfBoxDataFields_t *TfrfBoxDataField = &p_tfrf_data->p_tfrf_data_fields[i];
461 if( p_tfrf_data->i_version == 0 )
463 MP4_GET4BYTES( TfrfBoxDataField->i_fragment_abs_time );
464 MP4_GET4BYTES( TfrfBoxDataField->i_fragment_duration );
468 MP4_GET8BYTES( TfrfBoxDataField->i_fragment_abs_time );
469 MP4_GET8BYTES( TfrfBoxDataField->i_fragment_duration );
474 msg_Dbg( p_stream, "read box: \"tfrf\" version %d, flags 0x%x, "\
475 "fragment count %"PRIu8, p_tfrf_data->i_version,
476 p_tfrf_data->i_flags, p_tfrf_data->i_fragment_count );
478 for( uint8_t i = 0; i < p_tfrf_data->i_fragment_count; i++ )
480 TfrfBoxDataFields_t *TfrfBoxDataField = &p_tfrf_data->p_tfrf_data_fields[i];
481 msg_Dbg( p_stream, "\"tfrf\" fragment duration %"PRIu64", "\
482 "fragment abs time %"PRIu64,
483 TfrfBoxDataField->i_fragment_duration,
484 TfrfBoxDataField->i_fragment_abs_time );
489 MP4_READBOX_EXIT( 1 );
492 static void MP4_FreeBox_tfrf( MP4_Box_t *p_box )
494 FREENULL( p_box->data.p_tfrf->p_tfrf_data_fields );
497 static int MP4_ReadBox_stra( stream_t *p_stream, MP4_Box_t *p_box )
499 MP4_READBOX_ENTER( MP4_Box_data_stra_t );
500 MP4_Box_data_stra_t *p_stra = p_box->data.p_stra;
503 MP4_GET1BYTE( p_stra->i_es_cat );
504 MP4_GET1BYTE( i_reserved );
505 MP4_GET2BYTES( p_stra->i_track_ID );
507 MP4_GET4BYTES( p_stra->i_timescale );
508 MP4_GET8BYTES( p_stra->i_duration );
510 MP4_GET4BYTES( p_stra->FourCC );
511 MP4_GET4BYTES( p_stra->Bitrate );
512 MP4_GET4BYTES( p_stra->MaxWidth );
513 MP4_GET4BYTES( p_stra->MaxHeight );
514 MP4_GET4BYTES( p_stra->SamplingRate );
515 MP4_GET4BYTES( p_stra->Channels );
516 MP4_GET4BYTES( p_stra->BitsPerSample );
517 MP4_GET4BYTES( p_stra->AudioTag );
518 MP4_GET2BYTES( p_stra->nBlockAlign );
520 MP4_GET1BYTE( i_reserved );
521 MP4_GET1BYTE( i_reserved );
522 MP4_GET1BYTE( i_reserved );
523 MP4_GET1BYTE( p_stra->cpd_len );
524 if( p_stra->cpd_len > i_read )
526 p_stra->CodecPrivateData = malloc( p_stra->cpd_len );
527 if( unlikely( p_stra->CodecPrivateData == NULL ) )
529 memcpy( p_stra->CodecPrivateData, p_peek, p_stra->cpd_len );
532 msg_Dbg( p_stream, "es_cat is %"PRIu8", birate is %"PRIu32,
533 p_stra->i_es_cat, p_stra->Bitrate );
536 MP4_READBOX_EXIT( 1 );
538 MP4_READBOX_EXIT( 0 );
541 static void MP4_FreeBox_stra( MP4_Box_t *p_box )
543 FREENULL( p_box->data.p_stra->CodecPrivateData );
546 static int MP4_ReadBox_uuid( stream_t *p_stream, MP4_Box_t *p_box )
548 if( !CmpUUID( &p_box->i_uuid, &TfrfBoxUUID ) )
549 return MP4_ReadBox_tfrf( p_stream, p_box );
550 if( !CmpUUID( &p_box->i_uuid, &TfxdBoxUUID ) )
551 return MP4_ReadBox_tfxd( p_stream, p_box );
552 if( !CmpUUID( &p_box->i_uuid, &SmooBoxUUID ) )
553 return MP4_ReadBoxContainer( p_stream, p_box );
554 if( !CmpUUID( &p_box->i_uuid, &StraBoxUUID ) )
555 return MP4_ReadBox_stra( p_stream, p_box );
557 msg_Warn( p_stream, "Unknown uuid type box" );
561 static void MP4_FreeBox_uuid( MP4_Box_t *p_box )
563 if( !CmpUUID( &p_box->i_uuid, &TfrfBoxUUID ) )
564 return MP4_FreeBox_tfrf( p_box );
565 if( !CmpUUID( &p_box->i_uuid, &TfxdBoxUUID ) )
566 return MP4_FreeBox_Common( p_box );
567 if( !CmpUUID( &p_box->i_uuid, &SmooBoxUUID ) )
568 return MP4_FreeBox_Common( p_box );
569 if( !CmpUUID( &p_box->i_uuid, &StraBoxUUID ) )
570 return MP4_FreeBox_stra( p_box );
573 static int MP4_ReadBox_sidx( stream_t *p_stream, MP4_Box_t *p_box )
575 MP4_READBOX_ENTER( MP4_Box_data_sidx_t );
577 MP4_Box_data_sidx_t *p_sidx_data = p_box->data.p_sidx;
578 MP4_GETVERSIONFLAGS( p_sidx_data );
580 MP4_GET4BYTES( p_sidx_data->i_reference_ID );
581 MP4_GET4BYTES( p_sidx_data->i_timescale );
583 if( p_sidx_data->i_version == 0 )
585 MP4_GET4BYTES( p_sidx_data->i_earliest_presentation_time );
586 MP4_GET4BYTES( p_sidx_data->i_first_offset );
590 MP4_GET8BYTES( p_sidx_data->i_earliest_presentation_time );
591 MP4_GET8BYTES( p_sidx_data->i_first_offset );
595 MP4_GET2BYTES( i_reserved );
596 MP4_GET2BYTES( p_sidx_data->i_reference_count );
597 uint16_t i_count = p_sidx_data->i_reference_count;
599 p_sidx_data->p_items = calloc( i_count, sizeof( MP4_Box_sidx_item_t ) );
601 for( unsigned i = 0; i < i_count; i++ )
603 MP4_GET4BYTES( tmp );
604 p_sidx_data->p_items[i].b_reference_type = (bool)((tmp & 0x80000000)>>24);
605 p_sidx_data->p_items[i].i_referenced_size = tmp & 0x7fffffff;
606 MP4_GET4BYTES( p_sidx_data->p_items[i].i_subsegment_duration );
608 MP4_GET4BYTES( tmp );
609 p_sidx_data->p_items[i].b_starts_with_SAP = (bool)((tmp & 0x80000000)>>24);
610 p_sidx_data->p_items[i].i_SAP_type = (tmp & 0x70000000)>>24;
611 p_sidx_data->p_items[i].i_SAP_delta_time = tmp & 0xfffffff;
615 msg_Dbg( p_stream, "read box: \"sidx\" version %d, flags 0x%x, "\
616 "ref_ID %"PRIu32", timescale %"PRIu32", ref_count %"PRIu16", "\
617 "first subsegmt duration %"PRIu32,
618 p_sidx_data->i_version,
619 p_sidx_data->i_flags,
620 p_sidx_data->i_reference_ID,
621 p_sidx_data->i_timescale,
622 p_sidx_data->i_reference_count,
623 p_sidx_data->p_items[0].i_subsegment_duration
627 MP4_READBOX_EXIT( 1 );
630 static void MP4_FreeBox_sidx( MP4_Box_t *p_box )
632 FREENULL( p_box->data.p_sidx->p_items );
635 static int MP4_ReadBox_tfhd( stream_t *p_stream, MP4_Box_t *p_box )
637 MP4_READBOX_ENTER( MP4_Box_data_tfhd_t );
639 MP4_GETVERSIONFLAGS( p_box->data.p_tfhd );
641 if( p_box->data.p_tfhd->i_version != 0 )
643 msg_Warn( p_stream, "'tfhd' box with version != 0. "\
644 " Don't know what to do with that, please patch" );
645 MP4_READBOX_EXIT( 0 );
648 MP4_GET4BYTES( p_box->data.p_tfhd->i_track_ID );
650 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DURATION_IS_EMPTY )
652 msg_Dbg( p_stream, "'duration-is-empty' flag is present "\
653 "=> no samples for this time interval." );
654 p_box->data.p_tfhd->b_empty = true;
657 p_box->data.p_tfhd->b_empty = false;
659 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
660 MP4_GET8BYTES( p_box->data.p_tfhd->i_base_data_offset );
661 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
662 MP4_GET4BYTES( p_box->data.p_tfhd->i_sample_description_index );
663 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
664 MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_duration );
665 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
666 MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_size );
667 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
668 MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_flags );
671 char psz_base[128] = "\0";
672 char psz_desc[128] = "\0";
673 char psz_dura[128] = "\0";
674 char psz_size[128] = "\0";
675 char psz_flag[128] = "\0";
676 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
677 snprintf(psz_base, sizeof(psz_base), "base offset %"PRId64, p_box->data.p_tfhd->i_base_data_offset);
678 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
679 snprintf(psz_desc, sizeof(psz_desc), "sample description index %d", p_box->data.p_tfhd->i_sample_description_index);
680 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
681 snprintf(psz_dura, sizeof(psz_dura), "sample duration %d", p_box->data.p_tfhd->i_default_sample_duration);
682 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
683 snprintf(psz_size, sizeof(psz_size), "sample size %d", p_box->data.p_tfhd->i_default_sample_size);
684 if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
685 snprintf(psz_flag, sizeof(psz_flag), "sample flags 0x%x", p_box->data.p_tfhd->i_default_sample_flags);
687 msg_Dbg( p_stream, "read box: \"tfhd\" version %d flags 0x%x track ID %d %s %s %s %s %s",
688 p_box->data.p_tfhd->i_version,
689 p_box->data.p_tfhd->i_flags,
690 p_box->data.p_tfhd->i_track_ID,
691 psz_base, psz_desc, psz_dura, psz_size, psz_flag );
694 MP4_READBOX_EXIT( 1 );
697 static int MP4_ReadBox_trun( stream_t *p_stream, MP4_Box_t *p_box )
699 MP4_READBOX_ENTER( MP4_Box_data_trun_t );
701 MP4_GETVERSIONFLAGS( p_box->data.p_trun );
703 MP4_GET4BYTES( p_box->data.p_trun->i_sample_count );
705 if( p_box->data.p_trun->i_flags & MP4_TRUN_DATA_OFFSET )
706 MP4_GET4BYTES( p_box->data.p_trun->i_data_offset );
707 if( p_box->data.p_trun->i_flags & MP4_TRUN_FIRST_FLAGS )
708 MP4_GET4BYTES( p_box->data.p_trun->i_first_sample_flags );
710 p_box->data.p_trun->p_samples =
711 calloc( p_box->data.p_trun->i_sample_count, sizeof(MP4_descriptor_trun_sample_t) );
712 if ( p_box->data.p_trun->p_samples == NULL )
713 MP4_READBOX_EXIT( 0 );
715 for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
717 MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
718 if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION )
719 MP4_GET4BYTES( p_sample->i_duration );
720 if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE )
721 MP4_GET4BYTES( p_sample->i_size );
722 if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_FLAGS )
723 MP4_GET4BYTES( p_sample->i_flags );
724 if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET )
725 MP4_GET4BYTES( p_sample->i_composition_time_offset );
729 msg_Dbg( p_stream, "read box: \"trun\" version %u flags 0x%x sample count %u",
730 p_box->data.p_trun->i_version,
731 p_box->data.p_trun->i_flags,
732 p_box->data.p_trun->i_sample_count );
734 for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
736 MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
737 msg_Dbg( p_stream, "read box: \"trun\" sample %4.4u flags 0x%x "\
738 "duration %"PRIu32" size %"PRIu32" composition time offset %"PRIu32,
739 i, p_sample->i_flags, p_sample->i_duration,
740 p_sample->i_size, p_sample->i_composition_time_offset );
744 MP4_READBOX_EXIT( 1 );
747 static void MP4_FreeBox_trun( MP4_Box_t *p_box )
749 FREENULL( p_box->data.p_trun->p_samples );
753 static int MP4_ReadBox_tkhd( stream_t *p_stream, MP4_Box_t *p_box )
756 char s_creation_time[128];
757 char s_modification_time[128];
758 char s_duration[128];
760 MP4_READBOX_ENTER( MP4_Box_data_tkhd_t );
762 MP4_GETVERSIONFLAGS( p_box->data.p_tkhd );
764 if( p_box->data.p_tkhd->i_version )
766 MP4_GET8BYTES( p_box->data.p_tkhd->i_creation_time );
767 MP4_GET8BYTES( p_box->data.p_tkhd->i_modification_time );
768 MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
769 MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
770 MP4_GET8BYTES( p_box->data.p_tkhd->i_duration );
774 MP4_GET4BYTES( p_box->data.p_tkhd->i_creation_time );
775 MP4_GET4BYTES( p_box->data.p_tkhd->i_modification_time );
776 MP4_GET4BYTES( p_box->data.p_tkhd->i_track_ID );
777 MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved );
778 MP4_GET4BYTES( p_box->data.p_tkhd->i_duration );
781 for( unsigned i = 0; i < 2; i++ )
783 MP4_GET4BYTES( p_box->data.p_tkhd->i_reserved2[i] );
785 MP4_GET2BYTES( p_box->data.p_tkhd->i_layer );
786 MP4_GET2BYTES( p_box->data.p_tkhd->i_predefined );
787 MP4_GET2BYTES( p_box->data.p_tkhd->i_volume );
788 MP4_GET2BYTES( p_box->data.p_tkhd->i_reserved3 );
790 for( unsigned i = 0; i < 9; i++ )
792 MP4_GET4BYTES( p_box->data.p_tkhd->i_matrix[i] );
794 MP4_GET4BYTES( p_box->data.p_tkhd->i_width );
795 MP4_GET4BYTES( p_box->data.p_tkhd->i_height );
797 double rotation; //angle in degrees to be rotated clockwise
798 double scale[2]; // scale factor; sx = scale[0] , sy = scale[1]
799 double translate[2];// amount to translate; tx = translate[0] , ty = translate[1]
801 int *matrix = p_box->data.p_tkhd->i_matrix;
803 translate[0] = conv_fx(matrix[6]);
804 translate[1] = conv_fx(matrix[7]);
806 scale[0] = sqrt(conv_fx(matrix[0]) * conv_fx(matrix[0]) +
807 conv_fx(matrix[3]) * conv_fx(matrix[3]));
808 scale[1] = sqrt(conv_fx(matrix[1]) * conv_fx(matrix[1]) +
809 conv_fx(matrix[4]) * conv_fx(matrix[4]));
811 rotation = atan2(conv_fx(matrix[1]) / scale[1], conv_fx(matrix[0]) / scale[0]) * 180 / M_PI;
816 p_box->data.p_tkhd->f_rotation = rotation;
819 MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
820 MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time );
821 MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration );
823 msg_Dbg( p_stream, "read box: \"tkhd\" creation %s modification %s duration %s track ID %d layer %d volume %f rotation %f scaleX %f scaleY %f translateX %f translateY %f width %f height %f. "
824 "Matrix: %i %i %i %i %i %i %i %i %i",
828 p_box->data.p_tkhd->i_track_ID,
829 p_box->data.p_tkhd->i_layer,
830 (float)p_box->data.p_tkhd->i_volume / 256 ,
836 (float)p_box->data.p_tkhd->i_width / 65536,
837 (float)p_box->data.p_tkhd->i_height / 65536,
838 p_box->data.p_tkhd->i_matrix[0],
839 p_box->data.p_tkhd->i_matrix[1],
840 p_box->data.p_tkhd->i_matrix[2],
841 p_box->data.p_tkhd->i_matrix[3],
842 p_box->data.p_tkhd->i_matrix[4],
843 p_box->data.p_tkhd->i_matrix[5],
844 p_box->data.p_tkhd->i_matrix[6],
845 p_box->data.p_tkhd->i_matrix[7],
846 p_box->data.p_tkhd->i_matrix[8] );
848 MP4_READBOX_EXIT( 1 );
852 static int MP4_ReadBox_mdhd( stream_t *p_stream, MP4_Box_t *p_box )
856 char s_creation_time[128];
857 char s_modification_time[128];
858 char s_duration[128];
860 MP4_READBOX_ENTER( MP4_Box_data_mdhd_t );
862 MP4_GETVERSIONFLAGS( p_box->data.p_mdhd );
864 if( p_box->data.p_mdhd->i_version )
866 MP4_GET8BYTES( p_box->data.p_mdhd->i_creation_time );
867 MP4_GET8BYTES( p_box->data.p_mdhd->i_modification_time );
868 MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
869 MP4_GET8BYTES( p_box->data.p_mdhd->i_duration );
873 MP4_GET4BYTES( p_box->data.p_mdhd->i_creation_time );
874 MP4_GET4BYTES( p_box->data.p_mdhd->i_modification_time );
875 MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
876 MP4_GET4BYTES( p_box->data.p_mdhd->i_duration );
878 p_box->data.p_mdhd->i_language_code = i_language = GetWBE( p_peek );
879 for( unsigned i = 0; i < 3; i++ )
881 p_box->data.p_mdhd->i_language[i] =
882 ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
885 MP4_GET2BYTES( p_box->data.p_mdhd->i_predefined );
888 MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time );
889 MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time );
890 MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration );
891 msg_Dbg( p_stream, "read box: \"mdhd\" creation %s modification %s time scale %d duration %s language %c%c%c",
894 (uint32_t)p_box->data.p_mdhd->i_timescale,
896 p_box->data.p_mdhd->i_language[0],
897 p_box->data.p_mdhd->i_language[1],
898 p_box->data.p_mdhd->i_language[2] );
900 MP4_READBOX_EXIT( 1 );
904 static int MP4_ReadBox_hdlr( stream_t *p_stream, MP4_Box_t *p_box )
908 MP4_READBOX_ENTER( MP4_Box_data_hdlr_t );
910 MP4_GETVERSIONFLAGS( p_box->data.p_hdlr );
912 MP4_GETFOURCC( p_box->data.p_hdlr->i_predefined );
913 MP4_GETFOURCC( p_box->data.p_hdlr->i_handler_type );
915 MP4_GET4BYTES( i_reserved );
916 MP4_GET4BYTES( i_reserved );
917 MP4_GET4BYTES( i_reserved );
918 p_box->data.p_hdlr->psz_name = NULL;
922 uint8_t *psz = p_box->data.p_hdlr->psz_name = malloc( i_read + 1 );
923 if( unlikely( psz == NULL ) )
924 MP4_READBOX_EXIT( 0 );
926 /* Yes, I love .mp4 :( */
927 if( p_box->data.p_hdlr->i_predefined == VLC_FOURCC( 'm', 'h', 'l', 'r' ) )
932 MP4_GET1BYTE( i_len );
933 i_copy = __MIN( i_read, i_len );
935 memcpy( psz, p_peek, i_copy );
936 p_box->data.p_hdlr->psz_name[i_copy] = '\0';
940 memcpy( psz, p_peek, i_read );
941 p_box->data.p_hdlr->psz_name[i_read] = '\0';
946 msg_Dbg( p_stream, "read box: \"hdlr\" handler type: \"%4.4s\" name: \"%s\"",
947 (char*)&p_box->data.p_hdlr->i_handler_type,
948 p_box->data.p_hdlr->psz_name );
951 MP4_READBOX_EXIT( 1 );
954 static void MP4_FreeBox_hdlr( MP4_Box_t *p_box )
956 FREENULL( p_box->data.p_hdlr->psz_name );
959 static int MP4_ReadBox_vmhd( stream_t *p_stream, MP4_Box_t *p_box )
961 MP4_READBOX_ENTER( MP4_Box_data_vmhd_t );
963 MP4_GETVERSIONFLAGS( p_box->data.p_vmhd );
965 MP4_GET2BYTES( p_box->data.p_vmhd->i_graphics_mode );
966 for( unsigned i = 0; i < 3; i++ )
968 MP4_GET2BYTES( p_box->data.p_vmhd->i_opcolor[i] );
972 msg_Dbg( p_stream, "read box: \"vmhd\" graphics-mode %d opcolor (%d, %d, %d)",
973 p_box->data.p_vmhd->i_graphics_mode,
974 p_box->data.p_vmhd->i_opcolor[0],
975 p_box->data.p_vmhd->i_opcolor[1],
976 p_box->data.p_vmhd->i_opcolor[2] );
978 MP4_READBOX_EXIT( 1 );
981 static int MP4_ReadBox_smhd( stream_t *p_stream, MP4_Box_t *p_box )
983 MP4_READBOX_ENTER( MP4_Box_data_smhd_t );
985 MP4_GETVERSIONFLAGS( p_box->data.p_smhd );
989 MP4_GET2BYTES( p_box->data.p_smhd->i_balance );
991 MP4_GET2BYTES( p_box->data.p_smhd->i_reserved );
994 msg_Dbg( p_stream, "read box: \"smhd\" balance %f",
995 (float)p_box->data.p_smhd->i_balance / 256 );
997 MP4_READBOX_EXIT( 1 );
1001 static int MP4_ReadBox_hmhd( stream_t *p_stream, MP4_Box_t *p_box )
1003 MP4_READBOX_ENTER( MP4_Box_data_hmhd_t );
1005 MP4_GETVERSIONFLAGS( p_box->data.p_hmhd );
1007 MP4_GET2BYTES( p_box->data.p_hmhd->i_max_PDU_size );
1008 MP4_GET2BYTES( p_box->data.p_hmhd->i_avg_PDU_size );
1010 MP4_GET4BYTES( p_box->data.p_hmhd->i_max_bitrate );
1011 MP4_GET4BYTES( p_box->data.p_hmhd->i_avg_bitrate );
1013 MP4_GET4BYTES( p_box->data.p_hmhd->i_reserved );
1016 msg_Dbg( p_stream, "read box: \"hmhd\" maxPDU-size %d avgPDU-size %d max-bitrate %d avg-bitrate %d",
1017 p_box->data.p_hmhd->i_max_PDU_size,
1018 p_box->data.p_hmhd->i_avg_PDU_size,
1019 p_box->data.p_hmhd->i_max_bitrate,
1020 p_box->data.p_hmhd->i_avg_bitrate );
1022 MP4_READBOX_EXIT( 1 );
1025 static int MP4_ReadBox_url( stream_t *p_stream, MP4_Box_t *p_box )
1027 MP4_READBOX_ENTER( MP4_Box_data_url_t );
1029 MP4_GETVERSIONFLAGS( p_box->data.p_url );
1030 MP4_GETSTRINGZ( p_box->data.p_url->psz_location );
1033 msg_Dbg( p_stream, "read box: \"url\" url: %s",
1034 p_box->data.p_url->psz_location );
1037 MP4_READBOX_EXIT( 1 );
1041 static void MP4_FreeBox_url( MP4_Box_t *p_box )
1043 FREENULL( p_box->data.p_url->psz_location );
1046 static int MP4_ReadBox_urn( stream_t *p_stream, MP4_Box_t *p_box )
1048 MP4_READBOX_ENTER( MP4_Box_data_urn_t );
1050 MP4_GETVERSIONFLAGS( p_box->data.p_urn );
1052 MP4_GETSTRINGZ( p_box->data.p_urn->psz_name );
1053 MP4_GETSTRINGZ( p_box->data.p_urn->psz_location );
1056 msg_Dbg( p_stream, "read box: \"urn\" name %s location %s",
1057 p_box->data.p_urn->psz_name,
1058 p_box->data.p_urn->psz_location );
1060 MP4_READBOX_EXIT( 1 );
1062 static void MP4_FreeBox_urn( MP4_Box_t *p_box )
1064 FREENULL( p_box->data.p_urn->psz_name );
1065 FREENULL( p_box->data.p_urn->psz_location );
1069 static int MP4_ReadBox_dref( stream_t *p_stream, MP4_Box_t *p_box )
1071 MP4_READBOX_ENTER( MP4_Box_data_dref_t );
1073 MP4_GETVERSIONFLAGS( p_box->data.p_dref );
1075 MP4_GET4BYTES( p_box->data.p_dref->i_entry_count );
1077 stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
1078 MP4_ReadBoxContainerRaw( p_stream, p_box );
1081 msg_Dbg( p_stream, "read box: \"dref\" entry-count %d",
1082 p_box->data.p_dref->i_entry_count );
1085 MP4_READBOX_EXIT( 1 );
1088 static void MP4_FreeBox_stts( MP4_Box_t *p_box )
1090 FREENULL( p_box->data.p_stts->i_sample_count );
1091 FREENULL( p_box->data.p_stts->i_sample_delta );
1094 static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box )
1096 MP4_READBOX_ENTER( MP4_Box_data_stts_t );
1098 MP4_GETVERSIONFLAGS( p_box->data.p_stts );
1099 MP4_GET4BYTES( p_box->data.p_stts->i_entry_count );
1101 p_box->data.p_stts->i_sample_count =
1102 calloc( p_box->data.p_stts->i_entry_count, sizeof(uint32_t) );
1103 p_box->data.p_stts->i_sample_delta =
1104 calloc( p_box->data.p_stts->i_entry_count, sizeof(uint32_t) );
1105 if( p_box->data.p_stts->i_sample_count == NULL
1106 || p_box->data.p_stts->i_sample_delta == NULL )
1108 MP4_READBOX_EXIT( 0 );
1111 for( unsigned int i = 0; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ )
1113 MP4_GET4BYTES( p_box->data.p_stts->i_sample_count[i] );
1114 MP4_GET4BYTES( p_box->data.p_stts->i_sample_delta[i] );
1118 msg_Dbg( p_stream, "read box: \"stts\" entry-count %d",
1119 p_box->data.p_stts->i_entry_count );
1122 MP4_READBOX_EXIT( 1 );
1126 static void MP4_FreeBox_ctts( MP4_Box_t *p_box )
1128 FREENULL( p_box->data.p_ctts->i_sample_count );
1129 FREENULL( p_box->data.p_ctts->i_sample_offset );
1132 static int MP4_ReadBox_ctts( stream_t *p_stream, MP4_Box_t *p_box )
1134 MP4_READBOX_ENTER( MP4_Box_data_ctts_t );
1136 MP4_GETVERSIONFLAGS( p_box->data.p_ctts );
1138 MP4_GET4BYTES( p_box->data.p_ctts->i_entry_count );
1140 p_box->data.p_ctts->i_sample_count =
1141 calloc( p_box->data.p_ctts->i_entry_count, sizeof(uint32_t) );
1142 p_box->data.p_ctts->i_sample_offset =
1143 calloc( p_box->data.p_ctts->i_entry_count, sizeof(uint32_t) );
1144 if( ( p_box->data.p_ctts->i_sample_count == NULL )
1145 || ( p_box->data.p_ctts->i_sample_offset == NULL ) )
1147 MP4_READBOX_EXIT( 0 );
1150 for( unsigned int i = 0; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ )
1152 MP4_GET4BYTES( p_box->data.p_ctts->i_sample_count[i] );
1153 MP4_GET4BYTES( p_box->data.p_ctts->i_sample_offset[i] );
1157 msg_Dbg( p_stream, "read box: \"ctts\" entry-count %d",
1158 p_box->data.p_ctts->i_entry_count );
1161 MP4_READBOX_EXIT( 1 );
1165 static int MP4_ReadLengthDescriptor( uint8_t **pp_peek, int64_t *i_read )
1168 unsigned int i_len = 0;
1175 i_len = ( i_len << 7 ) + ( i_b&0x7f );
1176 } while( i_b&0x80 );
1181 static void MP4_FreeBox_esds( MP4_Box_t *p_box )
1183 FREENULL( p_box->data.p_esds->es_descriptor.psz_URL );
1184 if( p_box->data.p_esds->es_descriptor.p_decConfigDescr )
1186 FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info );
1187 FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr );
1191 static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
1193 #define es_descriptor p_box->data.p_esds->es_descriptor
1195 unsigned int i_flags;
1196 unsigned int i_type;
1198 MP4_READBOX_ENTER( MP4_Box_data_esds_t );
1200 MP4_GETVERSIONFLAGS( p_box->data.p_esds );
1203 MP4_GET1BYTE( i_type );
1204 if( i_type == 0x03 ) /* MP4ESDescrTag */
1206 i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1209 msg_Dbg( p_stream, "found esds MPEG4ESDescr (%dBytes)",
1213 MP4_GET2BYTES( es_descriptor.i_ES_ID );
1214 MP4_GET1BYTE( i_flags );
1215 es_descriptor.b_stream_dependence = ( (i_flags&0x80) != 0);
1216 es_descriptor.b_url = ( (i_flags&0x40) != 0);
1217 es_descriptor.b_OCRstream = ( (i_flags&0x20) != 0);
1219 es_descriptor.i_stream_priority = i_flags&0x1f;
1220 if( es_descriptor.b_stream_dependence )
1222 MP4_GET2BYTES( es_descriptor.i_depend_on_ES_ID );
1224 if( es_descriptor.b_url )
1228 MP4_GET1BYTE( i_len );
1229 es_descriptor.psz_URL = malloc( i_len + 1 );
1230 if( es_descriptor.psz_URL )
1232 memcpy( es_descriptor.psz_URL, p_peek, i_len );
1233 es_descriptor.psz_URL[i_len] = 0;
1240 es_descriptor.psz_URL = NULL;
1242 if( es_descriptor.b_OCRstream )
1244 MP4_GET2BYTES( es_descriptor.i_OCR_ES_ID );
1246 MP4_GET1BYTE( i_type ); /* get next type */
1249 if( i_type != 0x04)/* MP4DecConfigDescrTag */
1251 es_descriptor.p_decConfigDescr = NULL;
1252 MP4_READBOX_EXIT( 1 ); /* rest isn't interesting up to now */
1255 i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1258 msg_Dbg( p_stream, "found esds MP4DecConfigDescr (%dBytes)",
1262 es_descriptor.p_decConfigDescr =
1263 calloc( 1, sizeof( MP4_descriptor_decoder_config_t ));
1264 if( unlikely( es_descriptor.p_decConfigDescr == NULL ) )
1265 MP4_READBOX_EXIT( 0 );
1267 MP4_GET1BYTE( es_descriptor.p_decConfigDescr->i_objectTypeIndication );
1268 MP4_GET1BYTE( i_flags );
1269 es_descriptor.p_decConfigDescr->i_streamType = i_flags >> 2;
1270 es_descriptor.p_decConfigDescr->b_upStream = ( i_flags >> 1 )&0x01;
1271 MP4_GET3BYTES( es_descriptor.p_decConfigDescr->i_buffer_sizeDB );
1272 MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_max_bitrate );
1273 MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_avg_bitrate );
1274 MP4_GET1BYTE( i_type );
1275 if( i_type != 0x05 )/* MP4DecSpecificDescrTag */
1277 es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = 0;
1278 es_descriptor.p_decConfigDescr->p_decoder_specific_info = NULL;
1279 MP4_READBOX_EXIT( 1 );
1282 i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
1285 msg_Dbg( p_stream, "found esds MP4DecSpecificDescr (%dBytes)",
1288 if( i_len > i_read )
1289 MP4_READBOX_EXIT( 0 );
1291 es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = i_len;
1292 es_descriptor.p_decConfigDescr->p_decoder_specific_info = malloc( i_len );
1293 if( unlikely( es_descriptor.p_decConfigDescr->p_decoder_specific_info == NULL ) )
1294 MP4_READBOX_EXIT( 0 );
1296 memcpy( es_descriptor.p_decConfigDescr->p_decoder_specific_info,
1299 MP4_READBOX_EXIT( 1 );
1300 #undef es_descriptor
1303 static void MP4_FreeBox_avcC( MP4_Box_t *p_box )
1305 MP4_Box_data_avcC_t *p_avcC = p_box->data.p_avcC;
1308 if( p_avcC->i_avcC > 0 ) FREENULL( p_avcC->p_avcC );
1312 for( i = 0; i < p_avcC->i_sps; i++ )
1313 FREENULL( p_avcC->sps[i] );
1317 for( i = 0; i < p_avcC->i_pps; i++ )
1318 FREENULL( p_avcC->pps[i] );
1320 if( p_avcC->i_sps > 0 ) FREENULL( p_avcC->sps );
1321 if( p_avcC->i_sps > 0 ) FREENULL( p_avcC->i_sps_length );
1322 if( p_avcC->i_pps > 0 ) FREENULL( p_avcC->pps );
1323 if( p_avcC->i_pps > 0 ) FREENULL( p_avcC->i_pps_length );
1326 static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box )
1328 MP4_Box_data_avcC_t *p_avcC;
1331 MP4_READBOX_ENTER( MP4_Box_data_avcC_t );
1332 p_avcC = p_box->data.p_avcC;
1334 p_avcC->i_avcC = i_read;
1335 if( p_avcC->i_avcC > 0 )
1337 uint8_t * p = p_avcC->p_avcC = malloc( p_avcC->i_avcC );
1339 memcpy( p, p_peek, i_read );
1342 MP4_GET1BYTE( p_avcC->i_version );
1343 MP4_GET1BYTE( p_avcC->i_profile );
1344 MP4_GET1BYTE( p_avcC->i_profile_compatibility );
1345 MP4_GET1BYTE( p_avcC->i_level );
1346 MP4_GET1BYTE( p_avcC->i_reserved1 );
1347 p_avcC->i_length_size = (p_avcC->i_reserved1&0x03) + 1;
1348 p_avcC->i_reserved1 >>= 2;
1350 MP4_GET1BYTE( p_avcC->i_reserved2 );
1351 p_avcC->i_sps = p_avcC->i_reserved2&0x1f;
1352 p_avcC->i_reserved2 >>= 5;
1354 if( p_avcC->i_sps > 0 )
1356 p_avcC->i_sps_length = calloc( p_avcC->i_sps, sizeof( uint16_t ) );
1357 p_avcC->sps = calloc( p_avcC->i_sps, sizeof( uint8_t* ) );
1359 if( !p_avcC->i_sps_length || !p_avcC->sps )
1362 for( i = 0; i < p_avcC->i_sps; i++ )
1364 MP4_GET2BYTES( p_avcC->i_sps_length[i] );
1365 p_avcC->sps[i] = malloc( p_avcC->i_sps_length[i] );
1366 if( p_avcC->sps[i] )
1367 memcpy( p_avcC->sps[i], p_peek, p_avcC->i_sps_length[i] );
1369 p_peek += p_avcC->i_sps_length[i];
1370 i_read -= p_avcC->i_sps_length[i];
1374 MP4_GET1BYTE( p_avcC->i_pps );
1375 if( p_avcC->i_pps > 0 )
1377 p_avcC->i_pps_length = calloc( p_avcC->i_pps, sizeof( uint16_t ) );
1378 p_avcC->pps = calloc( p_avcC->i_pps, sizeof( uint8_t* ) );
1380 if( !p_avcC->i_pps_length || !p_avcC->pps )
1383 for( i = 0; i < p_avcC->i_pps; i++ )
1385 MP4_GET2BYTES( p_avcC->i_pps_length[i] );
1386 p_avcC->pps[i] = malloc( p_avcC->i_pps_length[i] );
1387 if( p_avcC->pps[i] )
1388 memcpy( p_avcC->pps[i], p_peek, p_avcC->i_pps_length[i] );
1390 p_peek += p_avcC->i_pps_length[i];
1391 i_read -= p_avcC->i_pps_length[i];
1396 "read box: \"avcC\" version=%d profile=0x%x level=0x%x length size=%d sps=%d pps=%d",
1397 p_avcC->i_version, p_avcC->i_profile, p_avcC->i_level,
1398 p_avcC->i_length_size,
1399 p_avcC->i_sps, p_avcC->i_pps );
1400 for( i = 0; i < p_avcC->i_sps; i++ )
1402 msg_Dbg( p_stream, " - sps[%d] length=%d",
1403 i, p_avcC->i_sps_length[i] );
1405 for( i = 0; i < p_avcC->i_pps; i++ )
1407 msg_Dbg( p_stream, " - pps[%d] length=%d",
1408 i, p_avcC->i_pps_length[i] );
1412 MP4_READBOX_EXIT( 1 );
1415 MP4_READBOX_EXIT( 0 );
1418 static int MP4_ReadBox_dac3( stream_t *p_stream, MP4_Box_t *p_box )
1420 MP4_Box_data_dac3_t *p_dac3;
1421 MP4_READBOX_ENTER( MP4_Box_data_dac3_t );
1423 p_dac3 = p_box->data.p_dac3;
1426 MP4_GET3BYTES( i_header );
1428 p_dac3->i_fscod = ( i_header >> 22 ) & 0x03;
1429 p_dac3->i_bsid = ( i_header >> 17 ) & 0x01f;
1430 p_dac3->i_bsmod = ( i_header >> 14 ) & 0x07;
1431 p_dac3->i_acmod = ( i_header >> 11 ) & 0x07;
1432 p_dac3->i_lfeon = ( i_header >> 10 ) & 0x01;
1433 p_dac3->i_bitrate_code = ( i_header >> 5) & 0x1f;
1437 "read box: \"dac3\" fscod=0x%x bsid=0x%x bsmod=0x%x acmod=0x%x lfeon=0x%x bitrate_code=0x%x",
1438 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 );
1440 MP4_READBOX_EXIT( 1 );
1443 static int MP4_ReadBox_dvc1( stream_t *p_stream, MP4_Box_t *p_box )
1445 MP4_Box_data_dvc1_t *p_dvc1;
1447 MP4_READBOX_ENTER( MP4_Box_data_dvc1_t );
1448 p_dvc1 = p_box->data.p_dvc1;
1450 MP4_GET1BYTE( p_dvc1->i_profile_level ); /* profile is on 4bits, level 3bits */
1451 uint8_t i_profile = (p_dvc1->i_profile_level & 0xf0) >> 4;
1452 if( i_profile != 0x06 && i_profile != 0x0c )
1454 msg_Warn( p_stream, "unsupported VC-1 profile (%"PRIu8"), please report", i_profile );
1455 MP4_READBOX_EXIT( 0 );
1459 p_dvc1->i_vc1 = p_box->i_size - 7; /* Header + profile_level */
1461 if( p_dvc1->i_vc1 > 0 )
1463 uint8_t *p = p_dvc1->p_vc1 = malloc( p_dvc1->i_vc1 );
1465 memcpy( p, p_peek, i_read );
1470 "read box: \"dvc1\" profile=%"PRIu8" level=%i",
1471 i_profile, p_dvc1->i_profile_level & 0x0e >> 1 );
1474 MP4_READBOX_EXIT( 1 );
1477 static int MP4_ReadBox_enda( stream_t *p_stream, MP4_Box_t *p_box )
1479 MP4_Box_data_enda_t *p_enda;
1480 MP4_READBOX_ENTER( MP4_Box_data_enda_t );
1482 p_enda = p_box->data.p_enda;
1484 MP4_GET2BYTES( p_enda->i_little_endian );
1488 "read box: \"enda\" little_endian=%d", p_enda->i_little_endian );
1490 MP4_READBOX_EXIT( 1 );
1493 static int MP4_ReadBox_gnre( stream_t *p_stream, MP4_Box_t *p_box )
1495 MP4_Box_data_gnre_t *p_gnre;
1496 MP4_READBOX_ENTER( MP4_Box_data_gnre_t );
1498 p_gnre = p_box->data.p_gnre;
1500 uint32_t i_data_len;
1501 uint32_t i_data_tag;
1503 MP4_GET4BYTES( i_data_len );
1504 MP4_GETFOURCC( i_data_tag );
1505 if( i_data_len < 10 || i_data_tag != ATOM_data )
1506 MP4_READBOX_EXIT( 0 );
1509 uint32_t i_reserved;
1510 MP4_GET4BYTES( i_version );
1511 MP4_GET4BYTES( i_reserved );
1512 MP4_GET2BYTES( p_gnre->i_genre );
1513 if( p_gnre->i_genre == 0 )
1514 MP4_READBOX_EXIT( 0 );
1516 msg_Dbg( p_stream, "read box: \"gnre\" genre=%i", p_gnre->i_genre );
1519 MP4_READBOX_EXIT( 1 );
1522 static int MP4_ReadBox_trkn( stream_t *p_stream, MP4_Box_t *p_box )
1524 MP4_Box_data_trkn_t *p_trkn;
1525 MP4_READBOX_ENTER( MP4_Box_data_trkn_t );
1527 p_trkn = p_box->data.p_trkn;
1529 uint32_t i_data_len;
1530 uint32_t i_data_tag;
1532 MP4_GET4BYTES( i_data_len );
1533 MP4_GETFOURCC( i_data_tag );
1534 if( i_data_len < 12 || i_data_tag != ATOM_data )
1535 MP4_READBOX_EXIT( 0 );
1538 uint32_t i_reserved;
1539 MP4_GET4BYTES( i_version );
1540 MP4_GET4BYTES( i_reserved );
1541 MP4_GET2BYTES( i_reserved );
1542 MP4_GET2BYTES( p_trkn->i_track_number );
1544 msg_Dbg( p_stream, "read box: \"trkn\" number=%i", p_trkn->i_track_number );
1546 if( i_data_len > 15 )
1548 MP4_GET2BYTES( p_trkn->i_track_total );
1550 msg_Dbg( p_stream, "read box: \"trkn\" total=%i", p_trkn->i_track_total );
1554 MP4_READBOX_EXIT( 1 );
1558 static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
1560 MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t );
1561 p_box->data.p_sample_soun->p_qt_description = NULL;
1563 /* Sanity check needed because the "wave" box does also contain an
1564 * "mp4a" box that we don't understand. */
1568 MP4_READBOX_EXIT( 1 );
1571 for( unsigned i = 0; i < 6 ; i++ )
1573 MP4_GET1BYTE( p_box->data.p_sample_soun->i_reserved1[i] );
1576 MP4_GET2BYTES( p_box->data.p_sample_soun->i_data_reference_index );
1579 * XXX hack -> produce a copy of the nearly complete chunk
1581 p_box->data.p_sample_soun->i_qt_description = 0;
1582 p_box->data.p_sample_soun->p_qt_description = NULL;
1585 p_box->data.p_sample_soun->p_qt_description = malloc( i_read );
1586 if( p_box->data.p_sample_soun->p_qt_description )
1588 p_box->data.p_sample_soun->i_qt_description = i_read;
1589 memcpy( p_box->data.p_sample_soun->p_qt_description, p_peek, i_read );
1593 MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_version );
1594 MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_revision_level );
1595 MP4_GET4BYTES( p_box->data.p_sample_soun->i_qt_vendor );
1597 MP4_GET2BYTES( p_box->data.p_sample_soun->i_channelcount );
1598 MP4_GET2BYTES( p_box->data.p_sample_soun->i_samplesize );
1599 MP4_GET2BYTES( p_box->data.p_sample_soun->i_predefined );
1600 MP4_GET2BYTES( p_box->data.p_sample_soun->i_reserved3 );
1601 MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratehi );
1602 MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratelo );
1604 if( p_box->data.p_sample_soun->i_qt_version == 1 && i_read >= 16 )
1606 /* SoundDescriptionV1 */
1607 MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
1608 MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_packet );
1609 MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_frame );
1610 MP4_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_sample );
1614 "read box: \"soun\" qt3+ sample/packet=%d bytes/packet=%d "
1615 "bytes/frame=%d bytes/sample=%d",
1616 p_box->data.p_sample_soun->i_sample_per_packet,
1617 p_box->data.p_sample_soun->i_bytes_per_packet,
1618 p_box->data.p_sample_soun->i_bytes_per_frame,
1619 p_box->data.p_sample_soun->i_bytes_per_sample );
1621 stream_Seek( p_stream, p_box->i_pos +
1622 mp4_box_headersize( p_box ) + 44 );
1624 else if( p_box->data.p_sample_soun->i_qt_version == 2 && i_read >= 36 )
1626 /* SoundDescriptionV2 */
1627 double f_sample_rate;
1631 MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
1632 MP4_GET8BYTES( dummy );
1633 memcpy( &f_sample_rate, &dummy, 8 );
1635 msg_Dbg( p_stream, "read box: %f Hz", f_sample_rate );
1636 p_box->data.p_sample_soun->i_sampleratehi = (int)f_sample_rate % 65536;
1637 p_box->data.p_sample_soun->i_sampleratelo = f_sample_rate / 65536;
1639 MP4_GET4BYTES( i_channel );
1640 p_box->data.p_sample_soun->i_channelcount = i_channel;
1643 msg_Dbg( p_stream, "read box: \"soun\" V2" );
1645 stream_Seek( p_stream, p_box->i_pos +
1646 mp4_box_headersize( p_box ) + 28 + 36 );
1650 p_box->data.p_sample_soun->i_sample_per_packet = 0;
1651 p_box->data.p_sample_soun->i_bytes_per_packet = 0;
1652 p_box->data.p_sample_soun->i_bytes_per_frame = 0;
1653 p_box->data.p_sample_soun->i_bytes_per_sample = 0;
1656 msg_Dbg( p_stream, "read box: \"soun\" mp4 or qt1/2 (rest=%"PRId64")",
1659 stream_Seek( p_stream, p_box->i_pos +
1660 mp4_box_headersize( p_box ) + 28 );
1663 if( p_box->i_type == ATOM_drms )
1665 msg_Warn( p_stream, "DRM protected streams are not supported." );
1666 MP4_READBOX_EXIT( 0 );
1669 if( p_box->i_type == ATOM_samr || p_box->i_type == ATOM_sawb )
1671 /* Ignore channelcount for AMR (3gpp AMRSpecificBox) */
1672 p_box->data.p_sample_soun->i_channelcount = 1;
1675 MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds/wave/... */
1678 msg_Dbg( p_stream, "read box: \"soun\" in stsd channel %d "
1679 "sample size %d sample rate %f",
1680 p_box->data.p_sample_soun->i_channelcount,
1681 p_box->data.p_sample_soun->i_samplesize,
1682 (float)p_box->data.p_sample_soun->i_sampleratehi +
1683 (float)p_box->data.p_sample_soun->i_sampleratelo / 65536 );
1686 MP4_READBOX_EXIT( 1 );
1690 static void MP4_FreeBox_sample_soun( MP4_Box_t *p_box )
1692 FREENULL( p_box->data.p_sample_soun->p_qt_description );
1696 int MP4_ReadBox_sample_vide( stream_t *p_stream, MP4_Box_t *p_box )
1698 MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t );
1700 for( unsigned i = 0; i < 6 ; i++ )
1702 MP4_GET1BYTE( p_box->data.p_sample_vide->i_reserved1[i] );
1705 MP4_GET2BYTES( p_box->data.p_sample_vide->i_data_reference_index );
1708 * XXX hack -> produce a copy of the nearly complete chunk
1712 p_box->data.p_sample_vide->p_qt_image_description = malloc( i_read );
1713 if( unlikely( p_box->data.p_sample_vide->p_qt_image_description == NULL ) )
1714 MP4_READBOX_EXIT( 0 );
1715 p_box->data.p_sample_vide->i_qt_image_description = i_read;
1716 memcpy( p_box->data.p_sample_vide->p_qt_image_description,
1721 p_box->data.p_sample_vide->i_qt_image_description = 0;
1722 p_box->data.p_sample_vide->p_qt_image_description = NULL;
1725 MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_version );
1726 MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_revision_level );
1727 MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_vendor );
1729 MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_temporal_quality );
1730 MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_spatial_quality );
1732 MP4_GET2BYTES( p_box->data.p_sample_vide->i_width );
1733 MP4_GET2BYTES( p_box->data.p_sample_vide->i_height );
1735 MP4_GET4BYTES( p_box->data.p_sample_vide->i_horizresolution );
1736 MP4_GET4BYTES( p_box->data.p_sample_vide->i_vertresolution );
1738 MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_data_size );
1739 MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_frame_count );
1741 memcpy( &p_box->data.p_sample_vide->i_compressorname, p_peek, 32 );
1742 p_peek += 32; i_read -= 32;
1744 MP4_GET2BYTES( p_box->data.p_sample_vide->i_depth );
1745 MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_color_table );
1747 stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 78);
1749 if( p_box->i_type == ATOM_drmi )
1751 msg_Warn( p_stream, "DRM protected streams are not supported." );
1752 MP4_READBOX_EXIT( 0 );
1755 MP4_ReadBoxContainerRaw( p_stream, p_box );
1758 msg_Dbg( p_stream, "read box: \"vide\" in stsd %dx%d depth %d",
1759 p_box->data.p_sample_vide->i_width,
1760 p_box->data.p_sample_vide->i_height,
1761 p_box->data.p_sample_vide->i_depth );
1764 MP4_READBOX_EXIT( 1 );
1768 void MP4_FreeBox_sample_vide( MP4_Box_t *p_box )
1770 FREENULL( p_box->data.p_sample_vide->p_qt_image_description );
1773 static int MP4_ReadBox_sample_mp4s( stream_t *p_stream, MP4_Box_t *p_box )
1775 stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
1776 MP4_ReadBoxContainerRaw( p_stream, p_box );
1780 static int MP4_ReadBox_sample_text( stream_t *p_stream, MP4_Box_t *p_box )
1784 MP4_READBOX_ENTER( MP4_Box_data_sample_text_t );
1786 MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved1 );
1787 MP4_GET2BYTES( p_box->data.p_sample_text->i_reserved2 );
1789 MP4_GET2BYTES( p_box->data.p_sample_text->i_data_reference_index );
1791 MP4_GET4BYTES( p_box->data.p_sample_text->i_display_flags );
1796 /* FIXME search right signification */
1798 p_box->data.p_sample_text->i_justification_horizontal = 1;
1799 p_box->data.p_sample_text->i_justification_vertical = 1;
1801 case -1: // Flush Right
1802 p_box->data.p_sample_text->i_justification_horizontal = -1;
1803 p_box->data.p_sample_text->i_justification_vertical = -1;
1805 case -2: // Flush Left
1806 p_box->data.p_sample_text->i_justification_horizontal = 0;
1807 p_box->data.p_sample_text->i_justification_vertical = 0;
1809 case 0: // Flush Default
1811 p_box->data.p_sample_text->i_justification_horizontal = 1;
1812 p_box->data.p_sample_text->i_justification_vertical = -1;
1816 MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[0] );
1817 MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[1] );
1818 MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[2] );
1819 p_box->data.p_sample_text->i_background_color[3] = 0;
1821 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_top );
1822 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_left );
1823 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_bottom );
1824 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_right );
1827 msg_Dbg( p_stream, "read box: \"text\" in stsd text" );
1829 MP4_READBOX_EXIT( 1 );
1832 static int MP4_ReadBox_sample_tx3g( stream_t *p_stream, MP4_Box_t *p_box )
1834 MP4_READBOX_ENTER( MP4_Box_data_sample_text_t );
1836 MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved1 );
1837 MP4_GET2BYTES( p_box->data.p_sample_text->i_reserved2 );
1839 MP4_GET2BYTES( p_box->data.p_sample_text->i_data_reference_index );
1841 MP4_GET4BYTES( p_box->data.p_sample_text->i_display_flags );
1843 MP4_GET1BYTE ( p_box->data.p_sample_text->i_justification_horizontal );
1844 MP4_GET1BYTE ( p_box->data.p_sample_text->i_justification_vertical );
1846 MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[0] );
1847 MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[1] );
1848 MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[2] );
1849 MP4_GET1BYTE ( p_box->data.p_sample_text->i_background_color[3] );
1851 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_top );
1852 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_left );
1853 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_bottom );
1854 MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_right );
1857 msg_Dbg( p_stream, "read box: \"tx3g\" in stsd text" );
1859 MP4_READBOX_EXIT( 1 );
1864 /* We can't easily call it, and anyway ~ 20 bytes lost isn't a real problem */
1865 static void MP4_FreeBox_sample_text( MP4_Box_t *p_box )
1867 FREENULL( p_box->data.p_sample_text->psz_text_name );
1872 static int MP4_ReadBox_stsd( stream_t *p_stream, MP4_Box_t *p_box )
1875 MP4_READBOX_ENTER( MP4_Box_data_stsd_t );
1877 MP4_GETVERSIONFLAGS( p_box->data.p_stsd );
1879 MP4_GET4BYTES( p_box->data.p_stsd->i_entry_count );
1881 stream_Seek( p_stream, p_box->i_pos + mp4_box_headersize( p_box ) + 8 );
1883 MP4_ReadBoxContainerRaw( p_stream, p_box );
1886 msg_Dbg( p_stream, "read box: \"stsd\" entry-count %d",
1887 p_box->data.p_stsd->i_entry_count );
1890 MP4_READBOX_EXIT( 1 );
1894 static int MP4_ReadBox_stsz( stream_t *p_stream, MP4_Box_t *p_box )
1896 MP4_READBOX_ENTER( MP4_Box_data_stsz_t );
1898 MP4_GETVERSIONFLAGS( p_box->data.p_stsz );
1900 MP4_GET4BYTES( p_box->data.p_stsz->i_sample_size );
1901 MP4_GET4BYTES( p_box->data.p_stsz->i_sample_count );
1903 if( p_box->data.p_stsz->i_sample_size == 0 )
1905 p_box->data.p_stsz->i_entry_size =
1906 calloc( p_box->data.p_stsz->i_sample_count, sizeof(uint32_t) );
1907 if( unlikely( !p_box->data.p_stsz->i_entry_size ) )
1908 MP4_READBOX_EXIT( 0 );
1910 for( unsigned int i = 0; (i<p_box->data.p_stsz->i_sample_count)&&(i_read >= 4 ); i++ )
1912 MP4_GET4BYTES( p_box->data.p_stsz->i_entry_size[i] );
1916 p_box->data.p_stsz->i_entry_size = NULL;
1919 msg_Dbg( p_stream, "read box: \"stsz\" sample-size %d sample-count %d",
1920 p_box->data.p_stsz->i_sample_size,
1921 p_box->data.p_stsz->i_sample_count );
1924 MP4_READBOX_EXIT( 1 );
1927 static void MP4_FreeBox_stsz( MP4_Box_t *p_box )
1929 FREENULL( p_box->data.p_stsz->i_entry_size );
1932 static void MP4_FreeBox_stsc( MP4_Box_t *p_box )
1934 FREENULL( p_box->data.p_stsc->i_first_chunk );
1935 FREENULL( p_box->data.p_stsc->i_samples_per_chunk );
1936 FREENULL( p_box->data.p_stsc->i_sample_description_index );
1939 static int MP4_ReadBox_stsc( stream_t *p_stream, MP4_Box_t *p_box )
1941 MP4_READBOX_ENTER( MP4_Box_data_stsc_t );
1943 MP4_GETVERSIONFLAGS( p_box->data.p_stsc );
1945 MP4_GET4BYTES( p_box->data.p_stsc->i_entry_count );
1947 p_box->data.p_stsc->i_first_chunk =
1948 calloc( p_box->data.p_stsc->i_entry_count, sizeof(uint32_t) );
1949 p_box->data.p_stsc->i_samples_per_chunk =
1950 calloc( p_box->data.p_stsc->i_entry_count, sizeof(uint32_t) );
1951 p_box->data.p_stsc->i_sample_description_index =
1952 calloc( p_box->data.p_stsc->i_entry_count, sizeof(uint32_t) );
1953 if( unlikely( p_box->data.p_stsc->i_first_chunk == NULL
1954 || p_box->data.p_stsc->i_samples_per_chunk == NULL
1955 || p_box->data.p_stsc->i_sample_description_index == NULL ) )
1957 MP4_READBOX_EXIT( 0 );
1960 for( unsigned int i = 0; (i < p_box->data.p_stsc->i_entry_count )&&( i_read >= 12 );i++ )
1962 MP4_GET4BYTES( p_box->data.p_stsc->i_first_chunk[i] );
1963 MP4_GET4BYTES( p_box->data.p_stsc->i_samples_per_chunk[i] );
1964 MP4_GET4BYTES( p_box->data.p_stsc->i_sample_description_index[i] );
1968 msg_Dbg( p_stream, "read box: \"stsc\" entry-count %d",
1969 p_box->data.p_stsc->i_entry_count );
1972 MP4_READBOX_EXIT( 1 );
1975 static int MP4_ReadBox_stco_co64( stream_t *p_stream, MP4_Box_t *p_box )
1977 MP4_READBOX_ENTER( MP4_Box_data_co64_t );
1979 MP4_GETVERSIONFLAGS( p_box->data.p_co64 );
1981 MP4_GET4BYTES( p_box->data.p_co64->i_entry_count );
1983 p_box->data.p_co64->i_chunk_offset =
1984 calloc( p_box->data.p_co64->i_entry_count, sizeof(uint64_t) );
1985 if( p_box->data.p_co64->i_chunk_offset == NULL )
1986 MP4_READBOX_EXIT( 0 );
1988 for( unsigned int i = 0; i < p_box->data.p_co64->i_entry_count; i++ )
1990 if( p_box->i_type == ATOM_stco )
1996 MP4_GET4BYTES( p_box->data.p_co64->i_chunk_offset[i] );
2004 MP4_GET8BYTES( p_box->data.p_co64->i_chunk_offset[i] );
2009 msg_Dbg( p_stream, "read box: \"co64\" entry-count %d",
2010 p_box->data.p_co64->i_entry_count );
2013 MP4_READBOX_EXIT( 1 );
2016 static void MP4_FreeBox_stco_co64( MP4_Box_t *p_box )
2018 FREENULL( p_box->data.p_co64->i_chunk_offset );
2021 static int MP4_ReadBox_stss( stream_t *p_stream, MP4_Box_t *p_box )
2023 MP4_READBOX_ENTER( MP4_Box_data_stss_t );
2025 MP4_GETVERSIONFLAGS( p_box->data.p_stss );
2027 MP4_GET4BYTES( p_box->data.p_stss->i_entry_count );
2029 p_box->data.p_stss->i_sample_number =
2030 calloc( p_box->data.p_stss->i_entry_count, sizeof(uint32_t) );
2031 if( unlikely( p_box->data.p_stss->i_sample_number == NULL ) )
2032 MP4_READBOX_EXIT( 0 );
2034 for( unsigned int i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 4 ); i++ )
2037 MP4_GET4BYTES( p_box->data.p_stss->i_sample_number[i] );
2038 /* XXX in libmp4 sample begin at 0 */
2039 p_box->data.p_stss->i_sample_number[i]--;
2043 msg_Dbg( p_stream, "read box: \"stss\" entry-count %d",
2044 p_box->data.p_stss->i_entry_count );
2047 MP4_READBOX_EXIT( 1 );
2050 static void MP4_FreeBox_stss( MP4_Box_t *p_box )
2052 FREENULL( p_box->data.p_stss->i_sample_number );
2055 static void MP4_FreeBox_stsh( MP4_Box_t *p_box )
2057 FREENULL( p_box->data.p_stsh->i_shadowed_sample_number );
2058 FREENULL( p_box->data.p_stsh->i_sync_sample_number );
2061 static int MP4_ReadBox_stsh( stream_t *p_stream, MP4_Box_t *p_box )
2063 MP4_READBOX_ENTER( MP4_Box_data_stsh_t );
2065 MP4_GETVERSIONFLAGS( p_box->data.p_stsh );
2068 MP4_GET4BYTES( p_box->data.p_stsh->i_entry_count );
2070 p_box->data.p_stsh->i_shadowed_sample_number =
2071 calloc( p_box->data.p_stsh->i_entry_count, sizeof(uint32_t) );
2072 p_box->data.p_stsh->i_sync_sample_number =
2073 calloc( p_box->data.p_stsh->i_entry_count, sizeof(uint32_t) );
2075 if( p_box->data.p_stsh->i_shadowed_sample_number == NULL
2076 || p_box->data.p_stsh->i_sync_sample_number == NULL )
2078 MP4_READBOX_EXIT( 0 );
2081 for( unsigned i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 8 ); i++ )
2083 MP4_GET4BYTES( p_box->data.p_stsh->i_shadowed_sample_number[i] );
2084 MP4_GET4BYTES( p_box->data.p_stsh->i_sync_sample_number[i] );
2088 msg_Dbg( p_stream, "read box: \"stsh\" entry-count %d",
2089 p_box->data.p_stsh->i_entry_count );
2091 MP4_READBOX_EXIT( 1 );
2095 static int MP4_ReadBox_stdp( stream_t *p_stream, MP4_Box_t *p_box )
2097 MP4_READBOX_ENTER( MP4_Box_data_stdp_t );
2099 MP4_GETVERSIONFLAGS( p_box->data.p_stdp );
2101 p_box->data.p_stdp->i_priority =
2102 calloc( i_read / 2, sizeof(uint16_t) );
2104 if( unlikely( !p_box->data.p_stdp->i_priority ) )
2105 MP4_READBOX_EXIT( 0 );
2107 for( unsigned i = 0; i < i_read / 2 ; i++ )
2109 MP4_GET2BYTES( p_box->data.p_stdp->i_priority[i] );
2113 msg_Dbg( p_stream, "read box: \"stdp\" entry-count %"PRId64,
2117 MP4_READBOX_EXIT( 1 );
2120 static void MP4_FreeBox_stdp( MP4_Box_t *p_box )
2122 FREENULL( p_box->data.p_stdp->i_priority );
2125 static void MP4_FreeBox_padb( MP4_Box_t *p_box )
2127 FREENULL( p_box->data.p_padb->i_reserved1 );
2128 FREENULL( p_box->data.p_padb->i_pad2 );
2129 FREENULL( p_box->data.p_padb->i_reserved2 );
2130 FREENULL( p_box->data.p_padb->i_pad1 );
2133 static int MP4_ReadBox_padb( stream_t *p_stream, MP4_Box_t *p_box )
2137 MP4_READBOX_ENTER( MP4_Box_data_padb_t );
2139 MP4_GETVERSIONFLAGS( p_box->data.p_padb );
2141 MP4_GET4BYTES( p_box->data.p_padb->i_sample_count );
2142 count = (p_box->data.p_padb->i_sample_count + 1) / 2;
2144 p_box->data.p_padb->i_reserved1 = calloc( count, sizeof(uint16_t) );
2145 p_box->data.p_padb->i_pad2 = calloc( count, sizeof(uint16_t) );
2146 p_box->data.p_padb->i_reserved2 = calloc( count, sizeof(uint16_t) );
2147 p_box->data.p_padb->i_pad1 = calloc( count, sizeof(uint16_t) );
2148 if( p_box->data.p_padb->i_reserved1 == NULL
2149 || p_box->data.p_padb->i_pad2 == NULL
2150 || p_box->data.p_padb->i_reserved2 == NULL
2151 || p_box->data.p_padb->i_pad1 == NULL )
2153 MP4_READBOX_EXIT( 0 );
2156 for( unsigned int i = 0; i < i_read / 2 ; i++ )
2160 MP4_READBOX_EXIT( 0 );
2162 p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 7 )&0x01;
2163 p_box->data.p_padb->i_pad2[i] = ( (*p_peek) >> 4 )&0x07;
2164 p_box->data.p_padb->i_reserved1[i] = ( (*p_peek) >> 3 )&0x01;
2165 p_box->data.p_padb->i_pad1[i] = ( (*p_peek) )&0x07;
2167 p_peek += 1; i_read -= 1;
2171 msg_Dbg( p_stream, "read box: \"stdp\" entry-count %"PRId64,
2175 MP4_READBOX_EXIT( 1 );
2178 static void MP4_FreeBox_elst( MP4_Box_t *p_box )
2180 FREENULL( p_box->data.p_elst->i_segment_duration );
2181 FREENULL( p_box->data.p_elst->i_media_time );
2182 FREENULL( p_box->data.p_elst->i_media_rate_integer );
2183 FREENULL( p_box->data.p_elst->i_media_rate_fraction );
2186 static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box )
2188 MP4_READBOX_ENTER( MP4_Box_data_elst_t );
2190 MP4_GETVERSIONFLAGS( p_box->data.p_elst );
2193 MP4_GET4BYTES( p_box->data.p_elst->i_entry_count );
2195 p_box->data.p_elst->i_segment_duration =
2196 calloc( p_box->data.p_elst->i_entry_count, sizeof(uint64_t) );
2197 p_box->data.p_elst->i_media_time =
2198 calloc( p_box->data.p_elst->i_entry_count, sizeof(uint64_t) );
2199 p_box->data.p_elst->i_media_rate_integer =
2200 calloc( p_box->data.p_elst->i_entry_count, sizeof(uint16_t) );
2201 p_box->data.p_elst->i_media_rate_fraction =
2202 calloc( p_box->data.p_elst->i_entry_count, sizeof(uint16_t) );
2203 if( p_box->data.p_elst->i_segment_duration == NULL
2204 || p_box->data.p_elst->i_media_time == NULL
2205 || p_box->data.p_elst->i_media_rate_integer == NULL
2206 || p_box->data.p_elst->i_media_rate_fraction == NULL )
2208 MP4_READBOX_EXIT( 0 );
2212 for( unsigned i = 0; i < p_box->data.p_elst->i_entry_count; i++ )
2214 if( p_box->data.p_elst->i_version == 1 )
2217 MP4_GET8BYTES( p_box->data.p_elst->i_segment_duration[i] );
2219 MP4_GET8BYTES( p_box->data.p_elst->i_media_time[i] );
2224 MP4_GET4BYTES( p_box->data.p_elst->i_segment_duration[i] );
2226 MP4_GET4BYTES( p_box->data.p_elst->i_media_time[i] );
2227 p_box->data.p_elst->i_media_time[i] = (int32_t)p_box->data.p_elst->i_media_time[i];
2230 MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_integer[i] );
2231 MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_fraction[i] );
2235 msg_Dbg( p_stream, "read box: \"elst\" entry-count %lu",
2236 (unsigned long)p_box->data.p_elst->i_entry_count );
2238 MP4_READBOX_EXIT( 1 );
2241 static int MP4_ReadBox_cprt( stream_t *p_stream, MP4_Box_t *p_box )
2243 unsigned int i_language;
2245 MP4_READBOX_ENTER( MP4_Box_data_cprt_t );
2247 MP4_GETVERSIONFLAGS( p_box->data.p_cprt );
2249 i_language = GetWBE( p_peek );
2250 for( unsigned i = 0; i < 3; i++ )
2252 p_box->data.p_cprt->i_language[i] =
2253 ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
2255 p_peek += 2; i_read -= 2;
2256 MP4_GETSTRINGZ( p_box->data.p_cprt->psz_notice );
2259 msg_Dbg( p_stream, "read box: \"cprt\" language %c%c%c notice %s",
2260 p_box->data.p_cprt->i_language[0],
2261 p_box->data.p_cprt->i_language[1],
2262 p_box->data.p_cprt->i_language[2],
2263 p_box->data.p_cprt->psz_notice );
2266 MP4_READBOX_EXIT( 1 );
2269 static void MP4_FreeBox_cprt( MP4_Box_t *p_box )
2271 FREENULL( p_box->data.p_cprt->psz_notice );
2275 static int MP4_ReadBox_dcom( stream_t *p_stream, MP4_Box_t *p_box )
2277 MP4_READBOX_ENTER( MP4_Box_data_dcom_t );
2279 MP4_GETFOURCC( p_box->data.p_dcom->i_algorithm );
2282 "read box: \"dcom\" compression algorithm : %4.4s",
2283 (char*)&p_box->data.p_dcom->i_algorithm );
2285 MP4_READBOX_EXIT( 1 );
2288 static int MP4_ReadBox_cmvd( stream_t *p_stream, MP4_Box_t *p_box )
2290 MP4_READBOX_ENTER( MP4_Box_data_cmvd_t );
2292 MP4_GET4BYTES( p_box->data.p_cmvd->i_uncompressed_size );
2294 p_box->data.p_cmvd->i_compressed_size = i_read;
2296 if( !( p_box->data.p_cmvd->p_data = malloc( i_read ) ) )
2297 MP4_READBOX_EXIT( 0 );
2299 /* now copy compressed data */
2300 memcpy( p_box->data.p_cmvd->p_data, p_peek,i_read);
2302 p_box->data.p_cmvd->b_compressed = 1;
2305 msg_Dbg( p_stream, "read box: \"cmvd\" compressed data size %d",
2306 p_box->data.p_cmvd->i_compressed_size );
2309 MP4_READBOX_EXIT( 1 );
2311 static void MP4_FreeBox_cmvd( MP4_Box_t *p_box )
2313 FREENULL( p_box->data.p_cmvd->p_data );
2317 static int MP4_ReadBox_cmov( stream_t *p_stream, MP4_Box_t *p_box )
2323 stream_t *p_stream_memory;
2329 if( !( p_box->data.p_cmov = calloc(1, sizeof( MP4_Box_data_cmov_t ) ) ) )
2332 if( !p_box->p_father ||
2333 ( p_box->p_father->i_type != ATOM_moov &&
2334 p_box->p_father->i_type != ATOM_foov ) )
2336 msg_Warn( p_stream, "Read box: \"cmov\" box alone" );
2340 if( !MP4_ReadBoxContainer( p_stream, p_box ) )
2345 if( ( p_dcom = MP4_BoxGet( p_box, "dcom" ) ) == NULL ||
2346 ( p_cmvd = MP4_BoxGet( p_box, "cmvd" ) ) == NULL ||
2347 p_cmvd->data.p_cmvd->p_data == NULL )
2349 msg_Warn( p_stream, "read box: \"cmov\" incomplete" );
2353 if( p_dcom->data.p_dcom->i_algorithm != ATOM_zlib )
2355 msg_Dbg( p_stream, "read box: \"cmov\" compression algorithm : %4.4s "
2356 "not supported", (char*)&p_dcom->data.p_dcom->i_algorithm );
2361 msg_Dbg( p_stream, "read box: \"cmov\" zlib unsupported" );
2365 /* decompress data */
2366 /* allocate a new buffer */
2367 if( !( p_data = malloc( p_cmvd->data.p_cmvd->i_uncompressed_size ) ) )
2369 /* init default structures */
2370 z_data.next_in = p_cmvd->data.p_cmvd->p_data;
2371 z_data.avail_in = p_cmvd->data.p_cmvd->i_compressed_size;
2372 z_data.next_out = p_data;
2373 z_data.avail_out = p_cmvd->data.p_cmvd->i_uncompressed_size;
2374 z_data.zalloc = (alloc_func)Z_NULL;
2375 z_data.zfree = (free_func)Z_NULL;
2376 z_data.opaque = (voidpf)Z_NULL;
2379 if( inflateInit( &z_data ) != Z_OK )
2381 msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
2387 i_result = inflate( &z_data, Z_NO_FLUSH );
2388 if( i_result != Z_OK && i_result != Z_STREAM_END )
2390 msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
2395 if( p_cmvd->data.p_cmvd->i_uncompressed_size != z_data.total_out )
2397 msg_Warn( p_stream, "read box: \"cmov\" uncompressing data size "
2400 p_cmvd->data.p_cmvd->i_uncompressed_size = z_data.total_out;
2403 if( inflateEnd( &z_data ) != Z_OK )
2405 msg_Warn( p_stream, "read box: \"cmov\" error while uncompressing "
2409 free( p_cmvd->data.p_cmvd->p_data );
2410 p_cmvd->data.p_cmvd->p_data = p_data;
2411 p_cmvd->data.p_cmvd->b_compressed = 0;
2413 msg_Dbg( p_stream, "read box: \"cmov\" box successfully uncompressed" );
2415 /* now create a memory stream */
2417 stream_MemoryNew( VLC_OBJECT(p_stream), p_cmvd->data.p_cmvd->p_data,
2418 p_cmvd->data.p_cmvd->i_uncompressed_size, true );
2420 /* and read uncompressd moov */
2421 p_box->data.p_cmov->p_moov = MP4_ReadBox( p_stream_memory, NULL );
2423 stream_Delete( p_stream_memory );
2426 msg_Dbg( p_stream, "read box: \"cmov\" compressed movie header completed");
2429 return p_box->data.p_cmov->p_moov ? 1 : 0;
2430 #endif /* HAVE_ZLIB_H */
2433 static int MP4_ReadBox_rdrf( stream_t *p_stream, MP4_Box_t *p_box )
2436 MP4_READBOX_ENTER( MP4_Box_data_rdrf_t );
2438 MP4_GETVERSIONFLAGS( p_box->data.p_rdrf );
2439 MP4_GETFOURCC( p_box->data.p_rdrf->i_ref_type );
2440 MP4_GET4BYTES( i_len );
2445 p_box->data.p_rdrf->psz_ref = malloc( i_len );
2446 if( p_box->data.p_rdrf->psz_ref == NULL )
2447 MP4_READBOX_EXIT( 0 );
2450 for( unsigned i = 0; i < i_len; i++ )
2452 MP4_GET1BYTE( p_box->data.p_rdrf->psz_ref[i] );
2454 p_box->data.p_rdrf->psz_ref[i_len] = '\0';
2458 p_box->data.p_rdrf->psz_ref = NULL;
2463 "read box: \"rdrf\" type:%4.4s ref %s",
2464 (char*)&p_box->data.p_rdrf->i_ref_type,
2465 p_box->data.p_rdrf->psz_ref );
2467 MP4_READBOX_EXIT( 1 );
2470 static void MP4_FreeBox_rdrf( MP4_Box_t *p_box )
2472 FREENULL( p_box->data.p_rdrf->psz_ref );
2476 static int MP4_ReadBox_rmdr( stream_t *p_stream, MP4_Box_t *p_box )
2478 MP4_READBOX_ENTER( MP4_Box_data_rmdr_t );
2480 MP4_GETVERSIONFLAGS( p_box->data.p_rmdr );
2482 MP4_GET4BYTES( p_box->data.p_rmdr->i_rate );
2486 "read box: \"rmdr\" rate:%d",
2487 p_box->data.p_rmdr->i_rate );
2489 MP4_READBOX_EXIT( 1 );
2492 static int MP4_ReadBox_rmqu( stream_t *p_stream, MP4_Box_t *p_box )
2494 MP4_READBOX_ENTER( MP4_Box_data_rmqu_t );
2496 MP4_GET4BYTES( p_box->data.p_rmqu->i_quality );
2500 "read box: \"rmqu\" quality:%d",
2501 p_box->data.p_rmqu->i_quality );
2503 MP4_READBOX_EXIT( 1 );
2506 static int MP4_ReadBox_rmvc( stream_t *p_stream, MP4_Box_t *p_box )
2508 MP4_READBOX_ENTER( MP4_Box_data_rmvc_t );
2509 MP4_GETVERSIONFLAGS( p_box->data.p_rmvc );
2511 MP4_GETFOURCC( p_box->data.p_rmvc->i_gestaltType );
2512 MP4_GET4BYTES( p_box->data.p_rmvc->i_val1 );
2513 MP4_GET4BYTES( p_box->data.p_rmvc->i_val2 );
2514 MP4_GET2BYTES( p_box->data.p_rmvc->i_checkType );
2518 "read box: \"rmvc\" gestaltType:%4.4s val1:0x%x val2:0x%x checkType:0x%x",
2519 (char*)&p_box->data.p_rmvc->i_gestaltType,
2520 p_box->data.p_rmvc->i_val1,p_box->data.p_rmvc->i_val2,
2521 p_box->data.p_rmvc->i_checkType );
2524 MP4_READBOX_EXIT( 1 );
2527 static int MP4_ReadBox_frma( stream_t *p_stream, MP4_Box_t *p_box )
2529 MP4_READBOX_ENTER( MP4_Box_data_frma_t );
2531 MP4_GETFOURCC( p_box->data.p_frma->i_type );
2534 msg_Dbg( p_stream, "read box: \"frma\" i_type:%4.4s",
2535 (char *)&p_box->data.p_frma->i_type );
2538 MP4_READBOX_EXIT( 1 );
2541 static int MP4_ReadBox_skcr( stream_t *p_stream, MP4_Box_t *p_box )
2543 MP4_READBOX_ENTER( MP4_Box_data_skcr_t );
2545 MP4_GET4BYTES( p_box->data.p_skcr->i_init );
2546 MP4_GET4BYTES( p_box->data.p_skcr->i_encr );
2547 MP4_GET4BYTES( p_box->data.p_skcr->i_decr );
2550 msg_Dbg( p_stream, "read box: \"skcr\" i_init:%d i_encr:%d i_decr:%d",
2551 p_box->data.p_skcr->i_init,
2552 p_box->data.p_skcr->i_encr,
2553 p_box->data.p_skcr->i_decr );
2556 MP4_READBOX_EXIT( 1 );
2559 static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box )
2562 /* ATOMs 'user', 'key', 'iviv', and 'priv' will be skipped,
2563 * so unless data decrypt itself by magic, there will be no playback,
2564 * but we never know... */
2565 msg_Warn( p_stream, "DRM protected streams are not supported." );
2569 static int MP4_ReadBox_name( stream_t *p_stream, MP4_Box_t *p_box )
2571 MP4_READBOX_ENTER( MP4_Box_data_name_t );
2573 p_box->data.p_name->psz_text = malloc( p_box->i_size + 1 - 8 ); /* +\0, -name, -size */
2574 if( p_box->data.p_name->psz_text == NULL )
2575 MP4_READBOX_EXIT( 0 );
2577 memcpy( p_box->data.p_name->psz_text, p_peek, p_box->i_size - 8 );
2578 p_box->data.p_name->psz_text[p_box->i_size - 8] = '\0';
2581 msg_Dbg( p_stream, "read box: \"name\" text=`%s'",
2582 p_box->data.p_name->psz_text );
2584 MP4_READBOX_EXIT( 1 );
2587 static void MP4_FreeBox_name( MP4_Box_t *p_box )
2589 FREENULL( p_box->data.p_name->psz_text );
2592 static int MP4_ReadBox_0xa9xxx( stream_t *p_stream, MP4_Box_t *p_box )
2596 MP4_READBOX_ENTER( MP4_Box_data_0xa9xxx_t );
2598 p_box->data.p_0xa9xxx->psz_text = NULL;
2600 MP4_GET2BYTES( i16 );
2606 MP4_GET2BYTES( i16 );
2607 if( i_length >= i_read ) i_length = i_read + 1;
2609 p_box->data.p_0xa9xxx->psz_text = malloc( i_length );
2610 if( p_box->data.p_0xa9xxx->psz_text == NULL )
2611 MP4_READBOX_EXIT( 0 );
2614 memcpy( p_box->data.p_0xa9xxx->psz_text,
2616 p_box->data.p_0xa9xxx->psz_text[i_length] = '\0';
2620 "read box: \"c%3.3s\" text=`%s'",
2621 ((char*)&p_box->i_type + 1),
2622 p_box->data.p_0xa9xxx->psz_text );
2627 /* try iTune/Quicktime format, rewind to start */
2628 p_peek -= 2; i_read += 2;
2629 // we are expecting a 'data' box
2630 uint32_t i_data_len;
2631 uint32_t i_data_tag;
2633 MP4_GET4BYTES( i_data_len );
2634 if( i_data_len > i_read ) i_data_len = i_read;
2635 MP4_GETFOURCC( i_data_tag );
2636 if( (i_data_len > 0) && (i_data_tag == ATOM_data) )
2638 /* data box contains a version/flags field */
2640 uint32_t i_reserved;
2641 MP4_GET4BYTES( i_version );
2642 MP4_GET4BYTES( i_reserved );
2643 // version should be 0, flags should be 1 for text, 0 for data
2644 if( ( i_version == 0x00000001 ) && (i_data_len >= 12 ) )
2646 // the rest is the text
2648 p_box->data.p_0xa9xxx->psz_text = malloc( i_data_len + 1 );
2649 if( p_box->data.p_0xa9xxx->psz_text == NULL )
2650 MP4_READBOX_EXIT( 0 );
2652 memcpy( p_box->data.p_0xa9xxx->psz_text,
2653 p_peek, i_data_len );
2654 p_box->data.p_0xa9xxx->psz_text[i_data_len] = '\0';
2657 "read box: \"c%3.3s\" text=`%s'",
2658 ((char*)&p_box->i_type+1),
2659 p_box->data.p_0xa9xxx->psz_text );
2664 // TODO: handle data values for ID3 tag values, track num or cover art,etc...
2669 MP4_READBOX_EXIT( 1 );
2671 static void MP4_FreeBox_0xa9xxx( MP4_Box_t *p_box )
2673 FREENULL( p_box->data.p_0xa9xxx->psz_text );
2676 /* Chapter support */
2677 static void MP4_FreeBox_chpl( MP4_Box_t *p_box )
2679 MP4_Box_data_chpl_t *p_chpl = p_box->data.p_chpl;
2680 for( unsigned i = 0; i < p_chpl->i_chapter; i++ )
2681 free( p_chpl->chapter[i].psz_name );
2684 static int MP4_ReadBox_chpl( stream_t *p_stream, MP4_Box_t *p_box )
2686 MP4_Box_data_chpl_t *p_chpl;
2689 MP4_READBOX_ENTER( MP4_Box_data_chpl_t );
2691 p_chpl = p_box->data.p_chpl;
2693 MP4_GETVERSIONFLAGS( p_chpl );
2695 MP4_GET4BYTES( i_dummy );
2697 MP4_GET1BYTE( p_chpl->i_chapter );
2699 for( i = 0; i < p_chpl->i_chapter; i++ )
2704 MP4_GET8BYTES( i_start );
2705 MP4_GET1BYTE( i_len );
2707 p_chpl->chapter[i].psz_name = malloc( i_len + 1 );
2708 if( !p_chpl->chapter[i].psz_name )
2709 MP4_READBOX_EXIT( 0 );
2711 i_copy = __MIN( i_len, i_read );
2713 memcpy( p_chpl->chapter[i].psz_name, p_peek, i_copy );
2714 p_chpl->chapter[i].psz_name[i_copy] = '\0';
2715 p_chpl->chapter[i].i_start = i_start;
2720 /* Bubble sort by increasing start date */
2723 for( i = 0; i < p_chpl->i_chapter - 1; i++ )
2725 if( p_chpl->chapter[i].i_start > p_chpl->chapter[i+1].i_start )
2727 char *psz = p_chpl->chapter[i+1].psz_name;
2728 int64_t i64 = p_chpl->chapter[i+1].i_start;
2730 p_chpl->chapter[i+1].psz_name = p_chpl->chapter[i].psz_name;
2731 p_chpl->chapter[i+1].i_start = p_chpl->chapter[i].i_start;
2733 p_chpl->chapter[i].psz_name = psz;
2734 p_chpl->chapter[i].i_start = i64;
2743 msg_Dbg( p_stream, "read box: \"chpl\" %d chapters",
2744 p_chpl->i_chapter );
2746 MP4_READBOX_EXIT( 1 );
2749 static int MP4_ReadBox_tref_generic( stream_t *p_stream, MP4_Box_t *p_box )
2751 MP4_READBOX_ENTER( MP4_Box_data_tref_generic_t );
2753 p_box->data.p_tref_generic->i_track_ID = NULL;
2754 p_box->data.p_tref_generic->i_entry_count = i_read / sizeof(uint32_t);
2755 if( p_box->data.p_tref_generic->i_entry_count > 0 )
2756 p_box->data.p_tref_generic->i_track_ID = calloc( p_box->data.p_tref_generic->i_entry_count, sizeof(uint32_t) );
2757 if( p_box->data.p_tref_generic->i_track_ID == NULL )
2758 MP4_READBOX_EXIT( 0 );
2760 for( unsigned i = 0; i < p_box->data.p_tref_generic->i_entry_count; i++ )
2762 MP4_GET4BYTES( p_box->data.p_tref_generic->i_track_ID[i] );
2765 msg_Dbg( p_stream, "read box: \"chap\" %d references",
2766 p_box->data.p_tref_generic->i_entry_count );
2769 MP4_READBOX_EXIT( 1 );
2771 static void MP4_FreeBox_tref_generic( MP4_Box_t *p_box )
2773 FREENULL( p_box->data.p_tref_generic->i_track_ID );
2776 static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
2778 uint8_t meta_data[8];
2779 int i_actually_read;
2781 // skip over box header
2782 i_actually_read = stream_Read( p_stream, meta_data, 8 );
2783 if( i_actually_read < 8 )
2786 /* meta content starts with a 4 byte version/flags value (should be 0) */
2787 i_actually_read = stream_Read( p_stream, meta_data, 4 );
2788 if( i_actually_read < 4 )
2791 /* then it behaves like a container */
2792 return MP4_ReadBoxContainerRaw( p_stream, p_box );
2795 static int MP4_ReadBox_iods( stream_t *p_stream, MP4_Box_t *p_box )
2799 MP4_READBOX_ENTER( MP4_Box_data_iods_t );
2800 MP4_GETVERSIONFLAGS( p_box->data.p_iods );
2802 MP4_GET1BYTE( i_unused ); /* tag */
2803 MP4_GET1BYTE( i_unused ); /* length */
2805 MP4_GET2BYTES( p_box->data.p_iods->i_object_descriptor ); /* 10bits, 6 other bits
2806 are used for other flags */
2807 MP4_GET1BYTE( p_box->data.p_iods->i_OD_profile_level );
2808 MP4_GET1BYTE( p_box->data.p_iods->i_scene_profile_level );
2809 MP4_GET1BYTE( p_box->data.p_iods->i_audio_profile_level );
2810 MP4_GET1BYTE( p_box->data.p_iods->i_visual_profile_level );
2811 MP4_GET1BYTE( p_box->data.p_iods->i_graphics_profile_level );
2815 "read box: \"iods\" objectDescriptorId: %i, OD: %i, scene: %i, audio: %i, "
2816 "visual: %i, graphics: %i",
2817 p_box->data.p_iods->i_object_descriptor >> 6,
2818 p_box->data.p_iods->i_OD_profile_level,
2819 p_box->data.p_iods->i_scene_profile_level,
2820 p_box->data.p_iods->i_audio_profile_level,
2821 p_box->data.p_iods->i_visual_profile_level,
2822 p_box->data.p_iods->i_graphics_profile_level );
2825 MP4_READBOX_EXIT( 1 );
2828 static int MP4_ReadBox_pasp( stream_t *p_stream, MP4_Box_t *p_box )
2830 MP4_READBOX_ENTER( MP4_Box_data_pasp_t );
2832 MP4_GET4BYTES( p_box->data.p_pasp->i_horizontal_spacing );
2833 MP4_GET4BYTES( p_box->data.p_pasp->i_vertical_spacing );
2837 "read box: \"paps\" %dx%d",
2838 p_box->data.p_pasp->i_horizontal_spacing,
2839 p_box->data.p_pasp->i_vertical_spacing);
2842 MP4_READBOX_EXIT( 1 );
2845 static int MP4_ReadBox_mehd( stream_t *p_stream, MP4_Box_t *p_box )
2847 MP4_READBOX_ENTER( MP4_Box_data_mehd_t );
2849 MP4_GETVERSIONFLAGS( p_box->data.p_mehd );
2850 if( p_box->data.p_mehd->i_version == 1 )
2851 MP4_GET8BYTES( p_box->data.p_mehd->i_fragment_duration );
2852 else /* version == 0 */
2853 MP4_GET4BYTES( p_box->data.p_mehd->i_fragment_duration );
2857 "read box: \"mehd\" frag dur. %"PRIu64"",
2858 p_box->data.p_mehd->i_fragment_duration );
2861 MP4_READBOX_EXIT( 1 );
2864 static int MP4_ReadBox_trex( stream_t *p_stream, MP4_Box_t *p_box )
2866 MP4_READBOX_ENTER( MP4_Box_data_trex_t );
2867 MP4_GETVERSIONFLAGS( p_box->data.p_trex );
2869 MP4_GET4BYTES( p_box->data.p_trex->i_track_ID );
2870 MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_description_index );
2871 MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_duration );
2872 MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_size );
2873 MP4_GET4BYTES( p_box->data.p_trex->i_default_sample_flags );
2877 "read box: \"trex\" trackID: %"PRIu32"",
2878 p_box->data.p_trex->i_track_ID );
2881 MP4_READBOX_EXIT( 1 );
2884 static int MP4_ReadBox_sdtp( stream_t *p_stream, MP4_Box_t *p_box )
2886 uint32_t i_sample_count;
2887 MP4_READBOX_ENTER( MP4_Box_data_sdtp_t );
2888 MP4_Box_data_sdtp_t *p_sdtp = p_box->data.p_sdtp;
2889 MP4_GETVERSIONFLAGS( p_box->data.p_sdtp );
2890 i_sample_count = i_read;
2892 p_sdtp->p_sample_table = calloc( i_sample_count, 1 );
2894 if( !p_sdtp->p_sample_table )
2895 MP4_READBOX_EXIT( 0 );
2897 for( uint32_t i = 0; i < i_sample_count; i++ )
2898 MP4_GET1BYTE( p_sdtp->p_sample_table[i] );
2901 msg_Info( p_stream, "i_sample_count is %"PRIu32"", i_sample_count );
2903 "read box: \"sdtp\" head: %"PRIx8" %"PRIx8" %"PRIx8" %"PRIx8"",
2904 p_sdtp->p_sample_table[0],
2905 p_sdtp->p_sample_table[1],
2906 p_sdtp->p_sample_table[2],
2907 p_sdtp->p_sample_table[3] );
2910 MP4_READBOX_EXIT( 1 );
2913 static void MP4_FreeBox_sdtp( MP4_Box_t *p_box )
2915 FREENULL( p_box->data.p_sdtp->p_sample_table );
2918 static int MP4_ReadBox_mfro( stream_t *p_stream, MP4_Box_t *p_box )
2920 MP4_READBOX_ENTER( MP4_Box_data_mfro_t );
2922 MP4_GETVERSIONFLAGS( p_box->data.p_mfro );
2923 MP4_GET4BYTES( p_box->data.p_mfro->i_size );
2927 "read box: \"mfro\" size: %"PRIu32"",
2928 p_box->data.p_mfro->i_size);
2931 MP4_READBOX_EXIT( 1 );
2934 static int MP4_ReadBox_tfra( stream_t *p_stream, MP4_Box_t *p_box )
2936 uint32_t i_number_of_entries;
2937 MP4_READBOX_ENTER( MP4_Box_data_tfra_t );
2938 MP4_Box_data_tfra_t *p_tfra = p_box->data.p_tfra;
2939 MP4_GETVERSIONFLAGS( p_box->data.p_tfra );
2941 MP4_GET4BYTES( p_tfra->i_track_ID );
2942 uint32_t i_lengths = 0;
2943 MP4_GET4BYTES( i_lengths );
2944 MP4_GET4BYTES( p_tfra->i_number_of_entries );
2945 i_number_of_entries = p_tfra->i_number_of_entries;
2946 p_tfra->i_length_size_of_traf_num = i_lengths >> 4;
2947 p_tfra->i_length_size_of_trun_num = ( i_lengths & 0x0c ) >> 2;
2948 p_tfra->i_length_size_of_sample_num = i_lengths & 0x03;
2950 size_t size = 4 + 4*p_tfra->i_version; /* size in {4, 8} */
2951 p_tfra->p_time = calloc( i_number_of_entries, size );
2952 p_tfra->p_moof_offset = calloc( i_number_of_entries, size );
2954 size = 1 + p_tfra->i_length_size_of_traf_num; /* size in [|1, 4|] */
2955 p_tfra->p_traf_number = calloc( i_number_of_entries, size );
2956 size = 1 + p_tfra->i_length_size_of_trun_num;
2957 p_tfra->p_trun_number = calloc( i_number_of_entries, size );
2958 size = 1 + p_tfra->i_length_size_of_sample_num;
2959 p_tfra->p_sample_number = calloc( i_number_of_entries, size );
2961 if( !p_tfra->p_time || !p_tfra->p_moof_offset || !p_tfra->p_traf_number
2962 || !p_tfra->p_trun_number || !p_tfra->p_sample_number )
2965 for( uint32_t i = 0; i < i_number_of_entries; i++ )
2967 if( p_tfra->i_version == 1 )
2969 MP4_GET8BYTES( p_tfra->p_time[i*2] );
2970 MP4_GET8BYTES( p_tfra->p_moof_offset[i*2] );
2974 MP4_GET4BYTES( p_tfra->p_time[i] );
2975 MP4_GET4BYTES( p_tfra->p_moof_offset[i] );
2977 switch (p_tfra->i_length_size_of_traf_num)
2980 MP4_GET1BYTE( p_tfra->p_traf_number[i] );
2983 MP4_GET2BYTES( p_tfra->p_traf_number[i*2] );
2986 MP4_GET3BYTES( p_tfra->p_traf_number[i*3] );
2989 MP4_GET4BYTES( p_tfra->p_traf_number[i*4] );
2995 switch (p_tfra->i_length_size_of_trun_num)
2998 MP4_GET1BYTE( p_tfra->p_trun_number[i] );
3001 MP4_GET2BYTES( p_tfra->p_trun_number[i*2] );
3004 MP4_GET3BYTES( p_tfra->p_trun_number[i*3] );
3007 MP4_GET4BYTES( p_tfra->p_trun_number[i*4] );
3013 switch (p_tfra->i_length_size_of_sample_num)
3016 MP4_GET1BYTE( p_tfra->p_sample_number[i] );
3019 MP4_GET2BYTES( p_tfra->p_sample_number[i*2] );
3022 MP4_GET3BYTES( p_tfra->p_sample_number[i*3] );
3025 MP4_GET4BYTES( p_tfra->p_sample_number[i*4] );
3033 if( p_tfra->i_version == 0 )
3035 msg_Dbg( p_stream, "time[0]: %"PRIu32", moof_offset[0]: %"PRIx32"",
3036 p_tfra->p_time[0], p_tfra->p_moof_offset[0] );
3038 msg_Dbg( p_stream, "time[1]: %"PRIu32", moof_offset[1]: %"PRIx32"",
3039 p_tfra->p_time[1], p_tfra->p_moof_offset[1] );
3043 msg_Dbg( p_stream, "time[0]: %"PRIu64", moof_offset[0]: %"PRIx64"",
3044 ((uint64_t *)(p_tfra->p_time))[0],
3045 ((uint64_t *)(p_tfra->p_moof_offset))[0] );
3047 msg_Dbg( p_stream, "time[1]: %"PRIu64", moof_offset[1]: %"PRIx64"",
3048 ((uint64_t *)(p_tfra->p_time))[1],
3049 ((uint64_t *)(p_tfra->p_moof_offset))[1] );
3052 msg_Info( p_stream, "number_of_entries is %"PRIu32"", i_number_of_entries );
3053 msg_Info( p_stream, "track ID is: %"PRIu32"", p_tfra->i_track_ID );
3056 MP4_READBOX_EXIT( 1 );
3058 MP4_READBOX_EXIT( 0 );
3061 static void MP4_FreeBox_tfra( MP4_Box_t *p_box )
3063 FREENULL( p_box->data.p_tfra->p_time );
3064 FREENULL( p_box->data.p_tfra->p_moof_offset );
3065 FREENULL( p_box->data.p_tfra->p_traf_number );
3066 FREENULL( p_box->data.p_tfra->p_trun_number );
3067 FREENULL( p_box->data.p_tfra->p_sample_number );
3072 static int MP4_ReadBox_default( stream_t *p_stream, MP4_Box_t *p_box )
3074 if( !p_box->p_father )
3078 if( p_box->p_father->i_type == ATOM_stsd )
3080 MP4_Box_t *p_mdia = MP4_BoxGet( p_box, "../../../.." );
3083 if( p_mdia == NULL || p_mdia->i_type != ATOM_mdia ||
3084 (p_hdlr = MP4_BoxGet( p_mdia, "hdlr" )) == NULL )
3088 switch( p_hdlr->data.p_hdlr->i_handler_type )
3091 return MP4_ReadBox_sample_soun( p_stream, p_box );
3093 return MP4_ReadBox_sample_vide( p_stream, p_box );
3095 return MP4_ReadBox_sample_text( p_stream, p_box );
3098 return MP4_ReadBox_sample_tx3g( p_stream, p_box );
3101 "unknown handler type in stsd (incompletely loaded)" );
3107 if MP4_BOX_TYPE_ASCII()
3109 "unknown box type %4.4s (incompletely loaded)",
3110 (char*)&p_box->i_type );
3113 "unknown box type c%3.3s (incompletely loaded)",
3114 (char*)&p_box->i_type+1 );
3119 /**** ------------------------------------------------------------------- ****/
3120 /**** "Higher level" Functions ****/
3121 /**** ------------------------------------------------------------------- ****/
3126 int (*MP4_ReadBox_function )( stream_t *p_stream, MP4_Box_t *p_box );
3127 void (*MP4_FreeBox_function )( MP4_Box_t *p_box );
3128 } MP4_Box_Function [] =
3131 { ATOM_moov, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3132 { ATOM_trak, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3133 { ATOM_mdia, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3134 { ATOM_moof, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3135 { ATOM_minf, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3136 { ATOM_stbl, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3137 { ATOM_dinf, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3138 { ATOM_edts, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3139 { ATOM_udta, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3140 { ATOM_nmhd, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3141 { ATOM_hnti, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3142 { ATOM_rmra, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3143 { ATOM_rmda, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3144 { ATOM_tref, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3145 { ATOM_gmhd, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3146 { ATOM_wave, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3147 { ATOM_ilst, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3148 { ATOM_mvex, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3151 { ATOM_ftyp, MP4_ReadBox_ftyp, MP4_FreeBox_ftyp },
3152 { ATOM_cmov, MP4_ReadBox_cmov, MP4_FreeBox_Common },
3153 { ATOM_mvhd, MP4_ReadBox_mvhd, MP4_FreeBox_Common },
3154 { ATOM_tkhd, MP4_ReadBox_tkhd, MP4_FreeBox_Common },
3155 { ATOM_mdhd, MP4_ReadBox_mdhd, MP4_FreeBox_Common },
3156 { ATOM_hdlr, MP4_ReadBox_hdlr, MP4_FreeBox_hdlr },
3157 { ATOM_vmhd, MP4_ReadBox_vmhd, MP4_FreeBox_Common },
3158 { ATOM_smhd, MP4_ReadBox_smhd, MP4_FreeBox_Common },
3159 { ATOM_hmhd, MP4_ReadBox_hmhd, MP4_FreeBox_Common },
3160 { ATOM_url, MP4_ReadBox_url, MP4_FreeBox_url },
3161 { ATOM_urn, MP4_ReadBox_urn, MP4_FreeBox_urn },
3162 { ATOM_dref, MP4_ReadBox_dref, MP4_FreeBox_Common },
3163 { ATOM_stts, MP4_ReadBox_stts, MP4_FreeBox_stts },
3164 { ATOM_ctts, MP4_ReadBox_ctts, MP4_FreeBox_ctts },
3165 { ATOM_stsd, MP4_ReadBox_stsd, MP4_FreeBox_Common },
3166 { ATOM_stsz, MP4_ReadBox_stsz, MP4_FreeBox_stsz },
3167 { ATOM_stsc, MP4_ReadBox_stsc, MP4_FreeBox_stsc },
3168 { ATOM_stco, MP4_ReadBox_stco_co64, MP4_FreeBox_stco_co64 },
3169 { ATOM_co64, MP4_ReadBox_stco_co64, MP4_FreeBox_stco_co64 },
3170 { ATOM_stss, MP4_ReadBox_stss, MP4_FreeBox_stss },
3171 { ATOM_stsh, MP4_ReadBox_stsh, MP4_FreeBox_stsh },
3172 { ATOM_stdp, MP4_ReadBox_stdp, MP4_FreeBox_stdp },
3173 { ATOM_padb, MP4_ReadBox_padb, MP4_FreeBox_padb },
3174 { ATOM_elst, MP4_ReadBox_elst, MP4_FreeBox_elst },
3175 { ATOM_cprt, MP4_ReadBox_cprt, MP4_FreeBox_cprt },
3176 { ATOM_esds, MP4_ReadBox_esds, MP4_FreeBox_esds },
3177 { ATOM_dcom, MP4_ReadBox_dcom, MP4_FreeBox_Common },
3178 { ATOM_cmvd, MP4_ReadBox_cmvd, MP4_FreeBox_cmvd },
3179 { ATOM_avcC, MP4_ReadBox_avcC, MP4_FreeBox_avcC },
3180 { ATOM_dac3, MP4_ReadBox_dac3, MP4_FreeBox_Common },
3181 { ATOM_dvc1, MP4_ReadBox_dvc1, MP4_FreeBox_Common },
3182 { ATOM_enda, MP4_ReadBox_enda, MP4_FreeBox_Common },
3183 { ATOM_gnre, MP4_ReadBox_gnre, MP4_FreeBox_Common },
3184 { ATOM_trkn, MP4_ReadBox_trkn, MP4_FreeBox_Common },
3185 { ATOM_iods, MP4_ReadBox_iods, MP4_FreeBox_Common },
3186 { ATOM_pasp, MP4_ReadBox_pasp, MP4_FreeBox_Common },
3188 /* Nothing to do with this box */
3189 { ATOM_mdat, MP4_ReadBoxSkip, MP4_FreeBox_Common },
3190 { ATOM_skip, MP4_ReadBoxSkip, MP4_FreeBox_Common },
3191 { ATOM_free, MP4_ReadBoxSkip, MP4_FreeBox_Common },
3192 { ATOM_wide, MP4_ReadBoxSkip, MP4_FreeBox_Common },
3195 { ATOM_soun, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3196 { ATOM_ms02, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3197 { ATOM_ms11, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3198 { ATOM_ms55, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3199 { ATOM__mp3, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3200 { ATOM_mp4a, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3201 { ATOM_twos, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3202 { ATOM_sowt, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3203 { ATOM_QDMC, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3204 { ATOM_QDM2, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3205 { ATOM_ima4, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3206 { ATOM_IMA4, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3207 { ATOM_dvi, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3208 { ATOM_alaw, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3209 { ATOM_ulaw, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3210 { ATOM_raw, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3211 { ATOM_MAC3, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3212 { ATOM_MAC6, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3213 { ATOM_Qclp, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3214 { ATOM_samr, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3215 { ATOM_sawb, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3216 { ATOM_OggS, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3217 { ATOM_alac, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3219 { ATOM_drmi, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3220 { ATOM_vide, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3221 { ATOM_mp4v, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3222 { ATOM_SVQ1, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3223 { ATOM_SVQ3, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3224 { ATOM_ZyGo, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3225 { ATOM_DIVX, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3226 { ATOM_XVID, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3227 { ATOM_h263, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3228 { ATOM_s263, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3229 { ATOM_cvid, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3230 { ATOM_3IV1, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3231 { ATOM_3iv1, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3232 { ATOM_3IV2, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3233 { ATOM_3iv2, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3234 { ATOM_3IVD, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3235 { ATOM_3ivd, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3236 { ATOM_3VID, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3237 { ATOM_3vid, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3238 { ATOM_mjpa, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3239 { ATOM_mjpb, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3240 { ATOM_qdrw, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3241 { ATOM_mp2v, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3242 { ATOM_hdv2, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3244 { ATOM_mjqt, MP4_ReadBox_default, NULL }, /* found in mjpa/b */
3245 { ATOM_mjht, MP4_ReadBox_default, NULL },
3247 { ATOM_dvc, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3248 { ATOM_dvp, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3249 { ATOM_dv5n, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3250 { ATOM_dv5p, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3251 { ATOM_VP31, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3252 { ATOM_vp31, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3253 { ATOM_h264, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3255 { ATOM_jpeg, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3256 { ATOM_avc1, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3258 { ATOM_yv12, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3259 { ATOM_yuv2, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide },
3261 { ATOM_mp4s, MP4_ReadBox_sample_mp4s, MP4_FreeBox_Common },
3263 /* XXX there is 2 box where we could find this entry stbl and tref*/
3264 { ATOM_hint, MP4_ReadBox_default, MP4_FreeBox_Common },
3266 /* found in tref box */
3267 { ATOM_dpnd, MP4_ReadBox_default, NULL },
3268 { ATOM_ipir, MP4_ReadBox_default, NULL },
3269 { ATOM_mpod, MP4_ReadBox_default, NULL },
3270 { ATOM_chap, MP4_ReadBox_tref_generic, MP4_FreeBox_tref_generic },
3273 { ATOM_rtp, MP4_ReadBox_default, NULL },
3276 { ATOM_rdrf, MP4_ReadBox_rdrf, MP4_FreeBox_rdrf },
3277 { ATOM_rmdr, MP4_ReadBox_rmdr, MP4_FreeBox_Common },
3278 { ATOM_rmqu, MP4_ReadBox_rmqu, MP4_FreeBox_Common },
3279 { ATOM_rmvc, MP4_ReadBox_rmvc, MP4_FreeBox_Common },
3281 { ATOM_drms, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
3282 { ATOM_sinf, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3283 { ATOM_schi, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3284 { ATOM_user, MP4_ReadBox_drms, MP4_FreeBox_Common },
3285 { ATOM_key, MP4_ReadBox_drms, MP4_FreeBox_Common },
3286 { ATOM_iviv, MP4_ReadBox_drms, MP4_FreeBox_Common },
3287 { ATOM_priv, MP4_ReadBox_drms, MP4_FreeBox_Common },
3288 { ATOM_frma, MP4_ReadBox_frma, MP4_FreeBox_Common },
3289 { ATOM_skcr, MP4_ReadBox_skcr, MP4_FreeBox_Common },
3292 { ATOM_0xa9nam, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3293 { ATOM_0xa9aut, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3294 { ATOM_0xa9cpy, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3295 { ATOM_0xa9swr, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3296 { ATOM_0xa9inf, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3297 { ATOM_0xa9ART, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3298 { ATOM_0xa9dir, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3299 { ATOM_0xa9cmt, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3300 { ATOM_0xa9req, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3301 { ATOM_0xa9day, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3302 { ATOM_0xa9des, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3303 { ATOM_0xa9fmt, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3304 { ATOM_0xa9prd, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3305 { ATOM_0xa9prf, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3306 { ATOM_0xa9src, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3307 { ATOM_0xa9alb, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3308 { ATOM_0xa9dis, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3309 { ATOM_0xa9enc, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3310 { ATOM_0xa9gen, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3311 { ATOM_0xa9trk, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3312 { ATOM_0xa9dsa, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3313 { ATOM_0xa9hst, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3314 { ATOM_0xa9url, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3315 { ATOM_0xa9ope, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3316 { ATOM_0xa9com, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3317 { ATOM_0xa9wrt, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3318 { ATOM_0xa9too, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3319 { ATOM_0xa9wrn, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3320 { ATOM_0xa9mak, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3321 { ATOM_0xa9mod, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3322 { ATOM_0xa9PRD, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3323 { ATOM_0xa9grp, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3324 { ATOM_0xa9lyr, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3325 { ATOM_0xa9gen, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3326 { ATOM_0xa9st3, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3327 { ATOM_0xa9ard, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3328 { ATOM_0xa9arg, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3329 { ATOM_0xa9cak, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3330 { ATOM_0xa9con, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3331 { ATOM_0xa9des, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3332 { ATOM_0xa9lnt, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3333 { ATOM_0xa9phg, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3334 { ATOM_0xa9pub, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3335 { ATOM_0xa9sne, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3336 { ATOM_0xa9sol, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3337 { ATOM_0xa9thx, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3338 { ATOM_0xa9xpd, MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx },
3340 { ATOM_chpl, MP4_ReadBox_chpl, MP4_FreeBox_chpl },
3342 /* iTunes/Quicktime meta info */
3343 { ATOM_meta, MP4_ReadBox_meta, MP4_FreeBox_Common },
3344 { ATOM_name, MP4_ReadBox_name, MP4_FreeBox_name },
3346 /* found in smoothstreaming */
3347 { ATOM_traf, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3348 { ATOM_mfra, MP4_ReadBoxContainer, MP4_FreeBox_Common },
3349 { ATOM_mfhd, MP4_ReadBox_mfhd, MP4_FreeBox_Common },
3350 { ATOM_sidx, MP4_ReadBox_sidx, MP4_FreeBox_sidx },
3351 { ATOM_tfhd, MP4_ReadBox_tfhd, MP4_FreeBox_Common },
3352 { ATOM_trun, MP4_ReadBox_trun, MP4_FreeBox_trun },
3353 { ATOM_trex, MP4_ReadBox_trex, MP4_FreeBox_Common },
3354 { ATOM_mehd, MP4_ReadBox_mehd, MP4_FreeBox_Common },
3355 { ATOM_sdtp, MP4_ReadBox_sdtp, MP4_FreeBox_sdtp },
3356 { ATOM_tfra, MP4_ReadBox_tfra, MP4_FreeBox_tfra },
3357 { ATOM_mfro, MP4_ReadBox_mfro, MP4_FreeBox_Common },
3358 { ATOM_uuid, MP4_ReadBox_uuid, MP4_FreeBox_uuid },
3361 { 0, MP4_ReadBox_default, NULL }
3365 /*****************************************************************************
3366 * MP4_ReadBox : parse the actual box and the children
3367 * XXX : Do not go to the next box
3368 *****************************************************************************/
3369 static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father )
3371 MP4_Box_t *p_box = calloc( 1, sizeof( MP4_Box_t ) ); /* Needed to ensure simple on error handler */
3372 unsigned int i_index;
3377 if( !MP4_ReadBoxCommon( p_stream, p_box ) )
3379 msg_Warn( p_stream, "cannot read one box" );
3383 if( !p_box->i_size )
3385 msg_Dbg( p_stream, "found an empty box (null size)" );
3389 p_box->p_father = p_father;
3391 /* Now search function to call */
3392 for( i_index = 0; ; i_index++ )
3394 if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
3395 ( MP4_Box_Function[i_index].i_type == 0 ) )
3401 if( !(MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box ) )
3403 MP4_BoxFree( p_stream, p_box );
3410 /*****************************************************************************
3411 * MP4_FreeBox : free memory after read with MP4_ReadBox and all
3413 *****************************************************************************/
3414 void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
3416 unsigned int i_index;
3422 for( p_child = p_box->p_first; p_child != NULL; )
3426 p_next = p_child->p_next;
3427 MP4_BoxFree( s, p_child );
3431 /* Now search function to call */
3432 if( p_box->data.p_data )
3434 for( i_index = 0; ; i_index++ )
3436 if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
3437 ( MP4_Box_Function[i_index].i_type == 0 ) )
3442 if( MP4_Box_Function[i_index].MP4_FreeBox_function == NULL )
3444 /* Should not happen */
3445 if MP4_BOX_TYPE_ASCII()
3447 "cannot free box %4.4s, type unknown",
3448 (char*)&p_box->i_type );
3451 "cannot free box c%3.3s, type unknown",
3452 (char*)&p_box->i_type+1 );
3456 MP4_Box_Function[i_index].MP4_FreeBox_function( p_box );
3458 free( p_box->data.p_data );
3463 /* SmooBox is a very simple MP4 box, VLC specific, used only for the stream_filter to
3464 * send information to the demux. SmooBox is actually a simplified moov box (we wanted
3465 * to avoid the hassle of building a moov box at the stream_filter level) */
3466 MP4_Box_t *MP4_BoxGetSmooBox( stream_t *s )
3468 /* p_chunk is a virtual root container for the smoo box */
3472 p_chunk = calloc( 1, sizeof( MP4_Box_t ) );
3473 if( unlikely( p_chunk == NULL ) )
3476 p_chunk->i_type = ATOM_root;
3477 p_chunk->i_shortsize = 1;
3479 p_smoo = MP4_ReadBox( s, p_chunk );
3480 if( !p_smoo || p_smoo->i_type != ATOM_uuid || CmpUUID( &p_smoo->i_uuid, &SmooBoxUUID ) )
3482 msg_Warn( s, "no smoo box found!");
3486 p_chunk->p_first = p_smoo;
3487 p_chunk->p_last = p_smoo;
3496 MP4_Box_t *MP4_BoxGetNextChunk( stream_t *s )
3498 /* p_chunk is a virtual root container for the moof and mdat boxes */
3500 MP4_Box_t *p_tmp_box = NULL;
3502 p_tmp_box = calloc( 1, sizeof( MP4_Box_t ) );
3503 if( unlikely( p_tmp_box == NULL ) )
3506 /* We might get a ftyp box or a SmooBox */
3507 MP4_ReadBoxCommon( s, p_tmp_box );
3509 if( (p_tmp_box->i_type == ATOM_uuid && !CmpUUID( &p_tmp_box->i_uuid, &SmooBoxUUID )) )
3512 return MP4_BoxGetSmooBox( s );
3514 else if( p_tmp_box->i_type == ATOM_ftyp )
3517 return MP4_BoxGetRoot( s );
3521 p_chunk = calloc( 1, sizeof( MP4_Box_t ) );
3522 if( unlikely( p_chunk == NULL ) )
3525 p_chunk->i_type = ATOM_root;
3526 p_chunk->i_shortsize = 1;
3528 MP4_ReadBoxContainerChildren( s, p_chunk, ATOM_moof );
3533 /*****************************************************************************
3534 * MP4_BoxGetRoot : Parse the entire file, and create all boxes in memory
3535 *****************************************************************************
3536 * The first box is a virtual box "root" and is the father for all first
3537 * level boxes for the file, a sort of virtual contener
3538 *****************************************************************************/
3539 MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
3545 p_root = malloc( sizeof( MP4_Box_t ) );
3546 if( p_root == NULL )
3550 p_root->i_type = ATOM_root;
3551 p_root->i_shortsize = 1;
3552 /* could be a DASH stream for exemple, 0 means unknown or infinite size */
3554 CreateUUID( &p_root->i_uuid, p_root->i_type );
3556 p_root->data.p_data = NULL;
3557 p_root->p_father = NULL;
3558 p_root->p_first = NULL;
3559 p_root->p_last = NULL;
3560 p_root->p_next = NULL;
3564 /* First get the moov */
3565 i_result = MP4_ReadBoxContainerChildren( p_stream, p_root, ATOM_moov );
3569 /* If there is a mvex box, it means fragmented MP4, and we're done */
3570 else if( MP4_BoxCount( p_root, "moov/mvex" ) > 0 )
3573 p_root->i_size = stream_Size( s );
3574 stream_Seek( p_stream, 0 );
3575 /* Get the rest of the file */
3576 i_result = MP4_ReadBoxContainerRaw( p_stream, p_root );
3584 /* check if there is a cmov, if so replace
3585 compressed moov by uncompressed one */
3586 if( ( ( p_moov = MP4_BoxGet( p_root, "moov" ) ) &&
3587 ( p_cmov = MP4_BoxGet( p_root, "moov/cmov" ) ) ) ||
3588 ( ( p_moov = MP4_BoxGet( p_root, "foov" ) ) &&
3589 ( p_cmov = MP4_BoxGet( p_root, "foov/cmov" ) ) ) )
3591 /* rename the compressed moov as a box to skip */
3592 p_moov->i_type = ATOM_skip;
3594 /* get uncompressed p_moov */
3595 p_moov = p_cmov->data.p_cmov->p_moov;
3596 p_cmov->data.p_cmov->p_moov = NULL;
3598 /* make p_root father of this new moov */
3599 p_moov->p_father = p_root;
3601 /* insert this new moov box as first child of p_root */
3602 p_moov->p_next = p_root->p_first;
3603 p_root->p_first = p_moov;
3614 static void MP4_BoxDumpStructure_Internal( stream_t *s,
3615 MP4_Box_t *p_box, unsigned int i_level )
3621 if MP4_BOX_TYPE_ASCII()
3622 msg_Dbg( s, "dumping root Box \"%4.4s\"",
3623 (char*)&p_box->i_type );
3625 msg_Dbg( s, "dumping root Box \"c%3.3s\"",
3626 (char*)&p_box->i_type+1 );
3631 if( i_level >= (sizeof(str) - 1)/4 )
3634 memset( str, ' ', sizeof(str) );
3635 for( unsigned i = 0; i < i_level; i++ )
3639 if( MP4_BOX_TYPE_ASCII() )
3640 snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
3642 (char*)&p_box->i_type, (uint32_t)p_box->i_size );
3644 snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
3646 (char*)&p_box->i_type+1, (uint32_t)p_box->i_size );
3647 msg_Dbg( s, "%s", str );
3649 p_child = p_box->p_first;
3652 MP4_BoxDumpStructure_Internal( s, p_child, i_level + 1 );
3653 p_child = p_child->p_next;
3657 void MP4_BoxDumpStructure( stream_t *s, MP4_Box_t *p_box )
3659 MP4_BoxDumpStructure_Internal( s, p_box, 0 );
3663 /*****************************************************************************
3664 *****************************************************************************
3666 ** High level methods to acces an MP4 file
3668 *****************************************************************************
3669 *****************************************************************************/
3670 static void get_token( char **ppsz_path, char **ppsz_token, int *pi_number )
3673 if( !*ppsz_path[0] )
3679 i_len = strcspn( *ppsz_path, "/[" );
3680 if( !i_len && **ppsz_path == '/' )
3684 *ppsz_token = strndup( *ppsz_path, i_len );
3685 if( unlikely(!*ppsz_token) )
3688 *ppsz_path += i_len;
3690 if( **ppsz_path == '[' )
3693 *pi_number = strtol( *ppsz_path, NULL, 10 );
3694 while( **ppsz_path && **ppsz_path != ']' )
3698 if( **ppsz_path == ']' )
3707 while( **ppsz_path == '/' )
3713 static void MP4_BoxGet_Internal( MP4_Box_t **pp_result,
3714 MP4_Box_t *p_box, const char *psz_fmt, va_list args)
3726 if( vasprintf( &psz_path, psz_fmt, args ) == -1 )
3729 if( !psz_path || !psz_path[0] )
3736 // fprintf( stderr, "path:'%s'\n", psz_path );
3737 psz_dup = psz_path; /* keep this pointer, as it need to be unallocated */
3742 get_token( &psz_path, &psz_token, &i_number );
3743 // fprintf( stderr, "path:'%s', token:'%s' n:%d\n",
3744 // psz_path,psz_token,i_number );
3752 if( !strcmp( psz_token, "/" ) )
3755 while( p_box && p_box->i_type != ATOM_root )
3757 p_box = p_box->p_father;
3765 if( !strcmp( psz_token, "." ) )
3770 if( !strcmp( psz_token, ".." ) )
3772 p_box = p_box->p_father;
3779 if( strlen( psz_token ) == 4 )
3782 i_fourcc = VLC_FOURCC( psz_token[0], psz_token[1],
3783 psz_token[2], psz_token[3] );
3784 p_box = p_box->p_first;
3791 if( p_box->i_type == i_fourcc )
3799 p_box = p_box->p_next;
3803 if( *psz_token == '\0' )
3805 p_box = p_box->p_first;
3817 p_box = p_box->p_next;
3822 // fprintf( stderr, "Argg malformed token \"%s\"",psz_token );
3826 FREENULL( psz_token );
3838 /*****************************************************************************
3839 * MP4_BoxGet: find a box given a path relative to p_box
3840 *****************************************************************************
3841 * Path Format: . .. / as usual
3842 * [number] to specifie box number ex: trak[12]
3844 * ex: /moov/trak[12]
3846 *****************************************************************************/
3847 MP4_Box_t *MP4_BoxGet( MP4_Box_t *p_box, const char *psz_fmt, ... )
3850 MP4_Box_t *p_result;
3852 va_start( args, psz_fmt );
3853 MP4_BoxGet_Internal( &p_result, p_box, psz_fmt, args );
3859 /*****************************************************************************
3860 * MP4_BoxCount: count box given a path relative to p_box
3861 *****************************************************************************
3862 * Path Format: . .. / as usual
3863 * [number] to specifie box number ex: trak[12]
3865 * ex: /moov/trak[12]
3867 *****************************************************************************/
3868 int MP4_BoxCount( MP4_Box_t *p_box, const char *psz_fmt, ... )
3872 MP4_Box_t *p_result, *p_next;
3874 va_start( args, psz_fmt );
3875 MP4_BoxGet_Internal( &p_result, p_box, psz_fmt, args );
3883 for( p_next = p_result->p_next; p_next != NULL; p_next = p_next->p_next)
3885 if( p_next->i_type == p_result->i_type)