]> git.sesse.net Git - vlc/blobdiff - src/input/input.c
Remove uninitialized and unsynchronized global stats
[vlc] / src / input / input.c
index 5a2745285b305922a41a8ddadc18838602986eef..7d05ae2f1d105ac19673d0d35292028d33253635 100644 (file)
@@ -73,7 +73,7 @@ static void             MainLoop( input_thread_t *p_input );
 
 static void ObjectKillChildrens( input_thread_t *, vlc_object_t * );
 
-static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline );
+static inline int ControlPop( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline );
 static void       ControlReduce( input_thread_t * );
 static bool Control( input_thread_t *, int, vlc_value_t );
 
@@ -149,17 +149,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     if( !p_input->p )
         return NULL;
 
-    /* One "randomly" selected input thread is responsible for computing
-     * the global stats. Check if there is already someone doing this */
-    if( p_input->p_libvlc->p_stats && !b_quick )
-    {
-        libvlc_priv_t *p_private = libvlc_priv( p_input->p_libvlc );
-        vlc_mutex_lock( &p_input->p_libvlc->p_stats->lock );
-        if( p_private->p_stats_computer == NULL )
-            p_private->p_stats_computer = p_input;
-        vlc_mutex_unlock( &p_input->p_libvlc->p_stats->lock );
-    }
-
     p_input->b_preparsing = b_quick;
     p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
 
@@ -183,8 +172,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     p_input->p->p_es_out = NULL;
     p_input->p->p_sout   = NULL;
     p_input->p->b_out_pace_control = false;
-    p_input->p->i_pts_delay = 0;
-    p_input->p->i_cr_average = 0;
 
     vlc_gc_incref( p_item ); /* Released in Destructor() */
     p_input->p->p_item = p_item;
@@ -239,8 +226,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     input_ControlVarInit( p_input );
 
     /* */
-    p_input->p->i_cr_average = var_GetInteger( p_input, "cr-average" );
-
     if( !p_input->b_preparsing )
     {
         var_Get( p_input, "bookmarks", &val );
@@ -416,13 +401,13 @@ int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
 
 /**
  * Initialize an input and initialize it to preparse the item
- * This function is blocking. It will only accept to parse files
+ * This function is blocking. It will only accept parsing regular files.
  *
  * \param p_parent a vlc_object_t
  * \param p_item an input item
  * \return VLC_SUCCESS or an error
  */
-int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
+int input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
 {
     input_thread_t *p_input;
 
@@ -489,11 +474,10 @@ static void ObjectKillChildrens( input_thread_t *p_input, vlc_object_t *p_obj )
     int i;
 
     /* FIXME ObjectKillChildrens seems a very bad idea in fact */
-    if( p_obj->i_object_type == VLC_OBJECT_VOUT ||
-        p_obj->i_object_type == VLC_OBJECT_AOUT ||
+    i = vlc_internals( p_obj )->i_object_type;
+    if( i == VLC_OBJECT_VOUT ||i == VLC_OBJECT_AOUT ||
         p_obj == VLC_OBJECT(p_input->p->p_sout) ||
-        p_obj->i_object_type == VLC_OBJECT_DECODER ||
-        p_obj->i_object_type == VLC_OBJECT_PACKETIZER )
+        i == VLC_OBJECT_DECODER || i == VLC_OBJECT_PACKETIZER )
         return;
 
     vlc_object_kill( p_obj );
@@ -705,12 +689,6 @@ static void MainLoopInterface( input_thread_t *p_input )
 static void MainLoopStatistic( input_thread_t *p_input )
 {
     stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
-    /* Are we the thread responsible for computing global stats ? */
-    if( libvlc_priv( p_input->p_libvlc )->p_stats_computer == p_input )
-    {
-        stats_ComputeGlobalStats( p_input->p_libvlc,
-                                  p_input->p_libvlc->p_stats );
-    }
     input_SendEventStatistics( p_input );
 }
 
@@ -772,16 +750,15 @@ static void MainLoop( input_thread_t *p_input )
                 i_deadline = __MIN( i_intf_update, i_statistic_update );
 
             /* Handle control */
-            vlc_mutex_lock( &p_input->p->lock_control );
             ControlReduce( p_input );
-            while( !ControlPopNoLock( p_input, &i_type, &val, i_deadline ) )
+            while( !ControlPop( p_input, &i_type, &val, i_deadline ) )
             {
+
                 msg_Dbg( p_input, "control type=%d", i_type );
 
                 if( Control( p_input, i_type, val ) )
                     b_force_update = true;
             }
-            vlc_mutex_unlock( &p_input->p->lock_control );
 
             /* Update interface and statistics */
             i_current = mdate();
@@ -897,29 +874,13 @@ static void InitTitle( input_thread_t * p_input )
     {
         /* Setup variables */
         input_ControlVarNavigation( p_input );
-        input_ControlVarTitle( p_input, 0 );
+        input_SendEventTitle( p_input, 0 );
     }
 
     /* Global flag */
     p_input->p->b_can_pace_control    = p_master->b_can_pace_control;
     p_input->p->b_can_pause        = p_master->b_can_pause;
     p_input->p->b_can_rate_control = p_master->b_can_rate_control;
-
-    /* Fix pts delay */
-    if( p_input->p->i_pts_delay < 0 )
-        p_input->p->i_pts_delay = 0;
-
-    /* If the desynchronisation requested by the user is < 0, we need to
-     * cache more data. */
-    const int i_desynch = var_GetInteger( p_input, "audio-desync" );
-    if( i_desynch < 0 )
-        p_input->p->i_pts_delay -= i_desynch * 1000;
-
-    /* Update cr_average depending on the caching */
-    p_input->p->i_cr_average *= (10 * p_input->p->i_pts_delay / 200000);
-    p_input->p->i_cr_average /= 10;
-    if( p_input->p->i_cr_average < 10 )
-        p_input->p->i_cr_average = 10;
 }
 
 static void StartTitle( input_thread_t * p_input )
@@ -970,6 +931,7 @@ static void StartTitle( input_thread_t * p_input )
         msg_Warn( p_input, "invalid stop-time ignored" );
         p_input->p->i_stop = 0;
     }
+    p_input->p->b_fast_seek = var_GetBool( p_input, "input-fast-seek" );
 }
 
 static void LoadSubtitles( input_thread_t *p_input )
@@ -1060,11 +1022,40 @@ static void LoadSlaves( input_thread_t *p_input )
     free( psz_org );
 }
 
+static void UpdatePtsDelay( input_thread_t *p_input )
+{
+    input_thread_private_t *p_sys = p_input->p;
+
+    /* Get max pts delay from input source */
+    mtime_t i_pts_delay = p_sys->input.i_pts_delay;
+    for( int i = 0; i < p_sys->i_slave; i++ )
+        i_pts_delay = __MAX( i_pts_delay, p_sys->slave[i]->i_pts_delay );
+
+    if( i_pts_delay < 0 )
+        i_pts_delay = 0;
+
+    /* Take care of audio/spu delay */
+    const mtime_t i_audio_delay = var_GetTime( p_input, "audio-delay" );
+    const mtime_t i_spu_delay   = var_GetTime( p_input, "spu-delay" );
+    const mtime_t i_extra_delay = __MIN( i_audio_delay, i_spu_delay );
+    if( i_extra_delay < 0 )
+        i_pts_delay -= i_extra_delay;
+
+    /* Update cr_average depending on the caching */
+    const int i_cr_average = var_GetInteger( p_input, "cr-average" ) * i_pts_delay / DEFAULT_PTS_DELAY;
+
+    /* */
+    es_out_SetJitter( p_input->p->p_es_out, i_pts_delay, i_cr_average );
+}
+
 static void InitPrograms( input_thread_t * p_input )
 {
     int i_es_out_mode;
     vlc_value_t val;
 
+    /* Compute correct pts_delay */
+    UpdatePtsDelay( p_input );
+
     /* Set up es_out */
     es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ACTIVE, true );
     i_es_out_mode = ES_OUT_MODE_AUTO;
@@ -1134,7 +1125,7 @@ static int Init( input_thread_t * p_input )
 #ifdef ENABLE_SOUT
     ret = InitSout( p_input );
     if( ret != VLC_SUCCESS )
-        return ret; /* FIXME: goto error; should be better here */
+        goto error_stats;
 #endif
 
     /* Create es out */
@@ -1209,12 +1200,8 @@ static int Init( input_thread_t * p_input )
         InputUpdateMeta( p_input, p_meta );
     }
 
-    if( !p_input->b_preparsing )
-    {
-        msg_Dbg( p_input, "`%s' successfully opened",
-                 p_input->p->p_item->psz_uri );
-
-    }
+    msg_Dbg( p_input, "`%s' successfully opened",
+             p_input->p->p_item->psz_uri );
 
     /* initialization is complete */
     input_ChangeState( p_input, PLAYING_S );
@@ -1236,6 +1223,9 @@ error:
         input_ressource_SetInput( p_input->p->p_ressource, NULL );
     }
 
+#ifdef ENABLE_SOUT
+error_stats:
+#endif
     if( !p_input->b_preparsing && libvlc_stats( p_input ) )
     {
 #define EXIT_COUNTER( c ) do { if( p_input->p->counters.p_##c ) \
@@ -1317,13 +1307,6 @@ static void End( input_thread_t * p_input )
 
             /* make sure we are up to date */
             stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
-            if( p_private->p_stats_computer == p_input )
-            {
-                stats_ComputeGlobalStats( p_input->p_libvlc,
-                                          p_input->p_libvlc->p_stats );
-                /* FIXME how can it be thread safe ? */
-                p_private->p_stats_computer = NULL;
-            }
             CL_CO( read_bytes );
             CL_CO( read_packets );
             CL_CO( demux_read );
@@ -1395,49 +1378,47 @@ void input_ControlPush( input_thread_t *p_input,
     vlc_mutex_unlock( &p_input->p->lock_control );
 }
 
-static inline int ControlPopNoLock( input_thread_t *p_input,
-                                    int *pi_type, vlc_value_t *p_val,
-                                    mtime_t i_deadline )
+static inline int ControlPop( input_thread_t *p_input,
+                              int *pi_type, vlc_value_t *p_val,
+                              mtime_t i_deadline )
 {
+    input_thread_private_t *p_sys = p_input->p;
 
-    while( p_input->p->i_control <= 0 )
+    vlc_mutex_lock( &p_sys->lock_control );
+    while( p_sys->i_control <= 0 )
     {
-        if( !vlc_object_alive( p_input ) )
-            return VLC_EGENERIC;
-
-        if( i_deadline < 0 )
+        if( !vlc_object_alive( p_input ) || i_deadline < 0 )
+        {
+            vlc_mutex_unlock( &p_sys->lock_control );
             return VLC_EGENERIC;
+        }
 
-        if( vlc_cond_timedwait( &p_input->p->wait_control, &p_input->p->lock_control, i_deadline ) )
+        if( vlc_cond_timedwait( &p_sys->wait_control, &p_sys->lock_control,
+                                i_deadline ) )
+        {
+            vlc_mutex_unlock( &p_sys->lock_control );
             return VLC_EGENERIC;
+        }
     }
 
-    *pi_type = p_input->p->control[0].i_type;
-    *p_val   = p_input->p->control[0].val;
-
-    p_input->p->i_control--;
-    if( p_input->p->i_control > 0 )
-    {
-        int i;
+    /* */
+    *pi_type = p_sys->control[0].i_type;
+    *p_val   = p_sys->control[0].val;
 
-        for( i = 0; i < p_input->p->i_control; i++ )
-        {
-            p_input->p->control[i].i_type = p_input->p->control[i+1].i_type;
-            p_input->p->control[i].val    = p_input->p->control[i+1].val;
-        }
-    }
+    p_sys->i_control--;
+    if( p_sys->i_control > 0 )
+        memmove( &p_sys->control[0], &p_sys->control[1],
+                 sizeof(*p_sys->control) * p_sys->i_control );
+    vlc_mutex_unlock( &p_sys->lock_control );
 
     return VLC_SUCCESS;
 }
 
 static void ControlReduce( input_thread_t *p_input )
 {
-    int i;
-
-    if( !p_input )
-        return;
+    vlc_mutex_lock( &p_input->p->lock_control );
 
-    for( i = 1; i < p_input->p->i_control; i++ )
+    for( int i = 1; i < p_input->p->i_control; i++ )
     {
         const int i_lt = p_input->p->control[i-1].i_type;
         const int i_ct = p_input->p->control[i].i_type;
@@ -1473,6 +1454,7 @@ static void ControlReduce( input_thread_t *p_input )
                 */
         }
     }
+    vlc_mutex_unlock( &p_input->p->lock_control );
 }
 /* Pause input */
 static void ControlPause( input_thread_t *p_input, mtime_t i_control_date )
@@ -1528,9 +1510,7 @@ static void ControlUnpause( input_thread_t *p_input, mtime_t i_control_date )
         {
             /* FIXME What to do ? */
             msg_Warn( p_input, "cannot unset pause -> EOF" );
-            vlc_mutex_unlock( &p_input->p->lock_control );
             input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
-            vlc_mutex_lock( &p_input->p->lock_control );
         }
     }
 
@@ -1581,7 +1561,7 @@ static bool Control( input_thread_t *p_input, int i_type,
             /* Reset the decoders states and clock sync (before calling the demuxer */
             es_out_SetTime( p_input->p->p_es_out, -1 );
             if( demux_Control( p_input->p->input.p_demux, DEMUX_SET_POSITION,
-                                f_pos ) )
+                                f_pos, !p_input->p->b_fast_seek ) )
             {
                 msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
                          "%2.1f%% failed", f_pos * 100 );
@@ -1620,7 +1600,8 @@ static bool Control( input_thread_t *p_input, int i_type,
             es_out_SetTime( p_input->p->p_es_out, -1 );
 
             i_ret = demux_Control( p_input->p->input.p_demux,
-                                    DEMUX_SET_TIME, i_time );
+                                   DEMUX_SET_TIME, i_time,
+                                   !p_input->p->b_fast_seek );
             if( i_ret )
             {
                 int64_t i_length;
@@ -1632,7 +1613,8 @@ static bool Control( input_thread_t *p_input, int i_type,
                 {
                     double f_pos = (double)i_time / (double)i_length;
                     i_ret = demux_Control( p_input->p->input.p_demux,
-                                            DEMUX_SET_POSITION, f_pos );
+                                            DEMUX_SET_POSITION, f_pos,
+                                            !p_input->p->b_fast_seek );
                 }
             }
             if( i_ret )
@@ -1832,12 +1814,18 @@ static bool Control( input_thread_t *p_input, int i_type,
 
         case INPUT_CONTROL_SET_AUDIO_DELAY:
             if( !es_out_SetDelay( p_input->p->p_es_out_display, AUDIO_ES, val.i_time ) )
+            {
                 input_SendEventAudioDelay( p_input, val.i_time );
+                UpdatePtsDelay( p_input );
+            }
             break;
 
         case INPUT_CONTROL_SET_SPU_DELAY:
             if( !es_out_SetDelay( p_input->p->p_es_out_display, SPU_ES, val.i_time ) )
+            {
                 input_SendEventSubtitleDelay( p_input, val.i_time );
+                UpdatePtsDelay( p_input );
+            }
             break;
 
         case INPUT_CONTROL_SET_TITLE:
@@ -1868,7 +1856,7 @@ static bool Control( input_thread_t *p_input, int i_type,
                     es_out_SetTime( p_input->p->p_es_out, -1 );
 
                     demux_Control( p_demux, DEMUX_SET_TITLE, i_title );
-                    input_ControlVarTitle( p_input, i_title );
+                    input_SendEventTitle( p_input, i_title );
                 }
             }
             else if( p_input->p->input.i_title > 0 )
@@ -1889,6 +1877,7 @@ static bool Control( input_thread_t *p_input, int i_type,
 
                     stream_Control( p_input->p->input.p_stream, STREAM_CONTROL_ACCESS,
                                     ACCESS_SET_TITLE, i_title );
+                    input_SendEventTitle( p_input, i_title );
                 }
             }
             break;
@@ -1934,6 +1923,7 @@ static bool Control( input_thread_t *p_input, int i_type,
                     es_out_SetTime( p_input->p->p_es_out, -1 );
 
                     demux_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
+                    input_SendEventSeekpoint( p_input, p_demux->info.i_title, i_seekpoint );
                 }
             }
             else if( p_input->p->input.i_title > 0 )
@@ -1968,6 +1958,7 @@ static bool Control( input_thread_t *p_input, int i_type,
 
                     stream_Control( p_input->p->input.p_stream, STREAM_CONTROL_ACCESS,
                                     ACCESS_SET_SEEKPOINT, i_seekpoint );
+                    input_SendEventSeekpoint( p_input, p_access->info.i_title, i_seekpoint );
                 }
             }
             break;
@@ -2004,7 +1995,7 @@ static bool Control( input_thread_t *p_input, int i_type,
                         break;
                     }
                     if( demux_Control( slave->p_demux,
-                                       DEMUX_SET_TIME, i_time ) )
+                                       DEMUX_SET_TIME, i_time, true ) )
                     {
                         msg_Err( p_input, "seek failed for new slave" );
                         InputSourceClean( slave );
@@ -2339,12 +2330,9 @@ static int InputSourceInit( input_thread_t *p_input,
 
     if( in->p_demux )
     {
-        int64_t i_pts_delay;
-
         /* Get infos from access_demux */
         demux_Control( in->p_demux,
-                        DEMUX_GET_PTS_DELAY, &i_pts_delay );
-        p_input->p->i_pts_delay = __MAX( p_input->p->i_pts_delay, i_pts_delay );
+                        DEMUX_GET_PTS_DELAY, &in->i_pts_delay );
 
         in->b_title_demux = true;
         if( demux_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
@@ -2386,8 +2374,6 @@ static int InputSourceInit( input_thread_t *p_input,
     }
     else
     {
-        int64_t i_pts_delay;
-
         /* Now try a real access */
         in->p_access = access_New( p_input, psz_access, psz_demux, psz_path );
 
@@ -2417,8 +2403,7 @@ static int InputSourceInit( input_thread_t *p_input,
         if( !p_input->b_preparsing )
         {
             access_Control( in->p_access,
-                             ACCESS_GET_PTS_DELAY, &i_pts_delay );
-            p_input->p->i_pts_delay = __MAX( p_input->p->i_pts_delay, i_pts_delay );
+                             ACCESS_GET_PTS_DELAY, &in->i_pts_delay );
 
             in->b_title_demux = false;
             if( access_Control( in->p_access, ACCESS_GET_TITLE_INFO,
@@ -2515,13 +2500,13 @@ static int InputSourceInit( input_thread_t *p_input,
         }
 
         {
-            /* Take access redirections into account */
+            /* Take access/stream redirections into account */
             char *psz_real_path;
             char *psz_buf = NULL;
-            if( in->p_access->psz_path )
+            if( in->p_stream->psz_path )
             {
                 const char *psz_a, *psz_d;
-                psz_buf = strdup( in->p_access->psz_path );
+                psz_buf = strdup( in->p_stream->psz_path );
                 input_SplitMRL( &psz_a, &psz_d, &psz_real_path, psz_buf );
             }
             else
@@ -2756,7 +2741,7 @@ static void SlaveSeek( input_thread_t *p_input )
     {
         input_source_t *in = p_input->p->slave[i];
 
-        if( demux_Control( in->p_demux, DEMUX_SET_TIME, i_time ) )
+        if( demux_Control( in->p_demux, DEMUX_SET_TIME, i_time, true ) )
         {
             if( !in->b_eof )
                 msg_Err( p_input, "seek failed for slave %d -> EOF", i );
@@ -2813,24 +2798,30 @@ static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta )
 
     vlc_meta_Delete( p_meta );
 
+    if( !psz_arturl || *psz_arturl == '\0' )
+    {
+        const char *psz_tmp = vlc_meta_Get( p_item->p_meta, vlc_meta_ArtworkURL );
+        if( psz_tmp )
+            psz_arturl = strdup( psz_tmp );
+    }
+    vlc_mutex_unlock( &p_item->lock );
+
     if( psz_arturl && *psz_arturl )
     {
-        vlc_meta_Set( p_item->p_meta, vlc_meta_ArtworkURL, psz_arturl );
+        input_item_SetArtURL( p_item, psz_arturl );
 
         if( !strncmp( psz_arturl, "attachment://", strlen("attachment") ) )
         {
             /* Don't look for art cover if sout
              * XXX It can change when sout has meta data support */
             if( p_input->p->p_sout && !p_input->b_preparsing )
-                vlc_meta_Set( p_item->p_meta, vlc_meta_ArtworkURL, "" );
+                input_item_SetArtURL( p_item, "" );
             else
                 input_ExtractAttachmentAndCacheArt( p_input );
         }
     }
     free( psz_arturl );
 
-    vlc_mutex_unlock( &p_item->lock );
-
     if( psz_title )
     {
         input_item_SetName( p_item, psz_title );