+static int MP4_ReadBox_mfhd( stream_t *p_stream, MP4_Box_t *p_box )
+{
+ MP4_READBOX_ENTER( MP4_Box_data_mfhd_t );
+
+ MP4_GETVERSIONFLAGS( p_box->data.p_mvhd );
+
+ MP4_GET4BYTES( p_box->data.p_mfhd->i_sequence_number );
+
+#ifdef MP4_VERBOSE
+ msg_Dbg( p_stream, "read box: \"mfhd\" sequence number %d",
+ p_box->data.p_mfhd->i_sequence_number );
+#endif
+ MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_tfxd( stream_t *p_stream, MP4_Box_t *p_box )
+{
+ MP4_READBOX_ENTER( MP4_Box_data_tfxd_t );
+
+ MP4_Box_data_tfxd_t *p_tfxd_data = p_box->data.p_tfxd;
+ MP4_GETVERSIONFLAGS( p_tfxd_data );
+
+ if( p_tfxd_data->i_version == 0 )
+ {
+ MP4_GET4BYTES( p_tfxd_data->i_fragment_abs_time );
+ MP4_GET4BYTES( p_tfxd_data->i_fragment_duration );
+ }
+ else
+ {
+ MP4_GET8BYTES( p_tfxd_data->i_fragment_abs_time );
+ MP4_GET8BYTES( p_tfxd_data->i_fragment_duration );
+ }
+
+#ifdef MP4_VERBOSE
+ msg_Dbg( p_stream, "read box: \"tfxd\" version %d, flags 0x%x, "\
+ "fragment duration %"PRIu64", fragment abs time %"PRIu64,
+ p_tfxd_data->i_version,
+ p_tfxd_data->i_flags,
+ p_tfxd_data->i_fragment_duration,
+ p_tfxd_data->i_fragment_abs_time
+ );
+#endif
+
+ MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_tfrf( stream_t *p_stream, MP4_Box_t *p_box )
+{
+ MP4_READBOX_ENTER( MP4_Box_data_tfxd_t );
+
+ MP4_Box_data_tfrf_t *p_tfrf_data = p_box->data.p_tfrf;
+ MP4_GETVERSIONFLAGS( p_tfrf_data );
+
+ MP4_GET1BYTE( p_tfrf_data->i_fragment_count );
+
+ p_tfrf_data->p_tfrf_data_fields = calloc( p_tfrf_data->i_fragment_count,
+ sizeof( TfrfBoxDataFields_t ) );
+ if( !p_tfrf_data->p_tfrf_data_fields )
+ MP4_READBOX_EXIT( 0 );
+
+ for( uint8_t i = 0; i < p_tfrf_data->i_fragment_count; i++ )
+ {
+ TfrfBoxDataFields_t *TfrfBoxDataField = &p_tfrf_data->p_tfrf_data_fields[i];
+ if( p_tfrf_data->i_version == 0 )
+ {
+ MP4_GET4BYTES( TfrfBoxDataField->i_fragment_abs_time );
+ MP4_GET4BYTES( TfrfBoxDataField->i_fragment_duration );
+ }
+ else
+ {
+ MP4_GET8BYTES( TfrfBoxDataField->i_fragment_abs_time );
+ MP4_GET8BYTES( TfrfBoxDataField->i_fragment_duration );
+ }
+ }
+
+#ifdef MP4_VERBOSE
+ msg_Dbg( p_stream, "read box: \"tfrf\" version %d, flags 0x%x, "\
+ "fragment count %"PRIu8, p_tfrf_data->i_version,
+ p_tfrf_data->i_flags, p_tfrf_data->i_fragment_count );
+
+ for( uint8_t i = 0; i < p_tfrf_data->i_fragment_count; i++ )
+ {
+ TfrfBoxDataFields_t *TfrfBoxDataField = &p_tfrf_data->p_tfrf_data_fields[i];
+ msg_Dbg( p_stream, "\"tfrf\" fragment duration %"PRIu64", "\
+ "fragment abs time %"PRIu64,
+ TfrfBoxDataField->i_fragment_duration,
+ TfrfBoxDataField->i_fragment_abs_time );
+ }
+
+#endif
+
+ MP4_READBOX_EXIT( 1 );
+}
+
+static void MP4_FreeBox_tfrf( MP4_Box_t *p_box )
+{
+ FREENULL( p_box->data.p_tfrf->p_tfrf_data_fields );
+}
+
+static int MP4_ReadBox_stra( stream_t *p_stream, MP4_Box_t *p_box )
+{
+ MP4_READBOX_ENTER( MP4_Box_data_stra_t );
+ MP4_Box_data_stra_t *p_stra = p_box->data.p_stra;
+
+ uint8_t i_reserved;
+ MP4_GET1BYTE( p_stra->i_es_cat );
+ MP4_GET1BYTE( i_reserved );
+ MP4_GET2BYTES( p_stra->i_track_ID );
+
+ MP4_GET4BYTES( p_stra->i_timescale );
+ MP4_GET8BYTES( p_stra->i_duration );
+
+ MP4_GET4BYTES( p_stra->FourCC );
+ MP4_GET4BYTES( p_stra->Bitrate );
+ MP4_GET4BYTES( p_stra->MaxWidth );
+ MP4_GET4BYTES( p_stra->MaxHeight );
+ MP4_GET4BYTES( p_stra->SamplingRate );
+ MP4_GET4BYTES( p_stra->Channels );
+ MP4_GET4BYTES( p_stra->BitsPerSample );
+ MP4_GET4BYTES( p_stra->AudioTag );
+ MP4_GET2BYTES( p_stra->nBlockAlign );
+
+ MP4_GET1BYTE( i_reserved );
+ MP4_GET1BYTE( i_reserved );
+ MP4_GET1BYTE( i_reserved );
+ MP4_GET1BYTE( p_stra->cpd_len );
+ if( p_stra->cpd_len > i_read )
+ goto error;
+ p_stra->CodecPrivateData = malloc( p_stra->cpd_len );
+ if( unlikely( p_stra->CodecPrivateData == NULL ) )
+ goto error;
+ memcpy( p_stra->CodecPrivateData, p_peek, p_stra->cpd_len );
+
+#ifdef MP4_VERBOSE
+ msg_Dbg( p_stream, "es_cat is %"PRIu8", birate is %"PRIu32,
+ p_stra->i_es_cat, p_stra->Bitrate );
+#endif
+
+ MP4_READBOX_EXIT( 1 );
+error:
+ MP4_READBOX_EXIT( 0 );
+}
+
+static void MP4_FreeBox_stra( MP4_Box_t *p_box )
+{
+ FREENULL( p_box->data.p_stra->CodecPrivateData );
+}
+
+static int MP4_ReadBox_uuid( stream_t *p_stream, MP4_Box_t *p_box )
+{
+ if( !CmpUUID( &p_box->i_uuid, &TfrfBoxUUID ) )
+ return MP4_ReadBox_tfrf( p_stream, p_box );
+ if( !CmpUUID( &p_box->i_uuid, &TfxdBoxUUID ) )
+ return MP4_ReadBox_tfxd( p_stream, p_box );
+ if( !CmpUUID( &p_box->i_uuid, &SmooBoxUUID ) )
+ return MP4_ReadBoxContainer( p_stream, p_box );
+ if( !CmpUUID( &p_box->i_uuid, &StraBoxUUID ) )
+ return MP4_ReadBox_stra( p_stream, p_box );
+
+ msg_Warn( p_stream, "Unknown uuid type box" );
+ return 1;
+}
+
+static void MP4_FreeBox_uuid( MP4_Box_t *p_box )
+{
+ if( !CmpUUID( &p_box->i_uuid, &TfrfBoxUUID ) )
+ return MP4_FreeBox_tfrf( p_box );
+ if( !CmpUUID( &p_box->i_uuid, &TfxdBoxUUID ) )
+ return MP4_FreeBox_Common( p_box );
+ if( !CmpUUID( &p_box->i_uuid, &SmooBoxUUID ) )
+ return MP4_FreeBox_Common( p_box );
+ if( !CmpUUID( &p_box->i_uuid, &StraBoxUUID ) )
+ return MP4_FreeBox_stra( p_box );
+}
+
+static int MP4_ReadBox_sidx( stream_t *p_stream, MP4_Box_t *p_box )
+{
+ MP4_READBOX_ENTER( MP4_Box_data_sidx_t );
+
+ MP4_Box_data_sidx_t *p_sidx_data = p_box->data.p_sidx;
+ MP4_GETVERSIONFLAGS( p_sidx_data );
+
+ MP4_GET4BYTES( p_sidx_data->i_reference_ID );
+ MP4_GET4BYTES( p_sidx_data->i_timescale );
+
+ if( p_sidx_data->i_version == 0 )
+ {
+ MP4_GET4BYTES( p_sidx_data->i_earliest_presentation_time );
+ MP4_GET4BYTES( p_sidx_data->i_first_offset );
+ }
+ else
+ {
+ MP4_GET8BYTES( p_sidx_data->i_earliest_presentation_time );
+ MP4_GET8BYTES( p_sidx_data->i_first_offset );
+ }
+
+ uint16_t i_reserved;
+ MP4_GET2BYTES( i_reserved );
+ MP4_GET2BYTES( p_sidx_data->i_reference_count );
+ uint16_t i_count = p_sidx_data->i_reference_count;
+
+ p_sidx_data->p_items = calloc( i_count, sizeof( MP4_Box_sidx_item_t ) );
+ uint32_t tmp;
+ for( unsigned i = 0; i < i_count; i++ )
+ {
+ MP4_GET4BYTES( tmp );
+ p_sidx_data->p_items[i].b_reference_type = (bool)((tmp & 0x80000000)>>24);
+ p_sidx_data->p_items[i].i_referenced_size = tmp & 0x7fffffff;
+ MP4_GET4BYTES( p_sidx_data->p_items[i].i_subsegment_duration );
+
+ MP4_GET4BYTES( tmp );
+ p_sidx_data->p_items[i].b_starts_with_SAP = (bool)((tmp & 0x80000000)>>24);
+ p_sidx_data->p_items[i].i_SAP_type = (tmp & 0x70000000)>>24;
+ p_sidx_data->p_items[i].i_SAP_delta_time = tmp & 0xfffffff;
+ }
+
+#ifdef MP4_VERBOSE
+ msg_Dbg( p_stream, "read box: \"sidx\" version %d, flags 0x%x, "\
+ "ref_ID %"PRIu32", timescale %"PRIu32", ref_count %"PRIu16", "\
+ "first subsegmt duration %"PRIu32,
+ p_sidx_data->i_version,
+ p_sidx_data->i_flags,
+ p_sidx_data->i_reference_ID,
+ p_sidx_data->i_timescale,
+ p_sidx_data->i_reference_count,
+ p_sidx_data->p_items[0].i_subsegment_duration
+ );
+#endif
+
+ MP4_READBOX_EXIT( 1 );
+}
+
+static void MP4_FreeBox_sidx( MP4_Box_t *p_box )
+{
+ FREENULL( p_box->data.p_sidx->p_items );
+}
+
+static int MP4_ReadBox_tfhd( stream_t *p_stream, MP4_Box_t *p_box )
+{
+ MP4_READBOX_ENTER( MP4_Box_data_tfhd_t );
+
+ MP4_GETVERSIONFLAGS( p_box->data.p_tfhd );
+
+ if( p_box->data.p_tfhd->i_version != 0 )
+ {
+ msg_Warn( p_stream, "'tfhd' box with version != 0. "\
+ " Don't know what to do with that, please patch" );
+ MP4_READBOX_EXIT( 0 );
+ }
+
+ MP4_GET4BYTES( p_box->data.p_tfhd->i_track_ID );
+
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DURATION_IS_EMPTY )
+ {
+ msg_Dbg( p_stream, "'duration-is-empty' flag is present "\
+ "=> no samples for this time interval." );
+ p_box->data.p_tfhd->b_empty = true;
+ }
+ else
+ p_box->data.p_tfhd->b_empty = false;
+
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
+ MP4_GET8BYTES( p_box->data.p_tfhd->i_base_data_offset );
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
+ MP4_GET4BYTES( p_box->data.p_tfhd->i_sample_description_index );
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
+ MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_duration );
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
+ MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_size );
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
+ MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_flags );
+
+#ifdef MP4_VERBOSE
+ char psz_base[128] = "\0";
+ char psz_desc[128] = "\0";
+ char psz_dura[128] = "\0";
+ char psz_size[128] = "\0";
+ char psz_flag[128] = "\0";
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
+ snprintf(psz_base, sizeof(psz_base), "base offset %"PRId64, p_box->data.p_tfhd->i_base_data_offset);
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
+ snprintf(psz_desc, sizeof(psz_desc), "sample description index %d", p_box->data.p_tfhd->i_sample_description_index);
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
+ snprintf(psz_dura, sizeof(psz_dura), "sample duration %d", p_box->data.p_tfhd->i_default_sample_duration);
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
+ snprintf(psz_size, sizeof(psz_size), "sample size %d", p_box->data.p_tfhd->i_default_sample_size);
+ if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
+ snprintf(psz_flag, sizeof(psz_flag), "sample flags 0x%x", p_box->data.p_tfhd->i_default_sample_flags);
+
+ msg_Dbg( p_stream, "read box: \"tfhd\" version %d flags 0x%x track ID %d %s %s %s %s %s",
+ p_box->data.p_tfhd->i_version,
+ p_box->data.p_tfhd->i_flags,
+ p_box->data.p_tfhd->i_track_ID,
+ psz_base, psz_desc, psz_dura, psz_size, psz_flag );
+#endif
+
+ MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_trun( stream_t *p_stream, MP4_Box_t *p_box )
+{
+ MP4_READBOX_ENTER( MP4_Box_data_trun_t );
+
+ MP4_GETVERSIONFLAGS( p_box->data.p_trun );
+
+ MP4_GET4BYTES( p_box->data.p_trun->i_sample_count );
+
+ if( p_box->data.p_trun->i_flags & MP4_TRUN_DATA_OFFSET )
+ MP4_GET4BYTES( p_box->data.p_trun->i_data_offset );
+ if( p_box->data.p_trun->i_flags & MP4_TRUN_FIRST_FLAGS )
+ MP4_GET4BYTES( p_box->data.p_trun->i_first_sample_flags );
+
+ p_box->data.p_trun->p_samples =
+ calloc( p_box->data.p_trun->i_sample_count, sizeof(MP4_descriptor_trun_sample_t) );
+ if ( p_box->data.p_trun->p_samples == NULL )
+ MP4_READBOX_EXIT( 0 );
+
+ for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
+ {
+ MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
+ if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION )
+ MP4_GET4BYTES( p_sample->i_duration );
+ if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE )
+ MP4_GET4BYTES( p_sample->i_size );
+ if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_FLAGS )
+ MP4_GET4BYTES( p_sample->i_flags );
+ if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET )
+ MP4_GET4BYTES( p_sample->i_composition_time_offset );
+ }
+
+#ifdef MP4_VERBOSE
+ msg_Dbg( p_stream, "read box: \"trun\" version %u flags 0x%x sample count %u",
+ p_box->data.p_trun->i_version,
+ p_box->data.p_trun->i_flags,
+ p_box->data.p_trun->i_sample_count );
+
+ for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
+ {
+ MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
+ msg_Dbg( p_stream, "read box: \"trun\" sample %4.4u flags 0x%x "\
+ "duration %"PRIu32" size %"PRIu32" composition time offset %"PRIu32,
+ i, p_sample->i_flags, p_sample->i_duration,
+ p_sample->i_size, p_sample->i_composition_time_offset );
+ }
+#endif
+
+ MP4_READBOX_EXIT( 1 );
+}
+
+static void MP4_FreeBox_trun( MP4_Box_t *p_box )
+{
+ FREENULL( p_box->data.p_trun->p_samples );
+}
+
+