]> git.sesse.net Git - vlc/blobdiff - modules/stream_filter/smooth/downloader.c
stream_filter: smooth: fix segfault
[vlc] / modules / stream_filter / smooth / downloader.c
index 39079ded5d26d2752724810380b68cc330af853e..8400fc1c8513dbcbf55ac689323574bb8e411045 100644 (file)
@@ -135,39 +135,6 @@ static chunk_t * chunk_Get( sms_stream_t *sms, const uint64_t start_time )
     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 );
@@ -295,168 +262,152 @@ BandwidthAdaptation( stream_t *s, sms_stream_t *sms,
 }
 #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;
 }
@@ -467,15 +418,9 @@ static chunk_t *build_init_chunk( stream_t *s )
     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" );
@@ -490,13 +435,6 @@ static int Download( stream_t *s, sms_stream_t *sms )
     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 )
     {
@@ -544,17 +482,7 @@ static int Download( stream_t *s, sms_stream_t *sms )
     }
     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 );