smooth: provide PTS delay
[vlc.git] / modules / stream_filter / smooth / smooth.c
index 08bf8ed..3189c32 100644 (file)
@@ -15,7 +15,7 @@
  *
  * This library is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
@@ -103,7 +103,7 @@ static bool isSmoothStreaming( stream_t *s )
         }
         peeked = FromCharset( encoding, peeked, 512 );
 
-        if( strstr( peeked, needle ) != NULL )
+        if( peeked != NULL && strstr( peeked, needle ) != NULL )
             ret = true;
     }
     free( peeked );
@@ -146,9 +146,7 @@ static int parse_Manifest( stream_t *s )
     }
 
     const char *node;
-    char *stream_name = NULL;
     uint8_t *WaveFormatEx;
-    int stream_type = UNKNOWN_ES;
     sms_stream_t *sms = NULL;
     quality_level_t *ql = NULL;
     int64_t start_time = 0, duration = 0;
@@ -192,17 +190,20 @@ static int parse_Manifest( stream_t *s )
                         if( !strcmp( name, "Type" ) )
                         {
                             if( !strcmp( value, "video" ) )
-                                stream_type = VIDEO_ES;
+                                sms->type = VIDEO_ES;
                             else if( !strcmp( value, "audio" ) )
-                                stream_type = AUDIO_ES;
+                                sms->type = AUDIO_ES;
                             else if( !strcmp( value, "text" ) )
-                                stream_type = SPU_ES;
+                                sms->type = SPU_ES;
                         }
 
                         if( !strcmp( name, "Name" ) )
-                            stream_name = strdup( value );
+                            sms->name = strdup( value );
                         if( !strcmp( name, "TimeScale" ) )
                             sms->timescale = strtoull( value, NULL, 10 );
+                        if( !strcmp( name, "FourCC" ) )
+                            sms->default_FourCC =
+                                VLC_FOURCC( value[0], value[1], value[2], value[3] );
 
                         if( !strcmp( name, "Chunks" ) )
                         {
@@ -219,18 +220,16 @@ static int parse_Manifest( stream_t *s )
 
                     if( sms && !sms->timescale )
                         sms->timescale = TIMESCALE;
-                    if( !stream_name )
+                    if( !sms->name )
                     {
-                        if( stream_type == VIDEO_ES )
-                            stream_name = strdup( "video" );
-                        else if( stream_type == AUDIO_ES )
-                            stream_name = strdup( "audio" );
-                        else if( stream_type == SPU_ES )
-                            stream_name = strdup( "text" );
+                        if( sms->type == VIDEO_ES )
+                            sms->name = strdup( "video" );
+                        else if( sms->type == AUDIO_ES )
+                            sms->name = strdup( "audio" );
+                        else if( sms->type == SPU_ES )
+                            sms->name = strdup( "text" );
                     }
 
-                    sms->name = stream_name;
-                    sms->type = stream_type;
                     vlc_array_append( p_sys->sms_streams, sms );
                 }
 
@@ -247,6 +246,8 @@ static int parse_Manifest( stream_t *s )
                             ql->Index = strtol( value, NULL, 10 );
                         if( !strcmp( name, "Bitrate" ) )
                             ql->Bitrate = strtoull( value, NULL, 10 );
+                        if( !strcmp( name, "PacketSize" ) )
+                            ql->nBlockAlign = strtoull( value, NULL, 10 );
                         if( !strcmp( name, "FourCC" ) )
                             ql->FourCC = VLC_FOURCC( value[0], value[1],
                                                      value[2], value[3] );
@@ -263,7 +264,6 @@ static int parse_Manifest( stream_t *s )
 
                             ql->Channels = ((uint16_t *)WaveFormatEx)[1];
                             ql->SamplingRate = ((uint32_t *)WaveFormatEx)[1];
-                            ql->AvgBytesPerSec = ((uint32_t *)WaveFormatEx)[2];
                             ql->nBlockAlign = ((uint16_t *)WaveFormatEx)[6];
                             ql->BitsPerSample = ((uint16_t *)WaveFormatEx)[7];
                             free( WaveFormatEx );
@@ -342,8 +342,6 @@ static int parse_Manifest( stream_t *s )
                 if( strcmp( node, "StreamIndex" ) )
                     break;
 
-                stream_name = NULL;
-                stream_type = UNKNOWN_ES;
                 computed_start_time = 0;
                 computed_duration = 0;
                 loop_count = 0;
@@ -403,8 +401,11 @@ static int Open( vlc_object_t *p_this )
     p_sys->b_cache = false;
 
     p_sys->sms_streams = vlc_array_new();
+    p_sys->selected_st = vlc_array_new();
     p_sys->download.chunks = vlc_array_new();
-    if( unlikely( !p_sys->sms_streams || !p_sys->download.chunks ) )
+    p_sys->init_chunks = vlc_array_new();
+    if( unlikely( !p_sys->sms_streams || !p_sys->download.chunks ||
+                  !p_sys->selected_st || !p_sys->init_chunks ) )
     {
         free( p_sys );
         return VLC_ENOMEM;
@@ -422,34 +423,14 @@ static int Open( vlc_object_t *p_this )
 
     p_sys->i_tracks = vlc_array_count( p_sys->sms_streams );
 
-    /* FIXME */
-    p_sys->i_selected_tracks = 2; /* one video track and one audio track */
-
-    /* Choose first video stream available */
-    sms_stream_t *vsms = NULL;
-    for( unsigned i = 0; i < p_sys->i_tracks; i++ )
-    {
-        vsms = vlc_array_item_at_index( p_sys->sms_streams, i );
-        if( vsms->type == VIDEO_ES )
-        {
-            msg_Dbg( s, "Video stream chosen is %s", vsms->name );
-            p_sys->vstream = vsms;
-            break;
-        }
-    }
-
-    /* Choose first audio stream available */
-    sms_stream_t *asms = NULL;
+    /* Choose first video / audio / subtitle stream available */
+    sms_stream_t *tmp = NULL, *selected = NULL;
     for( unsigned i = 0; i < p_sys->i_tracks; i++ )
     {
-        asms = vlc_array_item_at_index( p_sys->sms_streams, i );
-        //if( asms->type == AUDIO_ES && !strcmp( asms->name, "audio_eng" ) )
-        if( asms->type == AUDIO_ES )
-        {
-            msg_Dbg( s, "Audio stream chosen is %s", asms->name );
-            p_sys->astream = asms;
-            break;
-        }
+        tmp = vlc_array_item_at_index( p_sys->sms_streams, i );
+        selected = SMS_GET_SELECTED_ST( tmp->type );
+        if( !selected )
+            vlc_array_append( p_sys->selected_st, tmp );
     }
 
     /* Choose lowest quality for the first chunks */
@@ -497,7 +478,8 @@ static void Close( vlc_object_t *p_this )
     vlc_mutex_lock( &p_sys->download.lock_wait );
     p_sys->b_close = true;
     /* Negate the condition variable's predicate */
-    p_sys->download.vlead = p_sys->download.alead = 0;
+    for( int i = 0; i < 3; i++ )
+        p_sys->download.lead[i] = 0;
     p_sys->playback.toffset = 0;
     vlc_cond_signal(&p_sys->download.wait);
     vlc_mutex_unlock( &p_sys->download.lock_wait );
@@ -511,12 +493,22 @@ static void Close( vlc_object_t *p_this )
     for( int i = 0; i < vlc_array_count( p_sys->sms_streams ); i++ )
     {
         sms = vlc_array_item_at_index( p_sys->sms_streams, i );
-        if( sms)
+        if( sms )
             sms_Free( sms );
     }
+    /* Free downloaded chunks */
+    chunk_t *chunk;
+    for( int i = 0; i < vlc_array_count( p_sys->init_chunks ); i++ )
+    {
+        chunk = vlc_array_item_at_index( p_sys->init_chunks, i );
+        chunk_Free( chunk );
+    }
 
+    sms_queue_free( p_sys->bws );
     vlc_array_destroy( p_sys->sms_streams );
+    vlc_array_destroy( p_sys->selected_st );
     vlc_array_destroy( p_sys->download.chunks );
+    vlc_array_destroy( p_sys->init_chunks );
 
     free( p_sys->base_url );
     free( p_sys );
@@ -536,16 +528,14 @@ static chunk_t *get_chunk( stream_t *s, const bool wait )
          * that's why vlc_object_alive() has been deprecated. But if I
          * understood well, there is no good solution with a stream_filter
          * module anyaway. */
-        if( !wait || s->b_die || p_sys->b_error )
+        if( !wait || p_sys->b_error )
         {
             vlc_mutex_unlock( &p_sys->download.lock_wait );
             msg_Warn( s, "get_chunk failed! (playback index %u)",
                     p_sys->playback.index );
             return NULL;
         }
-        if( !p_sys->b_live &&
-            p_sys->download.aindex >= (p_sys->vstream->vod_chunks_nb -1) &&
-            p_sys->download.vindex >= (p_sys->astream->vod_chunks_nb -1) )
+        if( NO_MORE_CHUNKS )
         {
             vlc_mutex_unlock( &p_sys->download.lock_wait );
             msg_Info( s, "No more chunks, end of the VOD" );
@@ -579,7 +569,8 @@ static int sms_Read( stream_t *s, uint8_t *p_read, int i_read )
 
         if( chunk->read_pos >= (int)chunk->size )
         {
-            if( chunk->type == VIDEO_ES || !p_sys->vstream )
+            if( chunk->type == VIDEO_ES ||
+                ( !SMS_GET_SELECTED_ST( VIDEO_ES ) && chunk->type == AUDIO_ES ) )
             {
                 vlc_mutex_lock( &p_sys->download.lock_wait );
                 p_sys->playback.toffset += chunk->duration;
@@ -588,8 +579,8 @@ static int sms_Read( stream_t *s, uint8_t *p_read, int i_read )
             }
             if( !p_sys->b_cache || p_sys->b_live )
             {
-                block_Release( chunk->data );
-                chunk->data = NULL;
+                FREENULL( chunk->data );
+                chunk->read_pos = 0;
             }
 
             chunk->read_pos = 0;
@@ -607,14 +598,14 @@ static int sms_Read( stream_t *s, uint8_t *p_read, int i_read )
                         verb, chunk->sequence, i_read, chunk->type );
             /* check integrity */
             uint32_t type;
-            uint8_t *slice = chunk->data->p_buffer;
+            uint8_t *slice = chunk->data;
             SMS_GET4BYTES( type );
             SMS_GETFOURCC( type );
             assert( type == ATOM_moof || type == ATOM_uuid );
         }
 
         int len = -1;
-        uint8_t *src = chunk->data->p_buffer + chunk->read_pos;
+        uint8_t *src = chunk->data + chunk->read_pos;
         if( i_read <= chunk->size - chunk->read_pos )
             len = i_read;
         else
@@ -673,7 +664,7 @@ static int Peek( stream_t *s, const uint8_t **pp_peek, unsigned i_peek )
         msg_Err( s, "could not peek %u bytes, only %i!", i_peek, bytes );
     }
     msg_Dbg( s, "peeking at chunk %u!", chunk->sequence );
-    *pp_peek = chunk->data->p_buffer + chunk->read_pos;
+    *pp_peek = chunk->data + chunk->read_pos;
 
     return bytes;
 }
@@ -726,7 +717,8 @@ static int chunk_Seek( stream_t *s, const uint64_t pos )
 
         p_sys->b_tseek = true;
         p_sys->time_pos = p_sys->vod_duration * pos / FAKE_STREAM_SIZE;
-        p_sys->download.vlead = p_sys->download.alead = 0;
+        for( int i = 0; i < 3; i++ )
+            p_sys->download.lead[i] = 0;
         p_sys->playback.toffset = 0;
 
         vlc_cond_signal( &p_sys->download.wait);
@@ -746,6 +738,8 @@ static int Control( stream_t *s, int i_query, va_list args )
             *(va_arg( args, bool * )) = true;
             break;
         case STREAM_CAN_FASTSEEK:
+        case STREAM_CAN_PAUSE: /* TODO */
+        case STREAM_CAN_CONTROL_PACE:
             *(va_arg( args, bool * )) = false;
             break;
         case STREAM_GET_POSITION:
@@ -763,6 +757,10 @@ static int Control( stream_t *s, int i_query, va_list args )
         case STREAM_GET_SIZE:
             *(va_arg( args, uint64_t * )) = FAKE_STREAM_SIZE;
             break;
+        case STREAM_GET_PTS_DELAY:
+            *va_arg (args, int64_t *) =
+                var_InheritInteger(s, "network-caching");
+             break;
         default:
             return VLC_EGENERIC;
     }