[vlc-commits] es_out: split public and private controls

Thomas Guillem git at videolan.org
Fri Feb 28 20:45:55 CET 2020


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Wed Feb 26 16:20:29 2020 +0100| [33c53b0d6fdf90f42c656addac1db85868f68437] | committer: Thomas Guillem

es_out: split public and private controls

Private controls are necessarily called from the input_thead_t (or via
timeshift via the input_thread_t). Public controls can be called from demuxers
of the input_thread_t.

This separation will help the process of adding new es_out controls, specially
private one that don't need to be added in public headers.

Furthermore, this will help a future control ES_OUT_PRIV_SET_ES_CAT_IDS: that
will be able to be executed when the input is started or not. I think that such
new control should be explicitly made private.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=33c53b0d6fdf90f42c656addac1db85868f68437
---

 include/vlc_es_out.h                   |   6 +
 modules/demux/timestamps_filter.h      |   1 +
 src/input/es_out.c                     | 527 +++++++++++++++++----------------
 src/input/es_out.h                     |  95 +++---
 src/input/es_out_timeshift.c           | 268 +++++++++++------
 src/input/input.c                      |  36 +--
 test/modules/demux/timestamps_filter.c |   1 +
 7 files changed, 534 insertions(+), 400 deletions(-)

diff --git a/include/vlc_es_out.h b/include/vlc_es_out.h
index 06b6a8f338..5cf5116ab6 100644
--- a/include/vlc_es_out.h
+++ b/include/vlc_es_out.h
@@ -23,6 +23,8 @@
 #ifndef VLC_ES_OUT_H
 #define VLC_ES_OUT_H 1
 
+#include <assert.h>
+
 /**
  * \defgroup es_out ES output
  * \ingroup input
@@ -128,6 +130,10 @@ struct es_out_callbacks
     void         (*del)(es_out_t *, es_out_id_t *);
     int          (*control)(es_out_t *, int query, va_list);
     void         (*destroy)(es_out_t *);
+    /**
+     * Private control callback, must be NULL for es_out created from modules.
+     */
+    int          (*priv_control)(es_out_t *, int query, va_list);
 };
 
 struct es_out_t
diff --git a/modules/demux/timestamps_filter.h b/modules/demux/timestamps_filter.h
index f56c4e7137..4d2b2e0883 100644
--- a/modules/demux/timestamps_filter.h
+++ b/modules/demux/timestamps_filter.h
@@ -353,6 +353,7 @@ static const struct es_out_callbacks timestamps_filter_es_out_cbs =
     timestamps_filter_es_out_Del,
     timestamps_filter_es_out_Control,
     timestamps_filter_es_out_Delete,
+    NULL,
 };
 
 static es_out_t * timestamps_filter_es_out_New(es_out_t *orig)
diff --git a/src/input/es_out.c b/src/input/es_out.c
index 6955192dc0..9f3666965b 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -244,6 +244,7 @@ static void EsOutGlobalMeta( es_out_t *p_out, const vlc_meta_t *p_meta );
 static void EsOutMeta( es_out_t *p_out, const vlc_meta_t *p_meta, const vlc_meta_t *p_progmeta );
 static int EsOutEsUpdateFmt(es_out_t *out, es_out_id_t *es, const es_format_t *fmt);
 static int EsOutControlLocked( es_out_t *out, int i_query, ... );
+static int EsOutPrivControlLocked( es_out_t *out, int i_query, ... );
 
 static char *LanguageGetName( const char *psz_code );
 static char *LanguageGetCode( const char *psz_lang );
@@ -727,8 +728,8 @@ static void EsOutSetEsDelay(es_out_t *out, es_out_id_t *es, vlc_tick_t delay)
     EsOutDecoderChangeDelay(out, es);
 
     /* Update the clock pts delay only if the extra tracks delay changed */
-    EsOutControlLocked(out, ES_OUT_SET_JITTER, p_sys->i_pts_delay,
-                       p_sys->i_pts_jitter, p_sys->i_cr_average);
+    EsOutPrivControlLocked(out, ES_OUT_PRIV_SET_JITTER, p_sys->i_pts_delay,
+                           p_sys->i_pts_jitter, p_sys->i_cr_average);
 }
 
 static void EsOutSetDelay( es_out_t *out, int i_cat, vlc_tick_t i_delay )
@@ -745,8 +746,8 @@ static void EsOutSetDelay( es_out_t *out, int i_cat, vlc_tick_t i_delay )
         EsOutDecoderChangeDelay(out, es);
 
     /* Update the clock pts delay only if the extra tracks delay changed */
-    EsOutControlLocked(out, ES_OUT_SET_JITTER, p_sys->i_pts_delay,
-                       p_sys->i_pts_jitter, p_sys->i_cr_average);
+    EsOutPrivControlLocked(out, ES_OUT_PRIV_SET_JITTER, p_sys->i_pts_delay,
+                           p_sys->i_pts_jitter, p_sys->i_cr_average);
 }
 
 static int EsOutSetRecord(  es_out_t *out, bool b_record )
@@ -2784,59 +2785,6 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
         return VLC_SUCCESS;
     }
 
-    case ES_OUT_GET_GROUP_FORCED:
-    {
-        int *pi_group = va_arg( args, int * );
-        *pi_group = p_sys->i_group_id;
-        return VLC_SUCCESS;
-    }
-
-    case ES_OUT_SET_MODE:
-    {
-        const int i_mode = va_arg( args, int );
-        assert( i_mode == ES_OUT_MODE_NONE || i_mode == ES_OUT_MODE_ALL ||
-                i_mode == ES_OUT_MODE_AUTO || i_mode == ES_OUT_MODE_PARTIAL ||
-                i_mode == ES_OUT_MODE_END );
-
-        if (i_mode != ES_OUT_MODE_NONE && !p_sys->b_active && !vlc_list_is_empty(&p_sys->es))
-        {
-            /* XXX Terminate vout if there are tracks but no video one.
-             * This one is not mandatory but is he earliest place where it
-             * can be done */
-            es_out_id_t *p_es;
-            bool found = false;
-
-            foreach_es_then_es_slaves(p_es)
-                if( p_es->fmt.i_cat == VIDEO_ES && !found /* nested loop */ )
-                {
-                    found = true;
-                    break;
-                }
-
-            if (!found)
-                EsOutStopFreeVout( out );
-        }
-        p_sys->b_active = i_mode != ES_OUT_MODE_NONE;
-        p_sys->i_mode = i_mode;
-
-        /* Reapply policy mode */
-        es_out_id_t *es;
-
-        foreach_es_then_es_slaves(es)
-        {
-            if (EsIsSelected(es))
-                EsOutUnselectEs(out, es, es->p_pgrm == p_sys->p_pgrm);
-        }
-        foreach_es_then_es_slaves(es)
-        {
-            EsOutSelect(out, es, false);
-        }
-
-        if( i_mode == ES_OUT_MODE_END )
-            EsOutTerminate( out );
-        return VLC_SUCCESS;
-    }
-
     case ES_OUT_SET_ES:
     case ES_OUT_RESTART_ES:
     {
@@ -2898,13 +2846,6 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
         EsOutStopFreeVout( out );
         return VLC_SUCCESS;
     }
-    case ES_OUT_SET_ES_LIST:
-    {
-        enum es_format_category_e cat = va_arg( args, enum es_format_category_e );
-        vlc_es_id_t *const*es_id_list = va_arg( args, vlc_es_id_t ** );
-        EsOutSelectList( out, cat, es_id_list );
-        return VLC_SUCCESS;
-    }
     case ES_OUT_UNSET_ES:
     {
         es_out_id_t *es = va_arg( args, es_out_id_t * ), *other;
@@ -2925,50 +2866,6 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
         }
         return VLC_EGENERIC;
     }
-    case ES_OUT_STOP_ALL_ES:
-    {
-        es_out_id_t *es;
-        int count = 0;
-
-        foreach_es_then_es_slaves(es)
-            count++;
-
-        int *selected_es = vlc_alloc(count + 1, sizeof(int));
-        if (!selected_es)
-            return VLC_ENOMEM;
-
-        *va_arg(args, void **) = selected_es;
-        *selected_es = count;
-
-        foreach_es_then_es_slaves(es)
-        {
-            if (EsIsSelected(es))
-            {
-                EsOutDestroyDecoder(out, es);
-                *++selected_es = es->fmt.i_id;
-            }
-            else
-                *++selected_es = -1;
-        }
-        return VLC_SUCCESS;
-    }
-    case ES_OUT_START_ALL_ES:
-    {
-        int *selected_es = va_arg( args, void * );
-        int count = selected_es[0];
-        for( int i = 0; i < count; ++i )
-        {
-            int i_id = selected_es[i + 1];
-            if( i_id != -1 )
-            {
-                es_out_id_t *p_es = EsOutGetFromID( out, i_id );
-                EsOutCreateDecoder( out, p_es );
-            }
-        }
-        free(selected_es);
-        EsOutStopFreeVout( out );
-        return VLC_SUCCESS;
-    }
 
     case ES_OUT_SET_ES_DEFAULT:
     {
@@ -3107,10 +3004,9 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
                 /* Force a rebufferization when we are too late */
                 EsOutControlLocked( out, ES_OUT_RESET_PCR );
 
-                EsOutControlLocked( out, ES_OUT_SET_JITTER,
-                                    p_sys->i_pts_delay,
-                                    i_new_jitter,
-                                    p_sys->i_cr_average );
+                EsOutPrivControlLocked( out, ES_OUT_PRIV_SET_JITTER,
+                                        p_sys->i_pts_delay, i_new_jitter,
+                                        p_sys->i_cr_average );
             }
         }
         return VLC_SUCCESS;
@@ -3238,28 +3134,206 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
         return VLC_SUCCESS;
     }
 
-    case ES_OUT_GET_WAKE_UP:
+    case ES_OUT_GET_EMPTY:
+    {
+        bool *pb = va_arg( args, bool* );
+        *pb = EsOutDecodersIsEmpty( out );
+        return VLC_SUCCESS;
+    }
+
+    case ES_OUT_GET_PCR_SYSTEM:
+    {
+        if( p_sys->b_buffering )
+            return VLC_EGENERIC;
+
+        es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
+        if( !p_pgrm )
+            return VLC_EGENERIC;
+
+        vlc_tick_t *pi_system = va_arg( args, vlc_tick_t *);
+        vlc_tick_t *pi_delay  = va_arg( args, vlc_tick_t *);
+        input_clock_GetSystemOrigin( p_pgrm->p_input_clock, pi_system, pi_delay );
+        return VLC_SUCCESS;
+    }
+
+    case ES_OUT_MODIFY_PCR_SYSTEM:
+    {
+        if( p_sys->b_buffering )
+            return VLC_EGENERIC;
+
+        es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
+        if( !p_pgrm )
+            return VLC_EGENERIC;
+
+        const bool    b_absolute = va_arg( args, int );
+        const vlc_tick_t i_system   = va_arg( args, vlc_tick_t );
+        input_clock_ChangeSystemOrigin( p_pgrm->p_input_clock, b_absolute, i_system );
+        return VLC_SUCCESS;
+    }
+
+    case ES_OUT_POST_SUBNODE:
+    {
+        input_thread_t *input = p_sys->p_input;
+        input_item_node_t *node = va_arg(args, input_item_node_t *);
+        input_SendEventParsing(input, node);
+        input_item_node_Delete(node);
+
+        return VLC_SUCCESS;
+    }
+
+    case ES_OUT_VOUT_SET_MOUSE_EVENT:
+    {
+        es_out_id_t *p_es = va_arg( args, es_out_id_t * );
+
+        if( !p_es || p_es->fmt.i_cat != VIDEO_ES )
+            return VLC_EGENERIC;
+
+        p_es->mouse_event_cb = va_arg( args, vlc_mouse_event );
+        p_es->mouse_event_userdata = va_arg( args, void * );
+
+        if( p_es->p_dec )
+            input_DecoderSetVoutMouseEvent( p_es->p_dec,
+                p_es->mouse_event_cb, p_es->mouse_event_userdata );
+
+        return VLC_SUCCESS;
+    }
+    case ES_OUT_VOUT_ADD_OVERLAY:
+    {
+        es_out_id_t *p_es = va_arg( args, es_out_id_t * );
+        subpicture_t *sub = va_arg( args, subpicture_t * );
+        size_t *channel = va_arg( args, size_t * );
+        if( p_es && p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
+            return input_DecoderAddVoutOverlay( p_es->p_dec, sub, channel );
+        return VLC_EGENERIC;
+    }
+    case ES_OUT_VOUT_DEL_OVERLAY:
+    {
+        es_out_id_t *p_es = va_arg( args, es_out_id_t * );
+        size_t channel = va_arg( args, size_t );
+        if( p_es && p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
+            return input_DecoderDelVoutOverlay( p_es->p_dec, channel );
+        return VLC_EGENERIC;
+    }
+    case ES_OUT_SPU_SET_HIGHLIGHT:
+    {
+        es_out_id_t *p_es = va_arg( args, es_out_id_t * );
+        const vlc_spu_highlight_t *spu_hl =
+            va_arg( args, const vlc_spu_highlight_t * );
+        if( p_es && p_es->fmt.i_cat == SPU_ES && p_es->p_dec )
+            return input_DecoderSetSpuHighlight( p_es->p_dec, spu_hl );
+        return VLC_EGENERIC;
+    }
+    default:
+        msg_Err( p_sys->p_input, "unknown query 0x%x in %s", i_query,
+                 __func__  );
+        return VLC_EGENERIC;
+    }
+}
+
+static int EsOutVaPrivControlLocked( es_out_t *out, int query, va_list args )
+{
+    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
+
+    switch (query)
+    {
+    case ES_OUT_PRIV_SET_MODE:
+    {
+        const int i_mode = va_arg( args, int );
+        assert( i_mode == ES_OUT_MODE_NONE || i_mode == ES_OUT_MODE_ALL ||
+                i_mode == ES_OUT_MODE_AUTO || i_mode == ES_OUT_MODE_PARTIAL ||
+                i_mode == ES_OUT_MODE_END );
+
+        if (i_mode != ES_OUT_MODE_NONE && !p_sys->b_active && !vlc_list_is_empty(&p_sys->es))
+        {
+            /* XXX Terminate vout if there are tracks but no video one.
+             * This one is not mandatory but is he earliest place where it
+             * can be done */
+            es_out_id_t *p_es;
+            bool found = false;
+
+            foreach_es_then_es_slaves(p_es)
+                if( p_es->fmt.i_cat == VIDEO_ES && !found /* nested loop */ )
+                {
+                    found = true;
+                    break;
+                }
+
+            if (!found)
+                EsOutStopFreeVout( out );
+        }
+        p_sys->b_active = i_mode != ES_OUT_MODE_NONE;
+        p_sys->i_mode = i_mode;
+
+        /* Reapply policy mode */
+        es_out_id_t *es;
+
+        foreach_es_then_es_slaves(es)
+        {
+            if (EsIsSelected(es))
+                EsOutUnselectEs(out, es, es->p_pgrm == p_sys->p_pgrm);
+        }
+        foreach_es_then_es_slaves(es)
+        {
+            EsOutSelect(out, es, false);
+        }
+
+        if( i_mode == ES_OUT_MODE_END )
+            EsOutTerminate( out );
+        return VLC_SUCCESS;
+    }
+    case ES_OUT_PRIV_GET_WAKE_UP:
     {
         vlc_tick_t *pi_wakeup = va_arg( args, vlc_tick_t* );
         *pi_wakeup = EsOutGetWakeup( out );
         return VLC_SUCCESS;
     }
-
-    case ES_OUT_SET_ES_BY_ID:
-    case ES_OUT_RESTART_ES_BY_ID:
-    case ES_OUT_SET_ES_DEFAULT_BY_ID:
+    case ES_OUT_PRIV_SET_ES_LIST:
+    {
+        enum es_format_category_e cat = va_arg( args, enum es_format_category_e );
+        vlc_es_id_t *const*es_id_list = va_arg( args, vlc_es_id_t ** );
+        EsOutSelectList( out, cat, es_id_list );
+        return VLC_SUCCESS;
+    }
+    case ES_OUT_PRIV_SET_AUTOSELECT:
+    {
+        int i_cat = va_arg( args, int );
+        bool b_enabled = va_arg( args, int );
+        switch ( i_cat )
+        {
+            case VIDEO_ES:
+                p_sys->video.b_autoselect = b_enabled;
+                break;
+            case AUDIO_ES:
+                p_sys->audio.b_autoselect = b_enabled;
+                break;
+            case SPU_ES:
+                p_sys->sub.b_autoselect = b_enabled;
+                break;
+            default:
+                return VLC_EGENERIC;
+        }
+        return VLC_SUCCESS;
+    }
+    case ES_OUT_PRIV_SET_ES_BY_ID:
+    case ES_OUT_PRIV_RESTART_ES_BY_ID:
+    case ES_OUT_PRIV_SET_ES_DEFAULT_BY_ID:
     {
         const int i_id = va_arg( args, int );
         es_out_id_t *p_es = EsOutGetFromID( out, i_id );
         int i_new_query = 0;
 
-        switch( i_query )
+        switch( query )
         {
-        case ES_OUT_SET_ES_BY_ID:         i_new_query = ES_OUT_SET_ES;
+        case ES_OUT_PRIV_SET_ES_BY_ID:
+            i_new_query = ES_OUT_SET_ES;
             p_es->b_forced = va_arg( args, int );
             break;
-        case ES_OUT_RESTART_ES_BY_ID:     i_new_query = ES_OUT_RESTART_ES; break;
-        case ES_OUT_SET_ES_DEFAULT_BY_ID: i_new_query = ES_OUT_SET_ES_DEFAULT; break;
+        case ES_OUT_PRIV_RESTART_ES_BY_ID:
+            i_new_query = ES_OUT_RESTART_ES;
+            break;
+        case ES_OUT_PRIV_SET_ES_DEFAULT_BY_ID:
+            i_new_query = ES_OUT_SET_ES_DEFAULT;
+            break;
         default:
           vlc_assert_unreachable();
         }
@@ -3267,44 +3341,76 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
 
         return i_ret;
     }
+    case ES_OUT_PRIV_STOP_ALL_ES:
+    {
+        es_out_id_t *es;
+        int count = 0;
+
+        foreach_es_then_es_slaves(es)
+            count++;
+
+        int *selected_es = vlc_alloc(count + 1, sizeof(int));
+        if (!selected_es)
+            return VLC_ENOMEM;
 
-    case ES_OUT_GET_BUFFERING:
+        *va_arg(args, void **) = selected_es;
+        *selected_es = count;
+
+        foreach_es_then_es_slaves(es)
+        {
+            if (EsIsSelected(es))
+            {
+                EsOutDestroyDecoder(out, es);
+                *++selected_es = es->fmt.i_id;
+            }
+            else
+                *++selected_es = -1;
+        }
+        return VLC_SUCCESS;
+    }
+    case ES_OUT_PRIV_START_ALL_ES:
     {
-        bool *pb = va_arg( args, bool* );
-        *pb = p_sys->b_buffering;
+        int *selected_es = va_arg( args, void * );
+        int count = selected_es[0];
+        for( int i = 0; i < count; ++i )
+        {
+            int i_id = selected_es[i + 1];
+            if( i_id != -1 )
+            {
+                es_out_id_t *p_es = EsOutGetFromID( out, i_id );
+                EsOutCreateDecoder( out, p_es );
+            }
+        }
+        free(selected_es);
+        EsOutStopFreeVout( out );
         return VLC_SUCCESS;
     }
-
-    case ES_OUT_GET_EMPTY:
+    case ES_OUT_PRIV_GET_BUFFERING:
     {
         bool *pb = va_arg( args, bool* );
-        *pb = EsOutDecodersIsEmpty( out );
+        *pb = p_sys->b_buffering;
         return VLC_SUCCESS;
     }
-
-    case ES_OUT_SET_ES_DELAY:
+    case ES_OUT_PRIV_SET_ES_DELAY:
     {
         es_out_id_t *es = va_arg(args, es_out_id_t *);
         const vlc_tick_t delay = va_arg(args, vlc_tick_t);
         EsOutSetEsDelay(out, es, delay);
         return VLC_SUCCESS;
     }
-
-    case ES_OUT_SET_DELAY:
+    case ES_OUT_PRIV_SET_DELAY:
     {
         const int i_cat = va_arg( args, int );
         const vlc_tick_t i_delay = va_arg( args, vlc_tick_t );
         EsOutSetDelay( out, i_cat, i_delay );
         return VLC_SUCCESS;
     }
-
-    case ES_OUT_SET_RECORD_STATE:
+    case ES_OUT_PRIV_SET_RECORD_STATE:
     {
         bool b = va_arg( args, int );
         return EsOutSetRecord( out, b );
     }
-
-    case ES_OUT_SET_PAUSE_STATE:
+    case ES_OUT_PRIV_SET_PAUSE_STATE:
     {
         const bool b_source_paused = (bool)va_arg( args, int );
         const bool b_paused = (bool)va_arg( args, int );
@@ -3315,8 +3421,7 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
 
         return VLC_SUCCESS;
     }
-
-    case ES_OUT_SET_RATE:
+    case ES_OUT_PRIV_SET_RATE:
     {
         const float src_rate = va_arg( args, double );
         const float rate = va_arg( args, double );
@@ -3326,12 +3431,10 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
 
         return VLC_SUCCESS;
     }
-
-    case ES_OUT_SET_FRAME_NEXT:
+    case ES_OUT_PRIV_SET_FRAME_NEXT:
         EsOutFrameNext( out );
         return VLC_SUCCESS;
-
-    case ES_OUT_SET_TIMES:
+    case ES_OUT_PRIV_SET_TIMES:
     {
         double f_position = va_arg( args, double );
         vlc_tick_t i_time = va_arg( args, vlc_tick_t );
@@ -3371,7 +3474,7 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
                                   i_normal_time, i_length );
         return VLC_SUCCESS;
     }
-    case ES_OUT_SET_JITTER:
+    case ES_OUT_PRIV_SET_JITTER:
     {
         vlc_tick_t i_pts_delay  = va_arg( args, vlc_tick_t );
         vlc_tick_t i_pts_jitter = va_arg( args, vlc_tick_t );
@@ -3404,37 +3507,13 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
         }
         return VLC_SUCCESS;
     }
-
-    case ES_OUT_GET_PCR_SYSTEM:
+    case ES_OUT_PRIV_GET_GROUP_FORCED:
     {
-        if( p_sys->b_buffering )
-            return VLC_EGENERIC;
-
-        es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
-        if( !p_pgrm )
-            return VLC_EGENERIC;
-
-        vlc_tick_t *pi_system = va_arg( args, vlc_tick_t *);
-        vlc_tick_t *pi_delay  = va_arg( args, vlc_tick_t *);
-        input_clock_GetSystemOrigin( p_pgrm->p_input_clock, pi_system, pi_delay );
-        return VLC_SUCCESS;
-    }
-
-    case ES_OUT_MODIFY_PCR_SYSTEM:
-    {
-        if( p_sys->b_buffering )
-            return VLC_EGENERIC;
-
-        es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
-        if( !p_pgrm )
-            return VLC_EGENERIC;
-
-        const bool    b_absolute = va_arg( args, int );
-        const vlc_tick_t i_system   = va_arg( args, vlc_tick_t );
-        input_clock_ChangeSystemOrigin( p_pgrm->p_input_clock, b_absolute, i_system );
+        int *pi_group = va_arg( args, int * );
+        *pi_group = p_sys->i_group_id;
         return VLC_SUCCESS;
     }
-    case ES_OUT_SET_EOS:
+    case ES_OUT_PRIV_SET_EOS:
     {
         es_out_id_t *id;
         foreach_es_then_es_slaves(id)
@@ -3442,61 +3521,8 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
                 input_DecoderDrain(id->p_dec);
         return VLC_SUCCESS;
     }
-
-    case ES_OUT_POST_SUBNODE:
-    {
-        input_thread_t *input = p_sys->p_input;
-        input_item_node_t *node = va_arg(args, input_item_node_t *);
-        input_SendEventParsing(input, node);
-        input_item_node_Delete(node);
-
-        return VLC_SUCCESS;
-    }
-
-    case ES_OUT_VOUT_SET_MOUSE_EVENT:
-    {
-        es_out_id_t *p_es = va_arg( args, es_out_id_t * );
-
-        if( !p_es || p_es->fmt.i_cat != VIDEO_ES )
-            return VLC_EGENERIC;
-
-        p_es->mouse_event_cb = va_arg( args, vlc_mouse_event );
-        p_es->mouse_event_userdata = va_arg( args, void * );
-
-        if( p_es->p_dec )
-            input_DecoderSetVoutMouseEvent( p_es->p_dec,
-                p_es->mouse_event_cb, p_es->mouse_event_userdata );
-
-        return VLC_SUCCESS;
-    }
-    case ES_OUT_VOUT_ADD_OVERLAY:
-    {
-        es_out_id_t *p_es = va_arg( args, es_out_id_t * );
-        subpicture_t *sub = va_arg( args, subpicture_t * );
-        size_t *channel = va_arg( args, size_t * );
-        if( p_es && p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
-            return input_DecoderAddVoutOverlay( p_es->p_dec, sub, channel );
-        return VLC_EGENERIC;
-    }
-    case ES_OUT_VOUT_DEL_OVERLAY:
-    {
-        es_out_id_t *p_es = va_arg( args, es_out_id_t * );
-        size_t channel = va_arg( args, size_t );
-        if( p_es && p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
-            return input_DecoderDelVoutOverlay( p_es->p_dec, channel );
-        return VLC_EGENERIC;
-    }
-    case ES_OUT_SPU_SET_HIGHLIGHT:
-    {
-        es_out_id_t *p_es = va_arg( args, es_out_id_t * );
-        const vlc_spu_highlight_t *spu_hl =
-            va_arg( args, const vlc_spu_highlight_t * );
-        if( p_es && p_es->fmt.i_cat == SPU_ES && p_es->p_dec )
-            return input_DecoderSetSpuHighlight( p_es->p_dec, spu_hl );
-        return VLC_EGENERIC;
-    }
-    case ES_OUT_SET_VBI_PAGE:
-    case ES_OUT_SET_VBI_TRANSPARENCY:
+    case ES_OUT_PRIV_SET_VBI_PAGE:
+    case ES_OUT_PRIV_SET_VBI_TRANSPARENCY:
     {
         es_out_id_t *es = va_arg( args, es_out_id_t * );
         assert(es);
@@ -3505,7 +3531,7 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
             return VLC_EGENERIC;
 
         int ret;
-        if( i_query == ES_OUT_SET_VBI_PAGE )
+        if( query == ES_OUT_PRIV_SET_VBI_PAGE )
         {
             unsigned page = va_arg( args, unsigned );
             ret = var_SetInteger( es->p_dec, "vbi-page", page );
@@ -3521,32 +3547,11 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
         }
         return ret;
     }
-    case ES_OUT_SET_AUTOSELECT:
-    {
-        int i_cat = va_arg( args, int );
-        bool b_enabled = va_arg( args, int );
-        switch ( i_cat )
-        {
-            case VIDEO_ES:
-                p_sys->video.b_autoselect = b_enabled;
-                break;
-            case AUDIO_ES:
-                p_sys->audio.b_autoselect = b_enabled;
-                break;
-            case SPU_ES:
-                p_sys->sub.b_autoselect = b_enabled;
-                break;
-            default:
-                return VLC_EGENERIC;
-        }
-        return VLC_SUCCESS;
-    }
-    default:
-        msg_Err( p_sys->p_input, "unknown query 0x%x in %s", i_query,
-                 __func__  );
-        return VLC_EGENERIC;
+    default: vlc_assert_unreachable();
     }
+
 }
+
 static int EsOutControl( es_out_t *out, int i_query, va_list args )
 {
     es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
@@ -3559,6 +3564,27 @@ static int EsOutControl( es_out_t *out, int i_query, va_list args )
     return i_ret;
 }
 
+static int EsOutPrivControlLocked( es_out_t *out, int i_query, ... )
+{
+    va_list args;
+
+    va_start( args, i_query );
+    int ret = EsOutVaPrivControlLocked( out, i_query, args );
+    va_end( args );
+    return ret;
+}
+
+static int EsOutPrivControl( es_out_t *out, int query, va_list args )
+{
+    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
+
+    vlc_mutex_lock( &p_sys->lock );
+    int ret = EsOutVaPrivControlLocked( out, query, args );
+    vlc_mutex_unlock( &p_sys->lock );
+
+    return ret;
+}
+
 static const struct es_out_callbacks es_out_cbs =
 {
     .add = EsOutAdd,
@@ -3566,6 +3592,7 @@ static const struct es_out_callbacks es_out_cbs =
     .del = EsOutDel,
     .control = EsOutControl,
     .destroy = EsOutDelete,
+    .priv_control = EsOutPrivControl,
 };
 
 /****************************************************************************
diff --git a/src/input/es_out.h b/src/input/es_out.h
index 780dd12bd4..69c9130092 100644
--- a/src/input/es_out.h
+++ b/src/input/es_out.h
@@ -38,78 +38,93 @@ enum es_out_mode_e
 enum es_out_query_private_e
 {
     /* set/get mode */
-    ES_OUT_SET_MODE = ES_OUT_PRIVATE_START,         /* arg1= int                            */
+    ES_OUT_PRIV_SET_MODE,                           /* arg1= int */
 
     /* Get date to wait before demuxing more data */
-    ES_OUT_GET_WAKE_UP,                             /* arg1=vlc_tick_t*            res=cannot fail */
+    ES_OUT_PRIV_GET_WAKE_UP,                        /* arg1=vlc_tick_t*            res=cannot fail */
 
     /* Select a list of ES */
-    ES_OUT_SET_ES_LIST, /* arg1= es_out_id_t *const* (null terminated array) */
+    ES_OUT_PRIV_SET_ES_LIST, /* arg1= es_out_id_t *const* (null terminated array) */
 
     /* Disable autoselection of tracks from a given category */
-    ES_OUT_SET_AUTOSELECT,  /* arg1= int (es category),
-                               arg2= int (enabled/disabled), res=can fail */
+    ES_OUT_PRIV_SET_AUTOSELECT,  /* arg1= int (es category),
+                                    arg2= int (enabled/disabled), res=can fail */
 
     /* Wrapper for some ES command to work with id */
-    ES_OUT_SET_ES_BY_ID,                            /* arg1= int, arg2= bool (forced) */
-    ES_OUT_RESTART_ES_BY_ID,
-    ES_OUT_SET_ES_DEFAULT_BY_ID,
+    ES_OUT_PRIV_SET_ES_BY_ID,                       /* arg1= int, arg2= bool (forced) */
+    ES_OUT_PRIV_RESTART_ES_BY_ID,
+    ES_OUT_PRIV_SET_ES_DEFAULT_BY_ID,
 
     /* Stop all selected ES and save the stopped state in a context. free the
-     * context or call ES_OUT_STOP_ALL_ES */
-    ES_OUT_STOP_ALL_ES,                             /* arg1=void ** */
-    /* Start all ES from the context returned by ES_OUT_STOP_ALL_ES */
-    ES_OUT_START_ALL_ES,                            /* arg1=void * */
+     * context or call ES_OUT_PRIV_STOP_ALL_ES */
+    ES_OUT_PRIV_STOP_ALL_ES,                        /* arg1=void ** */
+    /* Start all ES from the context returned by ES_OUT_PRIV_STOP_ALL_ES */
+    ES_OUT_PRIV_START_ALL_ES,                       /* arg1=void * */
 
     /* Get buffering state */
-    ES_OUT_GET_BUFFERING,                           /* arg1=bool*               res=cannot fail */
+    ES_OUT_PRIV_GET_BUFFERING,                      /* arg1=bool*               res=cannot fail */
 
     /* Set delay for an ES identifier */
-    ES_OUT_SET_ES_DELAY,                            /* arg1=es_out_id_t *, res=cannot fail */
+    ES_OUT_PRIV_SET_ES_DELAY,                       /* arg1=es_out_id_t *, res=cannot fail */
 
     /* Set delay for a ES category */
-    ES_OUT_SET_DELAY,                               /* arg1=es_category_e,      res=cannot fail */
+    ES_OUT_PRIV_SET_DELAY,                          /* arg1=es_category_e,      res=cannot fail */
 
     /* Set record state */
-    ES_OUT_SET_RECORD_STATE,                        /* arg1=bool                res=can fail */
+    ES_OUT_PRIV_SET_RECORD_STATE,                        /* arg1=bool                res=can fail */
 
     /* Set pause state */
-    ES_OUT_SET_PAUSE_STATE,                         /* arg1=bool b_source_paused, bool b_paused arg2=vlc_tick_t res=can fail */
+    ES_OUT_PRIV_SET_PAUSE_STATE,                    /* arg1=bool b_source_paused, bool b_paused arg2=vlc_tick_t res=can fail */
 
     /* Set rate */
-    ES_OUT_SET_RATE,                                /* arg1=double source_rate arg2=double rate res=can fail */
+    ES_OUT_PRIV_SET_RATE,                           /* arg1=double source_rate arg2=double rate res=can fail */
 
     /* Set next frame */
-    ES_OUT_SET_FRAME_NEXT,                          /*                          res=can fail */
+    ES_OUT_PRIV_SET_FRAME_NEXT,                     /*                          res=can fail */
 
     /* Set position/time/length */
-    ES_OUT_SET_TIMES,                               /* arg1=double f_position arg2=vlc_tick_t i_time arg3=vlc_tick_t i_normal_time arg4=vlc_tick_t i_length res=cannot fail */
+    ES_OUT_PRIV_SET_TIMES,                          /* arg1=double f_position arg2=vlc_tick_t i_time arg3=vlc_tick_t i_normal_time arg4=vlc_tick_t i_length res=cannot fail */
 
     /* Set jitter */
-    ES_OUT_SET_JITTER,                              /* arg1=vlc_tick_t i_pts_delay arg2= vlc_tick_t i_pts_jitter, arg2=int i_cr_average res=cannot fail */
+    ES_OUT_PRIV_SET_JITTER,                         /* arg1=vlc_tick_t i_pts_delay arg2= vlc_tick_t i_pts_jitter, arg2=int i_cr_average res=cannot fail */
 
     /* Get forced group */
-    ES_OUT_GET_GROUP_FORCED,                        /* arg1=int * res=cannot fail */
+    ES_OUT_PRIV_GET_GROUP_FORCED,                   /* arg1=int * res=cannot fail */
 
     /* Set End Of Stream */
-    ES_OUT_SET_EOS,                                 /* res=cannot fail */
+    ES_OUT_PRIV_SET_EOS,                            /* res=cannot fail */
 
     /* Set a VBI/Teletext page */
-    ES_OUT_SET_VBI_PAGE,                            /* arg1=unsigned res=can fail */
+    ES_OUT_PRIV_SET_VBI_PAGE,                       /* arg1=unsigned res=can fail */
 
     /* Set VBI/Teletext menu transparent */
-    ES_OUT_SET_VBI_TRANSPARENCY                     /* arg1=bool res=can fail */
+    ES_OUT_PRIV_SET_VBI_TRANSPARENCY                /* arg1=bool res=can fail */
 };
 
+static inline int es_out_vaPrivControl( es_out_t *out, int query, va_list args )
+{
+    vlc_assert( out->cbs->priv_control );
+    return out->cbs->priv_control( out, query, args );
+}
+
+static inline int es_out_PrivControl( es_out_t *out, int query, ... )
+{
+    va_list args;
+    va_start( args, query );
+    int result = es_out_vaPrivControl( out, query, args );
+    va_end( args );
+    return result;
+}
+
 static inline void es_out_SetMode( es_out_t *p_out, int i_mode )
 {
-    int i_ret = es_out_Control( p_out, ES_OUT_SET_MODE, i_mode );
+    int i_ret = es_out_PrivControl( p_out, ES_OUT_PRIV_SET_MODE, i_mode );
     assert( !i_ret );
 }
 static inline vlc_tick_t es_out_GetWakeup( es_out_t *p_out )
 {
     vlc_tick_t i_wu;
-    int i_ret = es_out_Control( p_out, ES_OUT_GET_WAKE_UP, &i_wu );
+    int i_ret = es_out_PrivControl( p_out, ES_OUT_PRIV_GET_WAKE_UP, &i_wu );
 
     assert( !i_ret );
     return i_wu;
@@ -117,7 +132,7 @@ static inline vlc_tick_t es_out_GetWakeup( es_out_t *p_out )
 static inline bool es_out_GetBuffering( es_out_t *p_out )
 {
     bool b;
-    int i_ret = es_out_Control( p_out, ES_OUT_GET_BUFFERING, &b );
+    int i_ret = es_out_PrivControl( p_out, ES_OUT_PRIV_GET_BUFFERING, &b );
 
     assert( !i_ret );
     return b;
@@ -132,55 +147,55 @@ static inline bool es_out_GetEmpty( es_out_t *p_out )
 }
 static inline void es_out_SetEsDelay( es_out_t *p_out, es_out_id_t *es, vlc_tick_t i_delay )
 {
-    int i_ret = es_out_Control( p_out, ES_OUT_SET_ES_DELAY, es, i_delay );
+    int i_ret = es_out_PrivControl( p_out, ES_OUT_PRIV_SET_ES_DELAY, es, i_delay );
     assert( !i_ret );
 }
 static inline void es_out_SetDelay( es_out_t *p_out, int i_cat, vlc_tick_t i_delay )
 {
-    int i_ret = es_out_Control( p_out, ES_OUT_SET_DELAY, i_cat, i_delay );
+    int i_ret = es_out_PrivControl( p_out, ES_OUT_PRIV_SET_DELAY, i_cat, i_delay );
     assert( !i_ret );
 }
 static inline int es_out_SetRecordState( es_out_t *p_out, bool b_record )
 {
-    return es_out_Control( p_out, ES_OUT_SET_RECORD_STATE, b_record );
+    return es_out_PrivControl( p_out, ES_OUT_PRIV_SET_RECORD_STATE, b_record );
 }
 static inline int es_out_SetPauseState( es_out_t *p_out, bool b_source_paused, bool b_paused, vlc_tick_t i_date )
 {
-    return es_out_Control( p_out, ES_OUT_SET_PAUSE_STATE, b_source_paused, b_paused, i_date );
+    return es_out_PrivControl( p_out, ES_OUT_PRIV_SET_PAUSE_STATE, b_source_paused, b_paused, i_date );
 }
 static inline int es_out_SetRate( es_out_t *p_out, float source_rate, float rate )
 {
-    return es_out_Control( p_out, ES_OUT_SET_RATE, source_rate, rate );
+    return es_out_PrivControl( p_out, ES_OUT_PRIV_SET_RATE, source_rate, rate );
 }
 static inline int es_out_SetFrameNext( es_out_t *p_out )
 {
-    return es_out_Control( p_out, ES_OUT_SET_FRAME_NEXT );
+    return es_out_PrivControl( p_out, ES_OUT_PRIV_SET_FRAME_NEXT );
 }
 static inline void es_out_SetTimes( es_out_t *p_out, double f_position,
                                     vlc_tick_t i_time, vlc_tick_t i_normal_time,
                                     vlc_tick_t i_length )
 {
-    int i_ret = es_out_Control( p_out, ES_OUT_SET_TIMES, f_position, i_time,
-                                i_normal_time, i_length );
+    int i_ret = es_out_PrivControl( p_out, ES_OUT_PRIV_SET_TIMES, f_position, i_time,
+                                    i_normal_time, i_length );
     assert( !i_ret );
 }
 static inline void es_out_SetJitter( es_out_t *p_out,
                                      vlc_tick_t i_pts_delay, vlc_tick_t i_pts_jitter, int i_cr_average )
 {
-    int i_ret = es_out_Control( p_out, ES_OUT_SET_JITTER,
-                                i_pts_delay, i_pts_jitter, i_cr_average );
+    int i_ret = es_out_PrivControl( p_out, ES_OUT_PRIV_SET_JITTER,
+                                    i_pts_delay, i_pts_jitter, i_cr_average );
     assert( !i_ret );
 }
 static inline int es_out_GetGroupForced( es_out_t *p_out )
 {
     int i_group;
-    int i_ret = es_out_Control( p_out, ES_OUT_GET_GROUP_FORCED, &i_group );
+    int i_ret = es_out_PrivControl( p_out, ES_OUT_PRIV_GET_GROUP_FORCED, &i_group );
     assert( !i_ret );
     return i_group;
 }
 static inline void es_out_Eos( es_out_t *p_out )
 {
-    int i_ret = es_out_Control( p_out, ES_OUT_SET_EOS );
+    int i_ret = es_out_PrivControl( p_out, ES_OUT_PRIV_SET_EOS );
     assert( !i_ret );
 }
 
diff --git a/src/input/es_out_timeshift.c b/src/input/es_out_timeshift.c
index ff43fe1581..ff8de86b82 100644
--- a/src/input/es_out_timeshift.c
+++ b/src/input/es_out_timeshift.c
@@ -130,22 +130,31 @@ typedef struct attribute_packed
             int i_cat;
             int i_policy;
         } es_policy;
+    } u;
+} ts_cmd_control_t;
+
+typedef struct attribute_packed
+{
+    int  i_query;
+
+    union
+    {
+        int  i_int;
+        struct
+        {
+            vlc_tick_t i_pts_delay;
+            vlc_tick_t i_pts_jitter;
+            int     i_cr_average;
+        } jitter;
         struct
         {
-            /* FIXME Really too big (double make the whole thing too big) */
             double  f_position;
             vlc_tick_t i_time;
             vlc_tick_t i_normal_time;
             vlc_tick_t i_length;
         } times;
-        struct
-        {
-            vlc_tick_t i_pts_delay;
-            vlc_tick_t i_pts_jitter;
-            int     i_cr_average;
-        } jitter;
     } u;
-} ts_cmd_control_t;
+} ts_cmd_privcontrol_t;
 
 typedef struct attribute_packed
 {
@@ -157,6 +166,7 @@ typedef struct attribute_packed
         ts_cmd_del_t     del;
         ts_cmd_send_t    send;
         ts_cmd_control_t control;
+        ts_cmd_privcontrol_t privcontrol;
     } u;
 } ts_cmd_t;
 
@@ -278,6 +288,7 @@ static int  CmdInitAdd    ( ts_cmd_t *, es_out_id_t *, const es_format_t *, bool
 static void CmdInitSend   ( ts_cmd_t *, es_out_id_t *, block_t * );
 static int  CmdInitDel    ( ts_cmd_t *, es_out_id_t * );
 static int  CmdInitControl( ts_cmd_t *, int i_query, va_list, bool b_copy );
+static int  CmdInitPrivControl( ts_cmd_t *, int i_query, va_list, bool b_copy );
 
 /* */
 static void CmdCleanAdd    ( ts_cmd_t * );
@@ -289,6 +300,7 @@ static void CmdExecuteAdd    ( es_out_t *, ts_cmd_t * );
 static int  CmdExecuteSend   ( es_out_t *, ts_cmd_t * );
 static void CmdExecuteDel    ( es_out_t *, ts_cmd_t * );
 static int  CmdExecuteControl( es_out_t *, ts_cmd_t * );
+static int  CmdExecutePrivControl( es_out_t *, ts_cmd_t * );
 
 /* File helpers */
 static int GetTmpFile( char **ppsz_file, const char *psz_path );
@@ -602,7 +614,6 @@ static int ControlLocked( es_out_t *p_out, int i_query, va_list args )
     switch( i_query )
     {
     /* Pass-through control */
-    case ES_OUT_SET_MODE:
     case ES_OUT_SET_GROUP:
     case ES_OUT_SET_PCR:
     case ES_OUT_SET_GROUP_PCR:
@@ -622,9 +633,6 @@ static int ControlLocked( es_out_t *p_out, int i_query, va_list args )
     case ES_OUT_SET_ES_STATE:
     case ES_OUT_SET_ES_CAT_POLICY:
     case ES_OUT_SET_ES_FMT:
-    case ES_OUT_SET_TIMES:
-    case ES_OUT_SET_JITTER:
-    case ES_OUT_SET_EOS:
     {
         ts_cmd_t cmd;
         if( CmdInitControl( &cmd, i_query, args, p_sys->b_delayed ) )
@@ -686,17 +694,80 @@ static int ControlLocked( es_out_t *p_out, int i_query, va_list args )
         bool *pb_empty = va_arg( args, bool* );
         return ControlLockedGetEmpty( p_out, pb_empty );
     }
-    case ES_OUT_GET_WAKE_UP: /* TODO ? */
+
+    case ES_OUT_GET_PCR_SYSTEM:
+        if( p_sys->b_delayed )
+            return VLC_EGENERIC;
+        /* fall through */
+    case ES_OUT_POST_SUBNODE:
+        return es_out_vaControl( p_sys->p_out, i_query, args );
+
+    case ES_OUT_MODIFY_PCR_SYSTEM:
+    {
+        const bool    b_absolute = va_arg( args, int );
+        const vlc_tick_t i_system   = va_arg( args, vlc_tick_t );
+
+        if( b_absolute && p_sys->b_delayed )
+            return VLC_EGENERIC;
+
+        return es_out_ControlModifyPcrSystem( p_sys->p_out, b_absolute, i_system );
+    }
+
+    default:
+        vlc_assert_unreachable();
+        return VLC_EGENERIC;
+    }
+}
+
+static int Control( es_out_t *p_out, int i_query, va_list args )
+{
+    es_out_sys_t *p_sys = container_of(p_out, es_out_sys_t, out);
+    int i_ret;
+
+    vlc_mutex_lock( &p_sys->lock );
+
+    TsAutoStop( p_out );
+
+    i_ret = ControlLocked( p_out, i_query, args );
+
+    vlc_mutex_unlock( &p_sys->lock );
+
+    return i_ret;
+}
+
+static int PrivControlLocked( es_out_t *p_out, int i_query, va_list args )
+{
+    es_out_sys_t *p_sys = container_of(p_out, es_out_sys_t, out);
+
+    switch( i_query )
+    {
+    /* Pass-through control */
+    case ES_OUT_PRIV_SET_MODE:
+    case ES_OUT_PRIV_SET_TIMES:
+    case ES_OUT_PRIV_SET_JITTER:
+    case ES_OUT_PRIV_SET_EOS:
+    {
+        ts_cmd_t cmd;
+        if( CmdInitPrivControl( &cmd, i_query, args, p_sys->b_delayed ) )
+            return VLC_EGENERIC;
+        if( p_sys->b_delayed )
+        {
+            TsPushCmd( p_sys->p_ts, &cmd );
+            return VLC_SUCCESS;
+        }
+        return CmdExecutePrivControl( p_sys->p_out, &cmd );
+    }
+    case ES_OUT_PRIV_GET_WAKE_UP: /* TODO ? */
     {
         vlc_tick_t *pi_wakeup = va_arg( args, vlc_tick_t* );
         return ControlLockedGetWakeup( p_out, pi_wakeup );
     }
-    case ES_OUT_GET_BUFFERING:
+    case ES_OUT_PRIV_GET_BUFFERING:
     {
         bool *pb_buffering = va_arg( args, bool* );
         return ControlLockedGetBuffering( p_out, pb_buffering );
     }
-    case ES_OUT_SET_PAUSE_STATE:
+    case ES_OUT_PRIV_SET_PAUSE_STATE:
     {
         const bool b_source_paused = (bool)va_arg( args, int );
         const bool b_paused = (bool)va_arg( args, int );
@@ -704,55 +775,36 @@ static int ControlLocked( es_out_t *p_out, int i_query, va_list args )
 
         return ControlLockedSetPauseState( p_out, b_source_paused, b_paused, i_date );
     }
-    case ES_OUT_SET_RATE:
+    case ES_OUT_PRIV_SET_RATE:
     {
         const float src_rate = va_arg( args, double );
         const float rate = va_arg( args, double );
 
         return ControlLockedSetRate( p_out, src_rate, rate );
     }
-    case ES_OUT_SET_FRAME_NEXT:
+    case ES_OUT_PRIV_SET_FRAME_NEXT:
     {
         return ControlLockedSetFrameNext( p_out );
     }
-
-    case ES_OUT_GET_PCR_SYSTEM:
-        if( p_sys->b_delayed )
-            return VLC_EGENERIC;
-        /* fall through */
-    case ES_OUT_GET_GROUP_FORCED:
-    case ES_OUT_POST_SUBNODE:
-        return es_out_vaControl( p_sys->p_out, i_query, args );
-
-    case ES_OUT_MODIFY_PCR_SYSTEM:
-    {
-        const bool    b_absolute = va_arg( args, int );
-        const vlc_tick_t i_system   = va_arg( args, vlc_tick_t );
-
-        if( b_absolute && p_sys->b_delayed )
-            return VLC_EGENERIC;
-
-        return es_out_ControlModifyPcrSystem( p_sys->p_out, b_absolute, i_system );
-    }
-
+    case ES_OUT_PRIV_GET_GROUP_FORCED:
+        return es_out_vaPrivControl( p_sys->p_out, i_query, args );
     /* Invalid queries for this es_out level */
-    case ES_OUT_SET_ES_BY_ID:
-    case ES_OUT_SET_ES_LIST:
-    case ES_OUT_RESTART_ES_BY_ID:
-    case ES_OUT_SET_ES_DEFAULT_BY_ID:
-    case ES_OUT_STOP_ALL_ES:
-    case ES_OUT_START_ALL_ES:
-    case ES_OUT_SET_ES_DELAY:
-    case ES_OUT_SET_DELAY:
-    case ES_OUT_SET_RECORD_STATE:
-    case ES_OUT_SET_VBI_PAGE:
-    case ES_OUT_SET_VBI_TRANSPARENCY:
-    default:
-        vlc_assert_unreachable();
-        return VLC_EGENERIC;
+    case ES_OUT_PRIV_SET_ES_LIST:
+    case ES_OUT_PRIV_SET_ES_BY_ID:
+    case ES_OUT_PRIV_RESTART_ES_BY_ID:
+    case ES_OUT_PRIV_SET_ES_DEFAULT_BY_ID:
+    case ES_OUT_PRIV_STOP_ALL_ES:
+    case ES_OUT_PRIV_START_ALL_ES:
+    case ES_OUT_PRIV_SET_ES_DELAY:
+    case ES_OUT_PRIV_SET_DELAY:
+    case ES_OUT_PRIV_SET_RECORD_STATE:
+    case ES_OUT_PRIV_SET_VBI_PAGE:
+    case ES_OUT_PRIV_SET_VBI_TRANSPARENCY:
+    default: vlc_assert_unreachable();
     }
 }
-static int Control( es_out_t *p_out, int i_query, va_list args )
+
+static int PrivControl( es_out_t *p_out, int i_query, va_list args )
 {
     es_out_sys_t *p_sys = container_of(p_out, es_out_sys_t, out);
     int i_ret;
@@ -761,7 +813,7 @@ static int Control( es_out_t *p_out, int i_query, va_list args )
 
     TsAutoStop( p_out );
 
-    i_ret = ControlLocked( p_out, i_query, args );
+    i_ret = PrivControlLocked( p_out, i_query, args );
 
     vlc_mutex_unlock( &p_sys->lock );
 
@@ -775,6 +827,7 @@ static const struct es_out_callbacks es_out_timeshift_cbs =
     .del = Del,
     .control = Control,
     .destroy = Destroy,
+    .priv_control = PrivControl,
 };
 
 /*****************************************************************************
@@ -1388,7 +1441,6 @@ static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_co
     switch( i_query )
     {
     /* Pass-through control */
-    case ES_OUT_SET_MODE:    /* arg1= int                            */
     case ES_OUT_SET_GROUP:   /* arg1= int                            */
     case ES_OUT_DEL_GROUP:   /* arg1=int i_group */
         p_cmd->u.control.u.i_int = va_arg( args, int );
@@ -1410,7 +1462,6 @@ static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_co
         break;
 
     case ES_OUT_RESET_PCR:           /* no arg */
-    case ES_OUT_SET_EOS:
         break;
 
     case ES_OUT_SET_META:        /* arg1=const vlc_meta_t* */
@@ -1511,31 +1562,6 @@ static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_co
         }
         break;
     }
-    case ES_OUT_SET_TIMES:
-    {
-        double f_position = va_arg( args, double );
-        vlc_tick_t i_time = va_arg( args, vlc_tick_t );
-        vlc_tick_t i_normal_time = va_arg( args, vlc_tick_t );
-        vlc_tick_t i_length = va_arg( args, vlc_tick_t );
-
-        p_cmd->u.control.u.times.f_position = f_position;
-        p_cmd->u.control.u.times.i_time = i_time;
-        p_cmd->u.control.u.times.i_normal_time = i_normal_time;
-        p_cmd->u.control.u.times.i_length = i_length;
-        break;
-    }
-    case ES_OUT_SET_JITTER:
-    {
-        vlc_tick_t i_pts_delay = va_arg( args, vlc_tick_t );
-        vlc_tick_t i_pts_jitter = va_arg( args, vlc_tick_t );
-        int     i_cr_average = va_arg( args, int );
-
-        p_cmd->u.control.u.jitter.i_pts_delay = i_pts_delay;
-        p_cmd->u.control.u.jitter.i_pts_jitter = i_pts_jitter;
-        p_cmd->u.control.u.jitter.i_cr_average = i_cr_average;
-        break;
-    }
-
     default:
         vlc_assert_unreachable();
         return VLC_EGENERIC;
@@ -1550,7 +1576,6 @@ static int CmdExecuteControl( es_out_t *p_out, ts_cmd_t *p_cmd )
     switch( i_query )
     {
     /* Pass-through control */
-    case ES_OUT_SET_MODE:    /* arg1= int                            */
     case ES_OUT_SET_GROUP:   /* arg1= int                            */
     case ES_OUT_DEL_GROUP:   /* arg1=int i_group */
         return es_out_Control( p_out, i_query, p_cmd->u.control.u.i_int );
@@ -1564,7 +1589,6 @@ static int CmdExecuteControl( es_out_t *p_out, ts_cmd_t *p_cmd )
                                                p_cmd->u.control.u.int_i64.i_i64 );
 
     case ES_OUT_RESET_PCR:           /* no arg */
-    case ES_OUT_SET_EOS:
         return es_out_Control( p_out, i_query );
 
     case ES_OUT_SET_GROUP_META:  /* arg1=int i_group arg2=const vlc_meta_t* */
@@ -1609,16 +1633,6 @@ static int CmdExecuteControl( es_out_t *p_out, ts_cmd_t *p_cmd )
         return es_out_Control( p_out, i_query, p_cmd->u.control.u.es_fmt.p_es->p_es,
                                                p_cmd->u.control.u.es_fmt.p_fmt );
 
-    case ES_OUT_SET_TIMES:
-        return es_out_Control( p_out, i_query, p_cmd->u.control.u.times.f_position,
-                                               p_cmd->u.control.u.times.i_time,
-                                               p_cmd->u.control.u.times.i_normal_time,
-                                               p_cmd->u.control.u.times.i_length );
-    case ES_OUT_SET_JITTER:
-        return es_out_Control( p_out, i_query, p_cmd->u.control.u.jitter.i_pts_delay,
-                                               p_cmd->u.control.u.jitter.i_pts_jitter,
-                                               p_cmd->u.control.u.jitter.i_cr_average );
-
     default:
         vlc_assert_unreachable();
         return VLC_EGENERIC;
@@ -1651,6 +1665,76 @@ static void CmdCleanControl( ts_cmd_t *p_cmd )
     }
 }
 
+static int CmdInitPrivControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_copy )
+{
+    VLC_UNUSED( b_copy );
+    p_cmd->i_type = C_CONTROL;
+    p_cmd->i_date = vlc_tick_now();
+    p_cmd->u.privcontrol.i_query = i_query;
+
+    switch( i_query )
+    {
+    /* Pass-through control */
+    case ES_OUT_PRIV_SET_MODE:    /* arg1= int                            */
+        p_cmd->u.privcontrol.u.i_int = va_arg( args, int );
+        break;
+    case ES_OUT_PRIV_SET_JITTER:
+    {
+        vlc_tick_t i_pts_delay = va_arg( args, vlc_tick_t );
+        vlc_tick_t i_pts_jitter = va_arg( args, vlc_tick_t );
+        int     i_cr_average = va_arg( args, int );
+
+        p_cmd->u.privcontrol.u.jitter.i_pts_delay = i_pts_delay;
+        p_cmd->u.privcontrol.u.jitter.i_pts_jitter = i_pts_jitter;
+        p_cmd->u.privcontrol.u.jitter.i_cr_average = i_cr_average;
+        break;
+    }
+    case ES_OUT_PRIV_SET_TIMES:
+    {
+        double f_position = va_arg( args, double );
+        vlc_tick_t i_time = va_arg( args, vlc_tick_t );
+        vlc_tick_t i_normal_time = va_arg( args, vlc_tick_t );
+        vlc_tick_t i_length = va_arg( args, vlc_tick_t );
+
+        p_cmd->u.privcontrol.u.times.f_position = f_position;
+        p_cmd->u.privcontrol.u.times.i_time = i_time;
+        p_cmd->u.privcontrol.u.times.i_normal_time = i_normal_time;
+        p_cmd->u.privcontrol.u.times.i_length = i_length;
+        break;
+    }
+    case ES_OUT_PRIV_SET_EOS: /* no arg */
+        break;
+    default: vlc_assert_unreachable();
+    }
+
+    return VLC_SUCCESS;
+}
+
+static int CmdExecutePrivControl( es_out_t *p_out, ts_cmd_t *p_cmd )
+{
+    const int i_query = p_cmd->u.privcontrol.i_query;
+
+    switch( i_query )
+    {
+    /* Pass-through control */
+    case ES_OUT_PRIV_SET_MODE:    /* arg1= int                            */
+        return es_out_PrivControl( p_out, i_query, p_cmd->u.privcontrol.u.i_int );
+    case ES_OUT_PRIV_SET_JITTER:
+        return es_out_PrivControl( p_out, i_query, p_cmd->u.privcontrol.u.jitter.i_pts_delay,
+                                   p_cmd->u.privcontrol.u.jitter.i_pts_jitter,
+                                   p_cmd->u.privcontrol.u.jitter.i_cr_average );
+    case ES_OUT_PRIV_SET_TIMES:
+        return es_out_PrivControl( p_out, i_query,
+                                   p_cmd->u.privcontrol.u.times.f_position,
+                                   p_cmd->u.privcontrol.u.times.i_time,
+                                   p_cmd->u.privcontrol.u.times.i_normal_time,
+                                   p_cmd->u.privcontrol.u.times.i_length );
+    case ES_OUT_PRIV_SET_EOS: /* no arg */
+        return es_out_PrivControl( p_out, i_query );
+    default: vlc_assert_unreachable();
+    }
+}
+
 static int GetTmpFile( char **filename, const char *dirname )
 {
     if( dirname != NULL
diff --git a/src/input/input.c b/src/input/input.c
index 74e4f87d8b..36b243aa75 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -2014,9 +2014,9 @@ static bool Control( input_thread_t *p_input,
             break;
         case INPUT_CONTROL_SET_ES_LIST:
         {
-            if( es_out_Control( input_priv(p_input)->p_es_out_display,
-                                ES_OUT_SET_ES_LIST, param.list.cat,
-                                param.list.ids ) == VLC_SUCCESS )
+            if( es_out_PrivControl( input_priv(p_input)->p_es_out_display,
+                                    ES_OUT_PRIV_SET_ES_LIST, param.list.cat,
+                                    param.list.ids ) == VLC_SUCCESS )
             {
                 if( param.list.ids[0] != NULL && param.list.ids[1] == NULL )
                     demux_Control( input_priv(p_input)->master->p_demux, DEMUX_SET_ES,
@@ -2238,8 +2238,8 @@ static bool Control( input_thread_t *p_input,
                 break;
 
             void *context;
-            if( es_out_Control( priv->p_es_out_display,
-                                ES_OUT_STOP_ALL_ES, &context ) != VLC_SUCCESS )
+            if( es_out_PrivControl( priv->p_es_out_display,
+                                    ES_OUT_PRIV_STOP_ALL_ES, &context ) != VLC_SUCCESS )
                 break;
 
             if ( p_priv->p_renderer )
@@ -2261,23 +2261,23 @@ static bool Control( input_thread_t *p_input,
                                         vlc_renderer_item_demux_filter( p_item ) );
                 }
             }
-            es_out_Control( priv->p_es_out_display, ES_OUT_START_ALL_ES,
-                            context );
+            es_out_PrivControl( priv->p_es_out_display, ES_OUT_PRIV_START_ALL_ES,
+                                context );
 #endif
             break;
         }
         case INPUT_CONTROL_SET_VBI_PAGE:
-            es_out_Control( priv->p_es_out_display, ES_OUT_SET_VBI_PAGE,
-                            param.vbi_page.id, param.vbi_page.page );
+            es_out_PrivControl( priv->p_es_out_display, ES_OUT_PRIV_SET_VBI_PAGE,
+                                param.vbi_page.id, param.vbi_page.page );
             break;
         case INPUT_CONTROL_SET_VBI_TRANSPARENCY:
-            es_out_Control( priv->p_es_out_display, ES_OUT_SET_VBI_TRANSPARENCY,
-                            param.vbi_transparency.id,
-                            param.vbi_transparency.enabled );
+            es_out_PrivControl( priv->p_es_out_display, ES_OUT_PRIV_SET_VBI_TRANSPARENCY,
+                                param.vbi_transparency.id,
+                                param.vbi_transparency.enabled );
             break;
         case INPUT_CONTROL_SET_ES_AUTOSELECT:
-            es_out_Control( priv->p_es_out_display, ES_OUT_SET_AUTOSELECT,
-                            param.es_autoselect.cat, param.es_autoselect.enabled );
+            es_out_PrivControl( priv->p_es_out_display, ES_OUT_PRIV_SET_AUTOSELECT,
+                                param.es_autoselect.cat, param.es_autoselect.enabled );
             break;
 
         case INPUT_CONTROL_NAV_ACTIVATE:
@@ -3306,10 +3306,10 @@ static int input_SlaveSourceAdd( input_thread_t *p_input,
 
     assert( priv->i_last_es_id != -1 );
 
-    es_out_Control( priv->p_es_out_display, ES_OUT_SET_ES_DEFAULT_BY_ID,
-                    priv->i_last_es_id );
-    es_out_Control( priv->p_es_out_display, ES_OUT_SET_ES_BY_ID,
-                    priv->i_last_es_id, false );
+    es_out_PrivControl( priv->p_es_out_display, ES_OUT_PRIV_SET_ES_DEFAULT_BY_ID,
+                        priv->i_last_es_id );
+    es_out_PrivControl( priv->p_es_out_display, ES_OUT_PRIV_SET_ES_BY_ID,
+                        priv->i_last_es_id, false );
 
     return VLC_SUCCESS;
 }
diff --git a/test/modules/demux/timestamps_filter.c b/test/modules/demux/timestamps_filter.c
index e183938aae..f115fc394d 100644
--- a/test/modules/demux/timestamps_filter.c
+++ b/test/modules/demux/timestamps_filter.c
@@ -76,6 +76,7 @@ static const struct es_out_callbacks trash_es_out_cbs =
     trash_es_out_Del,
     trash_es_out_Control,
     trash_es_out_Delete,
+    NULL,
 };
 
 #define TIMELINE_0 (CLOCK_FREQ)



More information about the vlc-commits mailing list