return p_chunk;
}
-static unsigned set_track_id( chunk_t *chunk, const unsigned tid )
-{
- uint32_t size, type;
- if( !chunk->data || chunk->size < 32 )
- return 0;
- uint8_t *slice = chunk->data;
- if( !slice )
- return 0;
-
- SMS_GET4BYTES( size );
- SMS_GETFOURCC( type );
- assert( type == ATOM_moof );
-
- SMS_GET4BYTES( size );
- SMS_GETFOURCC( type );
- assert( type == ATOM_mfhd );
- slice += size - 8;
-
- SMS_GET4BYTES( size );
- SMS_GETFOURCC( type );
- assert( type == ATOM_traf );
-
- SMS_GET4BYTES( size );
- SMS_GETFOURCC( type );
- if( type != ATOM_tfhd )
- return 0;
-
- unsigned ret = bswap32( ((uint32_t *)slice)[1] );
- ((uint32_t *)slice)[1] = bswap32( tid );
-
- return ret;
-}
-
static int sms_Download( stream_t *s, chunk_t *chunk, char *url )
{
stream_t *p_ts = stream_UrlNew( s, url );
}
#endif
-static int get_new_chunks( stream_t *s, chunk_t *ck, sms_stream_t *sms )
+static int parse_chunk( stream_t *s, chunk_t *ck, sms_stream_t *sms )
{
- stream_sys_t *p_sys = s->p_sys;
-
- uint8_t *slice = ck->data;
- if( !slice )
+ if( ck->size < 24 )
return VLC_EGENERIC;
- uint8_t version, fragment_count;
- uint32_t size, type, flags;
- UUID_t uuid;
- TfrfBoxDataFields_t *tfrf_df;
- SMS_GET4BYTES( size );
- SMS_GETFOURCC( type );
- assert( type == ATOM_moof );
+ stream_t *ck_s = stream_MemoryNew( s, ck->data, ck->size, true );
+ if ( !ck_s )
+ return VLC_EGENERIC;
- SMS_GET4BYTES( size );
- SMS_GETFOURCC( type );
- assert( type == ATOM_mfhd );
- slice += size - 8;
+ MP4_Box_t root_box = { 0 };
+ root_box.i_type = ATOM_root;
+ root_box.i_size = ck->size;
+ if ( MP4_ReadBoxContainerChildren( ck_s, &root_box, 0 ) != 1 )
+ {
+ stream_Delete( ck_s );
+ return VLC_EGENERIC;
+ }
+#ifndef NDEBUG
+ MP4_BoxDumpStructure( ck_s, &root_box );
+#endif
- SMS_GET4BYTES( size );
- SMS_GETFOURCC( type );
- assert( type == ATOM_traf );
+ /* Do track ID fixup */
+ const MP4_Box_t *tfhd_box = MP4_BoxGet( &root_box, "moof/traf/tfhd" );
+ if ( tfhd_box )
+ SetDWBE( &ck->data[tfhd_box->i_pos + 8 + 4], sms->id );
- for(;;)
+ if ( s->p_sys->b_live )
{
- SMS_GET4BYTES( size );
- assert( size > 1 );
- SMS_GETFOURCC( type );
- if( type == ATOM_mdat )
+ const MP4_Box_t *uuid_box = MP4_BoxGet( &root_box, "moof/traf/uuid" );
+ while( uuid_box && uuid_box->i_type == ATOM_uuid )
{
- msg_Err( s, "No uuid box found :-(" );
- return VLC_EGENERIC;
- }
- else if( type == ATOM_uuid )
- {
- GetUUID( &uuid, slice);
- if( !CmpUUID( &uuid, &TfrfBoxUUID ) )
+ if ( !CmpUUID( &uuid_box->i_uuid, &TfrfBoxUUID ) )
break;
+ uuid_box = uuid_box->p_next;
}
- slice += size - 8;
- }
-
- slice += 16;
- SMS_GET1BYTE( version );
- SMS_GET3BYTES( flags );
- SMS_GET1BYTE( fragment_count );
-
- tfrf_df = calloc( fragment_count, sizeof( TfrfBoxDataFields_t ) );
- if( unlikely( tfrf_df == NULL ) )
- return VLC_EGENERIC;
- for( uint8_t i = 0; i < fragment_count; i++ )
- {
- SMS_GET4or8BYTES( tfrf_df[i].i_fragment_abs_time );
- SMS_GET4or8BYTES( tfrf_df[i].i_fragment_duration );
+ if ( uuid_box )
+ {
+ const MP4_Box_data_tfrf_t *p_tfrfdata = uuid_box->data.p_tfrf;
+ for ( uint8_t i=0; i<p_tfrfdata->i_fragment_count; i++ )
+ {
+ uint64_t dur = p_tfrfdata->p_tfrf_data_fields[i].i_fragment_duration;
+ uint64_t stime = p_tfrfdata->p_tfrf_data_fields[i].i_fragment_abs_time;
+ msg_Dbg( s, "\"tfrf\" fragment duration %"PRIu64", "
+ "fragment abs time %"PRIu64, dur, stime );
+ if( !chunk_Get( sms, stime + dur ) )
+ chunk_AppendNew( sms, dur, stime );
+ }
+ }
}
- msg_Dbg( s, "read box: \"tfrf\" version %d, flags 0x%x, "\
- "fragment count %"PRIu8, version, flags, fragment_count );
-
- for( uint8_t i = 0; i < fragment_count; i++ )
+ MP4_Box_t *p_box = root_box.p_first;
+ while( p_box )
{
- uint64_t dur = tfrf_df[i].i_fragment_duration;
- uint64_t stime = tfrf_df[i].i_fragment_abs_time;
- msg_Dbg( s, "\"tfrf\" fragment duration %"PRIu64", "\
- "fragment abs time %"PRIu64, dur, stime);
-
- if( !chunk_Get( sms, stime + dur ) )
- chunk_AppendNew( sms, dur, stime );
+ MP4_BoxFree( ck_s, p_box );
+ p_box = p_box->p_next;
}
- free( tfrf_df );
+ stream_Delete( ck_s );
return VLC_SUCCESS;
}
#define STRA_SIZE 334
-#define SMOO_SIZE (STRA_SIZE * 3 + 24) /* 1026 */
+//#define SMOO_SIZE (STRA_SIZE * 3 + 24) /* 1026 */
/* SmooBox is a very simple MP4 box, used only to pass information
* to the demux layer. As this box is not aimed to travel accross networks,
* simplicity of the design is better than compactness */
-static int build_smoo_box( stream_t *s, uint8_t *smoo_box )
+static int build_smoo_box( stream_t *s, chunk_t *p_chunk )
{
stream_sys_t *p_sys = s->p_sys;
- sms_stream_t *sms = NULL;
uint32_t FourCC;
/* smoo */
- memset( smoo_box, 0, SMOO_SIZE );
- smoo_box[2] = (SMOO_SIZE & 0xff00)>>8;
- smoo_box[3] = SMOO_SIZE & 0xff;
+ assert(p_sys->sms_selected.i_size);
+ size_t i_size = p_sys->sms_selected.i_size * STRA_SIZE + 24;
+ p_chunk->data = calloc( 1, i_size );
+ if ( !p_chunk->data )
+ return VLC_EGENERIC;
+ p_chunk->size = i_size;
+ uint8_t *smoo_box = p_chunk->data;
+
+ SetWBE( &smoo_box[2], i_size );
smoo_box[4] = 'u';
smoo_box[5] = 'u';
smoo_box[6] = 'i';
smoo_box[7] = 'd';
+ uint32_t *smoo_box32 = (uint32_t *)smoo_box;
/* UUID is e1da72ba-24d7-43c3-a6a5-1b5759a1a92c */
- ((uint32_t *)smoo_box)[2] = bswap32( 0xe1da72ba );
- ((uint32_t *)smoo_box)[3] = bswap32( 0x24d743c3 );
- ((uint32_t *)smoo_box)[4] = bswap32( 0xa6a51b57 );
- ((uint32_t *)smoo_box)[5] = bswap32( 0x59a1a92c );
+ SetDWBE( &smoo_box32[2], 0xe1da72ba );
+ SetDWBE( &smoo_box32[3], 0x24d743c3 );
+ SetDWBE( &smoo_box32[4], 0xa6a51b57 );
+ SetDWBE( &smoo_box32[5], 0x59a1a92c );
- uint8_t *stra_box;
- for( int i = 0; i < 3; i++ )
- {
- sms = NULL;
- int cat = UNKNOWN_ES;
- stra_box = smoo_box + i * STRA_SIZE;
-
- stra_box[26] = (STRA_SIZE & 0xff00)>>8;
- stra_box[27] = STRA_SIZE & 0xff;
- stra_box[28] = 'u';
- stra_box[29] = 'u';
- stra_box[30] = 'i';
- stra_box[31] = 'd';
-
- /* UUID is b03ef770-33bd-4bac-96c7-bf25f97e2447 */
- ((uint32_t *)stra_box)[8] = bswap32( 0xb03ef770 );
- ((uint32_t *)stra_box)[9] = bswap32( 0x33bd4bac );
- ((uint32_t *)stra_box)[10] = bswap32( 0x96c7bf25 );
- ((uint32_t *)stra_box)[11] = bswap32( 0xf97e2447 );
-
- cat = index_to_es_cat( i );
- stra_box[48] = cat;
- sms = SMS_GET_SELECTED_ST( cat );
-
- stra_box[49] = 0; /* reserved */
- if( sms == NULL )
+ int i = 0;
+ FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
+ uint8_t *stra_box = smoo_box + i++ * STRA_SIZE;
+ uint16_t *stra_box16 = (uint16_t *)stra_box;
+ uint32_t *stra_box32 = (uint32_t *)stra_box;
+ uint64_t *stra_box64 = (uint64_t *)stra_box;
+
+ SetWBE( &stra_box[26], STRA_SIZE );
+ stra_box[28] = 'u';
+ stra_box[29] = 'u';
+ stra_box[30] = 'i';
+ stra_box[31] = 'd';
+
+ /* UUID is b03ef770-33bd-4bac-96c7-bf25f97e2447 */
+ SetDWBE( &stra_box32[8], 0xb03ef770 );
+ SetDWBE( &stra_box32[9], 0x33bd4bac );
+ SetDWBE( &stra_box32[10], 0x96c7bf25 );
+ SetDWBE( &stra_box32[11], 0xf97e2447 );
+
+ stra_box[48] = sms->type;
+ stra_box[49] = 0; /* reserved */
+ SetWBE( &stra_box[50], sms->id );
+
+ SetDWBE( &stra_box32[13], sms->timescale );
+ SetQWBE( &stra_box64[7], p_sys->vod_duration );
+
+ const quality_level_t *qlvl = sms->current_qlvl;
+ if ( qlvl )
+ {
+ FourCC = qlvl->FourCC ? qlvl->FourCC : sms->default_FourCC;
+ SetDWBE( &stra_box32[16], FourCC );
+ SetDWBE( &stra_box32[17], qlvl->Bitrate );
+ SetDWBE( &stra_box32[18], qlvl->MaxWidth );
+ SetDWBE( &stra_box32[19], qlvl->MaxHeight );
+ SetDWBE( &stra_box32[20], qlvl->SamplingRate );
+ SetDWBE( &stra_box32[21], qlvl->Channels );
+ SetDWBE( &stra_box32[22], qlvl->BitsPerSample );
+ SetDWBE( &stra_box32[23], qlvl->AudioTag );
+ SetWBE( &stra_box16[48], qlvl->nBlockAlign );
+
+ if( !qlvl->CodecPrivateData )
continue;
- stra_box[50] = (sms->id & 0xff00)>>8;
- stra_box[51] = sms->id & 0xff;
-
- ((uint32_t *)stra_box)[13] = bswap32( sms->timescale );
- ((uint64_t *)stra_box)[7] = bswap64( p_sys->vod_duration );
-
- const quality_level_t *qlvl = sms->current_qlvl;
- if ( qlvl )
- {
- FourCC = qlvl->FourCC ? qlvl->FourCC : sms->default_FourCC;
- ((uint32_t *)stra_box)[16] = bswap32( FourCC );
- ((uint32_t *)stra_box)[17] = bswap32( qlvl->Bitrate );
- ((uint32_t *)stra_box)[18] = bswap32( qlvl->MaxWidth );
- ((uint32_t *)stra_box)[19] = bswap32( qlvl->MaxHeight );
- ((uint32_t *)stra_box)[20] = bswap32( qlvl->SamplingRate );
- ((uint32_t *)stra_box)[21] = bswap32( qlvl->Channels );
- ((uint32_t *)stra_box)[22] = bswap32( qlvl->BitsPerSample );
- ((uint32_t *)stra_box)[23] = bswap32( qlvl->AudioTag );
- ((uint16_t *)stra_box)[48] = bswap16( qlvl->nBlockAlign );
-
- if( !qlvl->CodecPrivateData )
- continue;
- stra_box[98] = stra_box[99] = stra_box[100] = 0; /* reserved */
- stra_box[101] = strlen( qlvl->CodecPrivateData ) / 2;
- if ( stra_box[101] > STRA_SIZE - 102 )
- stra_box[101] = STRA_SIZE - 102;
- uint8_t *binary_cpd = decode_string_hex_to_binary( qlvl->CodecPrivateData );
- memcpy( stra_box + 102, binary_cpd, stra_box[101] );
- free( binary_cpd );
- }
+ stra_box[98] = stra_box[99] = stra_box[100] = 0; /* reserved */
+ stra_box[101] = strlen( qlvl->CodecPrivateData ) / 2;
+ if ( stra_box[101] > STRA_SIZE - 102 )
+ stra_box[101] = STRA_SIZE - 102;
+ uint8_t *binary_cpd = decode_string_hex_to_binary( qlvl->CodecPrivateData );
+ memcpy( stra_box + 102, binary_cpd, stra_box[101] );
+ free( binary_cpd );
}
+ FOREACH_END();
return VLC_SUCCESS;
}
if( unlikely( ret == NULL ) )
goto build_init_chunk_error;
- ret->size = SMOO_SIZE;
- ret->data = malloc( SMOO_SIZE );
- if( !ret->data )
- goto build_init_chunk_error;
-
- if( build_smoo_box( s, ret->data ) == VLC_SUCCESS)
+ if( build_smoo_box( s, ret ) == VLC_SUCCESS )
return ret;
- free( ret->data );
build_init_chunk_error:
free( ret );
msg_Err( s, "build_init_chunk failed" );
assert( sms->p_nextdownload->data == NULL );
assert( sms->current_qlvl );
- int index = es_cat_to_index( sms->type );
- if ( unlikely( index == -1 ) )
- {
- msg_Err( s, "invalid stream type" );
- return VLC_EGENERIC;
- }
-
chunk_t *chunk = sms->p_nextdownload;
if( !chunk )
{
}
duration = mdate() - duration;
- unsigned real_id = set_track_id( chunk, sms->id );
- if( real_id == 0)
- {
- msg_Err( s, "tfhd box not found or invalid chunk" );
- return VLC_EGENERIC;
- }
-
- if( p_sys->b_live )
- {
- get_new_chunks( s, chunk, sms );
- }
+ parse_chunk( s, chunk, sms );
msg_Info( s, "downloaded chunk @%"PRIu64" from stream %s at quality %u",
chunk->start_time, sms->name, sms->current_qlvl->Bitrate );