Added rate change support to es_out_timeshift.
authorLaurent Aimar <fenrir@videolan.org>
Sat, 15 Nov 2008 19:28:08 +0000 (20:28 +0100)
committerLaurent Aimar <fenrir@videolan.org>
Mon, 17 Nov 2008 19:03:27 +0000 (20:03 +0100)
src/input/es_out_timeshift.c
src/input/es_out_timeshift.h
src/input/input.c

index 8498c48..896eec9 100644 (file)
@@ -123,6 +123,11 @@ struct es_out_sys_t
     bool           b_paused;
     mtime_t        i_pause_date;
 
+    int            i_rate;
+    int            i_rate_source;
+    mtime_t        i_rate_date;
+    mtime_t        i_rate_delay;
+
     /* */
     int            i_es;
     es_out_id_t    **pp_es;
@@ -168,7 +173,7 @@ static FILE *GetTmpFile( const char *psz_path );
 /*****************************************************************************
  * input_EsOutTimeshiftNew:
  *****************************************************************************/
-es_out_t *input_EsOutTimeshiftNew( input_thread_t *p_input, es_out_t *p_next_out )
+es_out_t *input_EsOutTimeshiftNew( input_thread_t *p_input, es_out_t *p_next_out, int i_rate )
 {
     es_out_t *p_out = malloc( sizeof(*p_out) );
     if( !p_out )
@@ -200,6 +205,10 @@ es_out_t *input_EsOutTimeshiftNew( input_thread_t *p_input, es_out_t *p_next_out
     p_sys->p_thread = NULL;
     p_sys->b_paused = false;
     p_sys->i_pause_date = -1;
+    p_sys->i_rate_source =
+    p_sys->i_rate        = i_rate;
+    p_sys->i_rate_date = -1;
+    p_sys->i_rate_delay = 0;
     p_sys->i_cmd_delay = 0;
 
     TAB_INIT( p_sys->i_es, p_sys->pp_es );
@@ -350,7 +359,6 @@ static int ControlLockedSetPauseState( es_out_t *p_out, bool b_source_paused, bo
     {
         return es_out_SetPauseState( p_sys->p_out, b_source_paused, b_paused, i_date );
     }
-
     if( p_sys->p_input->b_can_pace_control )
     {
         /* XXX we may do it BUT it would be better to finish the clock clean up+improvments
@@ -400,9 +408,26 @@ static int ControlLockedSetRate( es_out_t *p_out, int i_src_rate, int i_rate )
     {
         return es_out_SetRate( p_sys->p_out, i_src_rate, i_rate );
     }
-    /* TODO */
-    msg_Err( p_sys->p_input, "EsOutTimeshift does not yet support rate change" );
-    return VLC_EGENERIC;
+    if( p_sys->p_input->b_can_pace_control )
+    {
+        /* XXX we may do it BUT it would be better to finish the clock clean up+improvments
+         * and so be able to advertize correctly pace control property in access
+         * module */
+        msg_Err( p_sys->p_input, "EsOutTimeshift does not work with streams that have space control" );
+        return VLC_EGENERIC;
+    }
+
+    p_sys->i_cmd_delay += p_sys->i_rate_delay;
+
+    p_sys->i_rate_date = -1;
+    p_sys->i_rate_delay = 0;
+    p_sys->i_rate = i_rate;
+    p_sys->i_rate_source = i_src_rate;
+
+    if( !p_sys->b_delayed )
+        TsStart( p_out );
+
+    return es_out_SetRate( p_sys->p_out, i_rate, i_rate );
 }
 static int ControlLockedSetTime( es_out_t *p_out, mtime_t i_date )
 {
@@ -595,6 +620,7 @@ static void *TsRun( vlc_object_t *p_thread )
     for( ;; )
     {
         ts_cmd_t cmd;
+        mtime_t  i_deadline;
 
         /* Pop a command to execute */
         vlc_mutex_lock( &p_sys->lock );
@@ -603,15 +629,32 @@ static void *TsRun( vlc_object_t *p_thread )
         while( p_sys->b_paused || CmdPop( p_out, &cmd ) )
             vlc_cond_wait( &p_sys->wait, &p_sys->lock );
 
-        vlc_cleanup_pop();
-        vlc_mutex_unlock( &p_sys->lock );
+        if( p_sys->i_rate_date < 0 )
+            p_sys->i_rate_date = cmd.i_date;
+
+        p_sys->i_rate_delay = 0;
+        if( p_sys->i_rate_source != p_sys->i_rate )
+        {
+            const mtime_t i_duration = cmd.i_date - p_sys->i_rate_date;
+            p_sys->i_rate_delay = i_duration * p_sys->i_rate / p_sys->i_rate_source - i_duration;
+        }
+
+        i_deadline = cmd.i_date + p_sys->i_cmd_delay + p_sys->i_rate_delay;
+
+        if( p_sys->i_cmd_delay + p_sys->i_rate_delay < 0 )
+        {
+            /* TODO handle when we cannot go faster anymore */
+            msg_Err( p_sys->p_input, "FIXME rate underflow" );
+        }
+
+        vlc_cleanup_run();
 
         /* Regulate the speed of command processing to the same one than
          * reading  */
         //fprintf( stderr, "d=%d - %d\n", (int)(p_sys->i_cmd_delay/1000), (int)( (mdate() - cmd.i_date - p_sys->i_cmd_delay)/1000) );
         vlc_cleanup_push( cmd_cleanup_routine, &cmd );
 
-        mwait( cmd.i_date + p_sys->i_cmd_delay );
+        mwait( i_deadline );
 
         vlc_cleanup_pop();
 
index 4370963..b5eec97 100644 (file)
@@ -31,6 +31,6 @@
 #include <vlc_common.h>
 
 
-es_out_t *input_EsOutTimeshiftNew( input_thread_t *, es_out_t * );
+es_out_t *input_EsOutTimeshiftNew( input_thread_t *, es_out_t *, int i_rate );
 
 #endif
index 1049357..5d90e9a 100644 (file)
@@ -1185,7 +1185,7 @@ static int Init( input_thread_t * p_input )
 
     /* Create es out */
     p_input->p->p_es_out_display = input_EsOutNew( p_input, p_input->p->i_rate );
-    p_input->p->p_es_out         = input_EsOutTimeshiftNew( p_input, p_input->p->p_es_out_display );
+    p_input->p->p_es_out         = input_EsOutTimeshiftNew( p_input, p_input->p->p_es_out_display, p_input->p->i_rate );
     es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ACTIVE, false );
     es_out_Control( p_input->p->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
 
@@ -1517,12 +1517,20 @@ static void ControlPause( input_thread_t *p_input, mtime_t i_control_date )
         }
     }
 
+    /* */
+    if( !i_ret )
+    {
+        i_ret = es_out_SetPauseState( p_input->p->p_es_out, p_input->p->b_can_pause, true, i_control_date );
+        if( i_ret )
+        {
+            msg_Warn( p_input, "cannot set pause state at es_out level" );
+            i_state = p_input->i_state;
+        }
+    }
+
     /* Switch to new state */
     input_ChangeStateWithVarCallback( p_input, i_state, false );
 
-    /* */
-    if( !i_ret )
-        es_out_SetPauseState( p_input->p->p_es_out, p_input->p->b_can_pause, true, i_control_date );
 }
 static void ControlUnpause( input_thread_t *p_input, mtime_t i_control_date )
 {
@@ -1766,7 +1774,8 @@ static bool Control( input_thread_t *p_input, int i_type,
                 i_rate = INPUT_RATE_MAX;
             }
             if( i_rate != INPUT_RATE_DEFAULT &&
-                ( ( !p_input->b_can_pace_control && !p_input->p->b_can_rate_control ) ||
+                ( /*( !p_input->b_can_pace_control && !p_input->p->b_can_rate_control ) ||*/
+                  ( !p_input->p->b_can_rate_control && !p_input->p->input.b_rescale_ts ) ||
                   ( p_input->p->p_sout && !p_input->p->b_out_pace_control ) ) )
             {
                 msg_Dbg( p_input, "cannot change rate" );
@@ -1799,7 +1808,10 @@ static bool Control( input_thread_t *p_input, int i_type,
 
                 /* FIXME do we need a RESET_PCR when !p_input->p->input.b_rescale_ts ? */
                 if( p_input->p->input.b_rescale_ts )
-                    es_out_SetRate( p_input->p->p_es_out, i_rate, i_rate );
+                {
+                    const int i_rate_source = (p_input->b_can_pace_control || p_input->p->b_can_rate_control ) ? i_rate : INPUT_RATE_DEFAULT;
+                    es_out_SetRate( p_input->p->p_es_out, i_rate_source, i_rate );
+                }
 
                 b_force_update = true;
             }