[vlc-devel] [PATCH 5/5] core: first cleaning of input_thread_t variables/event

Thomas Guillem thomas at gllm.fr
Tue Jul 10 15:43:09 CEST 2018


Currently, the input_thread_t is controllable by either input_Control, specific
functions, by variables or by the 3 previous solutions. Some functionalities
are only controllable by variables (chapter for example).

The goal of this commit is to remove variables usage when it's not necessary.
This commit doesn't remove variables that should be used to pass users settings
(cf.  input_ConfigVarInit).

The "intf-event" callback is replaced by the new callback
input_thread_events_cb that pass a new event: struct vlc_input_event. There can
be only one listener: the creator of the input_thread_t. In the future, the new
vlc input manager will receive these events and forward them to all listeners.
In the meantime, I added input_LegacyVarInit, input_LegacyVarStop, and
input_LegacyEvents, 3 helpers functions that reproduce the legacy variable
behavior (transform new vlc_input_event to old intf-event events). These 3
functions are meant to be removed for 4.0 release (when vlc input manager is
added).

For now, the playlist and the media_player still use the legacy variables. VLM,
modules, and the preparser use the new event handling.

FIXME: there are some functionalities that are only controlable by variables,
like chapter selection, I need then to add a public API or a public
INPUT_CONTROL for thoses.
---
 include/vlc_input.h                  | 100 ++++++-
 lib/media_player.c                   |   6 +-
 modules/misc/fingerprinter.c         |  25 +-
 modules/services_discovery/podcast.c |   2 +-
 src/input/control.c                  |   9 +-
 src/input/es_out.c                   |   3 -
 src/input/event.c                    | 388 ++++++++++++---------------
 src/input/event.h                    |   1 +
 src/input/input_interface.h          |   4 +-
 src/input/input_internal.c           |  57 ++--
 src/input/input_internal.h           |   7 +-
 src/input/var.c                      | 313 ++++++++++++++++++---
 src/input/vlm.c                      |  69 +++--
 src/libvlccore.sym                   |   3 +
 src/playlist/thread.c                |  10 +-
 src/preparser/preparser.c            |  18 +-
 16 files changed, 649 insertions(+), 366 deletions(-)

diff --git a/include/vlc_input.h b/include/vlc_input.h
index 9ded0a16de..d43902beef 100644
--- a/include/vlc_input.h
+++ b/include/vlc_input.h
@@ -335,6 +335,9 @@ typedef enum input_event_type_e
     /* "rate" has changed */
     INPUT_EVENT_RATE,
 
+    /* "capabilities" has changed */
+    INPUT_EVENT_CAPABILITIES,
+
     /* At least one of "position" or "time" */
     INPUT_EVENT_POSITION,
 
@@ -388,6 +391,88 @@ typedef enum input_event_type_e
 
 } input_event_type_e;
 
+#define VLC_INPUT_CAPABILITIES_SEEKABLE (1<<0)
+#define VLC_INPUT_CAPABILITIES_PAUSEABLE (1<<1)
+#define VLC_INPUT_CAPABILITIES_CHANGE_RATE (1<<2)
+#define VLC_INPUT_CAPABILITIES_REWINDABLE (1<<3)
+#define VLC_INPUT_CAPABILITIES_RECORDABLE (1<<4)
+
+struct vlc_input_event
+{
+    input_event_type_e type;
+
+    union {
+        /* INPUT_EVENT_STATE */
+        input_state_e state;
+        /* INPUT_EVENT_RATE */
+        float rate;
+        /* INPUT_EVENT_CAPABILITIES */
+        int capabilities; /**< cf. VLC_INPUT_CAPABILITIES_* bitwise flags */
+        /* INPUT_EVENT_POSITION */
+        struct {
+            float     percentage;
+            vlc_tick_t ms;
+        } position;
+        /* INPUT_EVENT_LENGTH */
+        vlc_tick_t length;
+        /* INPUT_EVENT_TITLE */
+        int title;
+        /* INPUT_EVENT_CHAPTER */
+        struct {
+            int title;
+            int seekpoint;
+        } chapter;
+        /* INPUT_EVENT_PROGRAM */
+        struct {
+            enum {
+                VLC_INPUT_PROGRAM_ADDED,
+                VLC_INPUT_PROGRAM_DELETED,
+                VLC_INPUT_PROGRAM_SELECTED,
+                VLC_INPUT_PROGRAM_SCRAMBLED,
+            } action;
+            int id;
+            union {
+                const char *title;
+                bool scrambled;
+            };
+        } program;
+        /* INPUT_EVENT_ES */
+        struct {
+            enum {
+                VLC_INPUT_ES_ADDED,
+                VLC_INPUT_ES_DELETED,
+                VLC_INPUT_ES_SELECTED,
+            } action;
+            enum es_format_category_e cat;
+            int id; /**< id == -1 will unselect */
+            const char *title;
+        } es;
+        /* INPUT_EVENT_TELETEXT */
+        struct {
+            enum {
+                VLC_INPUT_TELETEXT_ADDED,
+                VLC_INPUT_TELETEXT_DELETED,
+                VLC_INPUT_TELETEXT_SELECTED,
+            } action;
+            int id; /**< id == -1 will unselect */
+            const char *title;
+        } teletext;
+        /* INPUT_EVENT_RECORD */
+        bool record;
+        /* INPUT_EVENT_SIGNAL */
+        struct {
+            float quality;
+            float strength;
+        } signal;
+        /* INPUT_EVENT_AUDIO_DELAY */
+        vlc_tick_t audio_delay;
+        /* INPUT_EVENT_SUBTITLE_DELAY */
+        vlc_tick_t subtitle_delay;
+        /* INPUT_EVENT_CACHE */
+        float cache;
+    };
+};
+
 /**
  * Input queries
  */
@@ -467,7 +552,6 @@ enum input_query_e
 
     /* On the fly record while playing */
     INPUT_SET_RECORD_STATE, /* arg1=bool    res=can fail */
-    INPUT_GET_RECORD_STATE, /* arg1=bool*   res=can fail */
 
     /* ES */
     INPUT_RESTART_ES,       /* arg1=int (-AUDIO/VIDEO/SPU_ES for the whole category) */
@@ -495,11 +579,15 @@ enum input_query_e
 /*****************************************************************************
  * Prototypes
  *****************************************************************************/
+typedef void (*input_thread_events_cb)( input_thread_t *input,
+                                        const struct vlc_input_event *event,
+                                        void *user_data );
 
-VLC_API input_thread_t * input_Create( vlc_object_t *p_parent, input_item_t *,
-                                       const char *psz_log, input_resource_t *,
+VLC_API input_thread_t * input_Create( vlc_object_t *p_parent,
+                                       input_thread_events_cb event_cb, void *events_data,
+                                       input_item_t *, const char *psz_log, input_resource_t *,
                                        vlc_renderer_item_t* p_renderer ) VLC_USED;
-#define input_Create(a,b,c,d,e) input_Create(VLC_OBJECT(a),b,c,d,e)
+#define input_Create(a,b,c,d,e,f,g) input_Create(VLC_OBJECT(a),b,c,d,e,f,g)
 
 VLC_API int input_Start( input_thread_t * );
 
@@ -518,6 +606,10 @@ VLC_API void input_SetTime( input_thread_t *, vlc_tick_t i_time, bool b_fast );
 
 VLC_API void input_SetPosition( input_thread_t *, float f_position, bool b_fast );
 
+VLC_API void input_LegacyEvents(input_thread_t *, const struct vlc_input_event *, void *);
+VLC_API void input_LegacyVarInit ( input_thread_t * );
+VLC_API void input_LegacyVarStop( input_thread_t * );
+
 /**
  * Get the input item for an input thread
  *
diff --git a/lib/media_player.c b/lib/media_player.c
index e293e2cbb0..5a8b09f261 100644
--- a/lib/media_player.c
+++ b/lib/media_player.c
@@ -179,6 +179,7 @@ static void release_input_thread( libvlc_media_player_t *p_mi )
     var_DelCallback( p_input_thread, "intf-event",
                      input_event_changed, p_mi );
     del_es_callbacks( p_input_thread, p_mi );
+    input_LegacyVarStop( p_input_thread );
 
     /* We owned this one */
     input_Stop( p_input_thread );
@@ -984,7 +985,8 @@ int libvlc_media_player_play( libvlc_media_player_t *p_mi )
 
     media_attach_preparsed_event( p_mi->p_md );
 
-    p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL,
+    p_input_thread = input_Create( p_mi, input_LegacyEvents, NULL,
+                                   p_mi->p_md->p_input_item, NULL,
                                    p_mi->input.p_resource,
                                    p_mi->input.p_renderer );
     unlock(p_mi);
@@ -996,6 +998,7 @@ int libvlc_media_player_play( libvlc_media_player_t *p_mi )
         return -1;
     }
 
+    input_LegacyVarInit( p_input_thread );
     var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
     var_AddCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
@@ -1010,6 +1013,7 @@ int libvlc_media_player_play( libvlc_media_player_t *p_mi )
         var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
         var_DelCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
         var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
+        input_LegacyVarStop( p_input_thread );
         input_Close( p_input_thread );
         media_detach_preparsed_event( p_mi->p_md );
         libvlc_printerr( "Input initialization failure" );
diff --git a/modules/misc/fingerprinter.c b/modules/misc/fingerprinter.c
index 58d12cfa47..36cc1a0e68 100644
--- a/modules/misc/fingerprinter.c
+++ b/modules/misc/fingerprinter.c
@@ -128,17 +128,14 @@ static void ApplyResult( fingerprint_request_t *p_r, size_t i_resultid )
     vlc_mutex_unlock( &p_item->lock );
 }
 
-static int InputEventHandler( vlc_object_t *p_this, char const *psz_cmd,
-                              vlc_value_t oldval, vlc_value_t newval,
-                              void *p_data )
+static void InputEvent( input_thread_t *p_input,
+                        const struct vlc_input_event *p_event,
+                        void *p_user_data )
 {
-    VLC_UNUSED( psz_cmd );
-    VLC_UNUSED( oldval );
-    input_thread_t *p_input = (input_thread_t *) p_this;
-    fingerprinter_sys_t *p_sys = (fingerprinter_sys_t *) p_data;
-    if( newval.i_int == INPUT_EVENT_STATE )
+    fingerprinter_sys_t *p_sys = p_user_data;
+    if( p_event->type == INPUT_EVENT_STATE )
     {
-        if( var_GetInteger( p_input, "state" ) >= PAUSE_S )
+        if( p_event->state >= PAUSE_S )
         {
             vlc_mutex_lock( &p_sys->processing.lock );
             p_sys->processing.b_working = false;
@@ -185,7 +182,9 @@ static void DoFingerprint( fingerprinter_thread_t *p_fingerprinter,
     }
     input_item_SetURI( p_item, psz_uri ) ;
 
-    input_thread_t *p_input = input_Create( p_fingerprinter, p_item, "fingerprinter", NULL, NULL );
+    input_thread_t *p_input = input_Create( p_fingerprinter, InputEvent,
+                                            p_fingerprinter->p_sys,
+                                            p_item, "fingerprinter", NULL, NULL );
     input_item_Release( p_item );
 
     if( p_input == NULL )
@@ -199,13 +198,8 @@ static void DoFingerprint( fingerprinter_thread_t *p_fingerprinter,
     var_Create( p_input, "fingerprint-data", VLC_VAR_ADDRESS );
     var_SetAddress( p_input, "fingerprint-data", &chroma_fingerprint );
 
-    var_AddCallback( p_input, "intf-event", InputEventHandler, p_fingerprinter->p_sys );
-
     if( input_Start( p_input ) != VLC_SUCCESS )
-    {
-        var_DelCallback( p_input, "intf-event", InputEventHandler, p_fingerprinter->p_sys );
         input_Close( p_input );
-    }
     else
     {
         p_fingerprinter->p_sys->processing.b_working = true;
@@ -214,7 +208,6 @@ static void DoFingerprint( fingerprinter_thread_t *p_fingerprinter,
             vlc_cond_wait( &p_fingerprinter->p_sys->processing.cond,
                            &p_fingerprinter->p_sys->processing.lock );
         }
-        var_DelCallback( p_input, "intf-event", InputEventHandler, p_fingerprinter->p_sys );
         input_Stop( p_input );
         input_Close( p_input );
 
diff --git a/modules/services_discovery/podcast.c b/modules/services_discovery/podcast.c
index 690a324718..9fd8c35c17 100644
--- a/modules/services_discovery/podcast.c
+++ b/modules/services_discovery/podcast.c
@@ -213,7 +213,7 @@ static void Close( vlc_object_t *p_this )
 static input_thread_t *InputCreateAndStart( services_discovery_t *sd,
                                             input_item_t *item )
 {
-    input_thread_t *input = input_Create( sd, item, NULL, NULL, NULL );
+    input_thread_t *input = input_Create( sd, NULL, NULL, item, NULL, NULL, NULL );
     if( input != NULL && input_Start( input ) )
     {
         vlc_object_release( input );
diff --git a/src/input/control.c b/src/input/control.c
index 133f76ebed..9f47cc1ebd 100644
--- a/src/input/control.c
+++ b/src/input/control.c
@@ -494,13 +494,8 @@ int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
         }
 
         case INPUT_SET_RECORD_STATE:
-            b_bool = va_arg( args, int );
-            var_SetBool( p_input, "record", b_bool );
-            return VLC_SUCCESS;
-
-        case INPUT_GET_RECORD_STATE:
-            pb_bool = va_arg( args, bool* );
-            *pb_bool = var_GetBool( p_input, "record" );
+            input_ControlPushHelper( p_input, INPUT_CONTROL_SET_RECORD_STATE,
+                &(vlc_value_t) { .b_bool = va_arg( args, int ) });
             return VLC_SUCCESS;
 
         case INPUT_RESTART_ES:
diff --git a/src/input/es_out.c b/src/input/es_out.c
index cd61ba76e3..e8c1a511e8 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -1040,9 +1040,6 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
     input_SendEventTeletextDel( p_input, -1 );
     input_SendEventProgramScrambled( p_input, p_pgrm->i_id, p_pgrm->b_scrambled );
 
-    /* TODO event */
-    var_SetInteger( p_input, "teletext-es", -1 );
-
     foreach_es_then_es_slaves(es)
     {
         if (es->p_pgrm == p_sys->p_pgrm)
diff --git a/src/input/event.c b/src/input/event.c
index 1f94918ebb..634fd4c02c 100644
--- a/src/input/event.c
+++ b/src/input/event.c
@@ -34,174 +34,142 @@
 #include "event.h"
 #include <assert.h>
 
-/* */
-static void Trigger( input_thread_t *, int i_type );
-static void VarListAdd( input_thread_t *,
-                        const char *psz_variable, int i_event,
-                        int i_value, const char *psz_text );
-static void VarListDel( input_thread_t *,
-                        const char *psz_variable, int i_event,
-                        int i_value );
-static void VarListSelect( input_thread_t *,
-                           const char *psz_variable, int i_event,
-                           int i_value );
+static void input_SendEvent( input_thread_t *p_input,
+                             const struct vlc_input_event *event )
+{
+    input_thread_private_t *priv = input_priv(p_input);
+    if( priv->events_cb )
+        priv->events_cb( p_input, event, priv->events_data );
+}
 
-/*****************************************************************************
- * Event for input.c
- *****************************************************************************/
 void input_SendEventDead( input_thread_t *p_input )
 {
-    Trigger( p_input, INPUT_EVENT_DEAD );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_DEAD,
+    });
 }
 
-void input_SendEventPosition( input_thread_t *p_input, double f_position, vlc_tick_t i_time )
+void input_SendEventCapabilities( input_thread_t *p_input, int i_capabilities )
 {
-    vlc_value_t val;
-
-    /* */
-    val.f_float = f_position;
-    var_Change( p_input, "position", VLC_VAR_SETVALUE, val );
-
-    /* */
-    val.i_int = i_time;
-    var_Change( p_input, "time", VLC_VAR_SETVALUE, val );
-
-    Trigger( p_input, INPUT_EVENT_POSITION );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_CAPABILITIES,
+        .capabilities = i_capabilities
+    });
+}
+void input_SendEventPosition( input_thread_t *p_input, double f_position,
+                              vlc_tick_t i_time )
+{
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_POSITION,
+        .position = { f_position, i_time }
+    });
 }
 void input_SendEventLength( input_thread_t *p_input, vlc_tick_t i_length )
 {
-    vlc_value_t val;
-
-    /* FIXME ugly + what about meta change event ? */
-    if( var_GetInteger( p_input, "length" ) == i_length )
-        return;
-
     input_item_SetDuration( input_priv(p_input)->p_item, i_length );
-
-    val.i_int = i_length;
-    var_Change( p_input, "length", VLC_VAR_SETVALUE, val );
-
-    Trigger( p_input, INPUT_EVENT_LENGTH );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_LENGTH,
+        .length = i_length,
+    });
 }
 void input_SendEventStatistics( input_thread_t *p_input )
 {
-    Trigger( p_input, INPUT_EVENT_STATISTICS );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_STATISTICS,
+    });
 }
 void input_SendEventRate( input_thread_t *p_input, int i_rate )
 {
-    vlc_value_t val;
-
-    val.f_float = (float)INPUT_RATE_DEFAULT / (float)i_rate;
-    var_Change( p_input, "rate", VLC_VAR_SETVALUE, val );
-
-    Trigger( p_input, INPUT_EVENT_RATE );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_RATE,
+        .rate = (float)INPUT_RATE_DEFAULT / (float)i_rate,
+    });
 }
 void input_SendEventAudioDelay( input_thread_t *p_input, vlc_tick_t i_delay )
 {
-    vlc_value_t val;
-
-    val.i_int = i_delay;
-    var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, val );
-
-    Trigger( p_input, INPUT_EVENT_AUDIO_DELAY );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_AUDIO_DELAY,
+        .audio_delay = i_delay,
+    });
 }
 
 void input_SendEventSubtitleDelay( input_thread_t *p_input, vlc_tick_t i_delay )
 {
-    vlc_value_t val;
-
-    val.i_int = i_delay;
-    var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, val );
-
-    Trigger( p_input, INPUT_EVENT_SUBTITLE_DELAY );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_SUBTITLE_DELAY,
+        .subtitle_delay = i_delay,
+    });
 }
 
 /* TODO and file name ? */
 void input_SendEventRecord( input_thread_t *p_input, bool b_recording )
 {
-    vlc_value_t val;
-
-    val.b_bool = b_recording;
-    var_Change( p_input, "record", VLC_VAR_SETVALUE, val );
-
-    Trigger( p_input, INPUT_EVENT_RECORD );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_RECORD,
+        .record = b_recording
+    });
 }
 
 void input_SendEventTitle( input_thread_t *p_input, int i_title )
 {
-    vlc_value_t val;
-
-    val.i_int = i_title;
-    var_Change( p_input, "title", VLC_VAR_SETVALUE, val );
-
-    input_ControlVarTitle( p_input, i_title );
-
-    Trigger( p_input, INPUT_EVENT_TITLE );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_TITLE,
+        .title = i_title
+    });
 }
 
 void input_SendEventSeekpoint( input_thread_t *p_input, int i_title, int i_seekpoint )
 {
-    vlc_value_t val;
-
-    /* "chapter" */
-    val.i_int = i_seekpoint;
-    var_Change( p_input, "chapter", VLC_VAR_SETVALUE, val );
-
-    /* "title %2u" */
-    char psz_title[sizeof ("title ") + 3 * sizeof (int)];
-    sprintf( psz_title, "title %2u", i_title );
-    var_Change( p_input, psz_title, VLC_VAR_SETVALUE, val );
-
-    /* */
-    Trigger( p_input, INPUT_EVENT_CHAPTER );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_CHAPTER,
+        .chapter = { i_title, i_seekpoint }
+    });
 }
 
-void input_SendEventSignal( input_thread_t *p_input, double f_quality, double f_strength )
+void input_SendEventSignal( input_thread_t *p_input, double f_quality,
+                            double f_strength )
 {
-    vlc_value_t val;
-
-    val.f_float = f_quality;
-    var_Change( p_input, "signal-quality", VLC_VAR_SETVALUE, val );
-
-    val.f_float = f_strength;
-    var_Change( p_input, "signal-strength", VLC_VAR_SETVALUE, val );
-
-    Trigger( p_input, INPUT_EVENT_SIGNAL );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_SIGNAL,
+        .signal = { f_quality, f_strength }
+    });
 }
 
 void input_SendEventState( input_thread_t *p_input, int i_state )
 {
-    vlc_value_t val;
-
-    val.i_int = i_state;
-    var_Change( p_input, "state", VLC_VAR_SETVALUE, val );
-
-    Trigger( p_input, INPUT_EVENT_STATE );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_STATE,
+        .state = i_state
+    });
 }
 
 void input_SendEventCache( input_thread_t *p_input, double f_level )
 {
-    vlc_value_t val;
-
-    val.f_float = f_level;
-    var_Change( p_input, "cache", VLC_VAR_SETVALUE, val );
-
-    Trigger( p_input, INPUT_EVENT_CACHE );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_CACHE,
+        .cache = f_level
+    });
 }
 
 void input_SendEventMeta( input_thread_t *p_input )
 {
-    Trigger( p_input, INPUT_EVENT_ITEM_META );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_ITEM_META,
+    });
 }
 
 void input_SendEventMetaInfo( input_thread_t *p_input )
 {
-    Trigger( p_input, INPUT_EVENT_ITEM_INFO );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_ITEM_INFO,
+    });
 }
 
 void input_SendEventMetaEpg( input_thread_t *p_input )
 {
-    Trigger( p_input, INPUT_EVENT_ITEM_EPG );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_ITEM_EPG,
+    });
 }
 /*****************************************************************************
  * Event for es_out.c
@@ -209,138 +177,136 @@ void input_SendEventMetaEpg( input_thread_t *p_input )
 void input_SendEventProgramAdd( input_thread_t *p_input,
                                 int i_program, const char *psz_text )
 {
-    VarListAdd( p_input, "program", INPUT_EVENT_PROGRAM, i_program, psz_text );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_PROGRAM,
+        .program = {
+            .action = VLC_INPUT_PROGRAM_ADDED,
+            .id = i_program,
+            .title = psz_text
+        }
+    });
 }
 void input_SendEventProgramDel( input_thread_t *p_input, int i_program )
 {
-    VarListDel( p_input, "program", INPUT_EVENT_PROGRAM, i_program );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_PROGRAM, 
+        .program = {
+            .action = VLC_INPUT_PROGRAM_DELETED,
+            .id = i_program
+        }
+    });
 }
 void input_SendEventProgramSelect( input_thread_t *p_input, int i_program )
 {
-    VarListSelect( p_input, "program", INPUT_EVENT_PROGRAM, i_program );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_PROGRAM, 
+        .program = {
+            .action = VLC_INPUT_PROGRAM_SELECTED,
+            .id = i_program
+        }
+    });
 }
 void input_SendEventProgramScrambled( input_thread_t *p_input, int i_group, bool b_scrambled )
 {
-    if( var_GetInteger( p_input, "program" ) != i_group )
-        return;
-
-    var_SetBool( p_input, "program-scrambled", b_scrambled );
-    Trigger( p_input, INPUT_EVENT_PROGRAM );
-}
-
-static const char *GetEsVarName( enum es_format_category_e i_cat )
-{
-    switch( i_cat )
-    {
-    case VIDEO_ES:
-        return "video-es";
-    case AUDIO_ES:
-        return "audio-es";
-    case SPU_ES:
-        return "spu-es";
-    default:
-        return NULL;
-    }
-}
-void input_SendEventEsAdd( input_thread_t *p_input, enum es_format_category_e i_cat, int i_id, const char *psz_text )
-{
-    const char *psz_varname = GetEsVarName( i_cat );
-    if( psz_varname )
-        VarListAdd( p_input, psz_varname, INPUT_EVENT_ES, i_id, psz_text );
-}
-void input_SendEventEsDel( input_thread_t *p_input, enum es_format_category_e i_cat, int i_id )
-{
-    const char *psz_varname = GetEsVarName( i_cat );
-    if( psz_varname )
-        VarListDel( p_input, psz_varname, INPUT_EVENT_ES, i_id );
-}
-/* i_id == -1 will unselect */
-void input_SendEventEsSelect( input_thread_t *p_input, enum es_format_category_e i_cat, int i_id )
-{
-    const char *psz_varname = GetEsVarName( i_cat );
-    if( psz_varname )
-        VarListSelect( p_input, psz_varname, INPUT_EVENT_ES, i_id );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_PROGRAM, 
+        .program = {
+            .action = VLC_INPUT_PROGRAM_SCRAMBLED,
+            .id = i_group,
+            .scrambled = b_scrambled 
+        }
+    });
+}
+
+void input_SendEventEsAdd( input_thread_t *p_input,
+                           enum es_format_category_e i_cat, int i_id,
+                           const char *psz_text )
+{
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_ES,
+        .es = {
+            .action = VLC_INPUT_ES_ADDED,
+            .cat = i_cat,
+            .id = i_id,
+            .title = psz_text
+        }
+    });
+}
+void input_SendEventEsDel( input_thread_t *p_input,
+                           enum es_format_category_e i_cat, int i_id )
+{
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_ES,
+        .es = {
+            .action = VLC_INPUT_ES_DELETED,
+            .cat = i_cat,
+            .id = i_id,
+        }
+    });
+}
+void input_SendEventEsSelect( input_thread_t *p_input,
+                              enum es_format_category_e i_cat, int i_id )
+{
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_ES,
+        .es = {
+            .action = VLC_INPUT_ES_SELECTED,
+            .cat = i_cat,
+            .id = i_id,
+        }
+    });
 }
 
 void input_SendEventTeletextAdd( input_thread_t *p_input,
                                  int i_teletext, const char *psz_text )
 {
-    VarListAdd( p_input, "teletext-es", INPUT_EVENT_TELETEXT, i_teletext, psz_text );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_TELETEXT,
+        .teletext = {
+            .action = VLC_INPUT_TELETEXT_ADDED,
+            .id = i_teletext,
+            .title = psz_text
+        }
+    });
 }
 void input_SendEventTeletextDel( input_thread_t *p_input, int i_teletext )
 {
-    VarListDel( p_input, "teletext-es", INPUT_EVENT_TELETEXT, i_teletext );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_TELETEXT,
+        .teletext = {
+            .action = VLC_INPUT_TELETEXT_DELETED,
+            .id = i_teletext,
+        }
+    });
 }
 void input_SendEventTeletextSelect( input_thread_t *p_input, int i_teletext )
 {
-    VarListSelect( p_input, "teletext-es", INPUT_EVENT_TELETEXT, i_teletext );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_TELETEXT,
+        .teletext = {
+            .action = VLC_INPUT_TELETEXT_SELECTED,
+            .id = i_teletext,
+        }
+    });
 }
 
 void input_SendEventVout( input_thread_t *p_input )
 {
-    Trigger( p_input, INPUT_EVENT_VOUT );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_VOUT
+    });
 }
 
 void input_SendEventAout( input_thread_t *p_input )
 {
-    Trigger( p_input, INPUT_EVENT_AOUT );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_AOUT
+    });
 }
 
-/*****************************************************************************
- * Event for control.c/input.c
- *****************************************************************************/
 void input_SendEventBookmark( input_thread_t *p_input )
 {
-    Trigger( p_input, INPUT_EVENT_BOOKMARK );
+    input_SendEvent( p_input, &(struct vlc_input_event) {
+        .type = INPUT_EVENT_BOOKMARK
+    });
 }
-
-/*****************************************************************************
- *
- *****************************************************************************/
-static void Trigger( input_thread_t *p_input, int i_type )
-{
-    var_SetInteger( p_input, "intf-event", i_type );
-}
-static void VarListAdd( input_thread_t *p_input,
-                        const char *psz_variable, int i_event,
-                        int i_value, const char *psz_text )
-{
-    vlc_value_t val;
-
-    val.i_int = i_value;
-
-    var_Change( p_input, psz_variable, VLC_VAR_ADDCHOICE, val, psz_text );
-
-    Trigger( p_input, i_event );
-}
-static void VarListDel( input_thread_t *p_input,
-                        const char *psz_variable, int i_event,
-                        int i_value )
-{
-    vlc_value_t val;
-
-    if( i_value >= 0 )
-    {
-        val.i_int = i_value;
-        var_Change( p_input, psz_variable, VLC_VAR_DELCHOICE, val );
-    }
-    else
-    {
-        var_Change( p_input, psz_variable, VLC_VAR_CLEARCHOICES );
-    }
-
-    Trigger( p_input, i_event );
-}
-static void VarListSelect( input_thread_t *p_input,
-                           const char *psz_variable, int i_event,
-                           int i_value )
-{
-    vlc_value_t val;
-
-    val.i_int = i_value;
-    var_Change( p_input, psz_variable, VLC_VAR_SETVALUE, val );
-
-    Trigger( p_input, i_event );
-}
-
-
diff --git a/src/input/event.h b/src/input/event.h
index 0be2fd0e22..4c9792d228 100644
--- a/src/input/event.h
+++ b/src/input/event.h
@@ -34,6 +34,7 @@ void input_SendEventPosition( input_thread_t *p_input, double f_position, vlc_ti
 void input_SendEventLength( input_thread_t *p_input, vlc_tick_t i_length );
 void input_SendEventStatistics( input_thread_t *p_input );
 void input_SendEventRate( input_thread_t *p_input, int i_rate );
+void input_SendEventCapabilities( input_thread_t *p_input, int capabilities );
 void input_SendEventAudioDelay( input_thread_t *p_input, vlc_tick_t i_delay );
 void input_SendEventSubtitleDelay( input_thread_t *p_input, vlc_tick_t i_delay );
 void input_SendEventRecord( input_thread_t *p_input, bool b_recording );
diff --git a/src/input/input_interface.h b/src/input/input_interface.h
index c89d2a7340..a2635c429a 100644
--- a/src/input/input_interface.h
+++ b/src/input/input_interface.h
@@ -50,7 +50,9 @@ void input_item_SetEpgOffline( input_item_t * );
  * @param item input item to preparse
  * @return an input thread or NULL on error
  */
-input_thread_t *input_CreatePreparser(vlc_object_t *obj, input_item_t *item)
+input_thread_t *input_CreatePreparser(vlc_object_t *obj,
+                                      input_thread_events_cb events_cb,
+                                      void *events_data, input_item_t *item)
 VLC_USED;
 
 /**
diff --git a/src/input/input_internal.c b/src/input/input_internal.c
index e6f8da85d1..9b8c1a540e 100644
--- a/src/input/input_internal.c
+++ b/src/input/input_internal.c
@@ -61,9 +61,9 @@
 static  void *Run( void * );
 static  void *Preparse( void * );
 
-static input_thread_t * Create  ( vlc_object_t *, input_item_t *,
-                                  const char *, bool, input_resource_t *,
-                                  vlc_renderer_item_t * );
+static input_thread_t * Create  ( vlc_object_t *, input_thread_events_cb, void *,
+                                  input_item_t *, const char *, bool,
+                                  input_resource_t *, vlc_renderer_item_t * );
 static  int             Init    ( input_thread_t *p_input );
 static void             End     ( input_thread_t *p_input );
 static void             MainLoop( input_thread_t *p_input, bool b_interactive );
@@ -125,11 +125,13 @@ static void input_ChangeState( input_thread_t *p_input, int i_state ); /* TODO f
  * \return a pointer to the spawned input thread
  */
 input_thread_t *input_Create( vlc_object_t *p_parent,
+                              input_thread_events_cb events_cb, void *events_data,
                               input_item_t *p_item,
                               const char *psz_log, input_resource_t *p_resource,
                               vlc_renderer_item_t *p_renderer )
 {
-    return Create( p_parent, p_item, psz_log, false, p_resource, p_renderer );
+    return Create( p_parent, events_cb, events_data, p_item, psz_log, false,
+                   p_resource, p_renderer );
 }
 
 #undef input_Read
@@ -142,7 +144,8 @@ input_thread_t *input_Create( vlc_object_t *p_parent,
  */
 int input_Read( vlc_object_t *p_parent, input_item_t *p_item )
 {
-    input_thread_t *p_input = Create( p_parent, p_item, NULL, false, NULL, NULL );
+    input_thread_t *p_input = Create( p_parent, NULL, NULL, p_item, NULL, false,
+                                      NULL, NULL );
     if( !p_input )
         return VLC_EGENERIC;
 
@@ -157,9 +160,10 @@ int input_Read( vlc_object_t *p_parent, input_item_t *p_item )
 }
 
 input_thread_t *input_CreatePreparser( vlc_object_t *parent,
-                                       input_item_t *item )
+                                       input_thread_events_cb events_cb,
+                                       void *events_data, input_item_t *item )
 {
-    return Create( parent, item, NULL, true, NULL, NULL );
+    return Create( parent, events_cb, events_data, item, NULL, true, NULL, NULL );
 }
 
 /**
@@ -300,9 +304,10 @@ input_item_t *input_GetItem( input_thread_t *p_input )
  *
  * XXX Do not forget to update vlc_input.h if you add new variables.
  *****************************************************************************/
-static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
-                               const char *psz_header, bool b_preparsing,
-                               input_resource_t *p_resource,
+static input_thread_t *Create( vlc_object_t *p_parent,
+                               input_thread_events_cb events_cb, void *events_data,
+                               input_item_t *p_item, const char *psz_header,
+                               bool b_preparsing, input_resource_t *p_resource,
                                vlc_renderer_item_t *p_renderer )
 {
     /* Allocate descriptor */
@@ -325,6 +330,8 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     p_input->obj.header = psz_header ? strdup( psz_header ) : NULL;
 
     /* Init Common fields */
+    priv->events_cb = events_cb;
+    priv->events_data = events_data;
     priv->b_preparsing = b_preparsing;
     priv->b_can_pace_control = true;
     priv->i_start = 0;
@@ -425,9 +432,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
     /* Create Object Variables for private use only */
     input_ConfigVarInit( p_input );
 
-    /* Create Objects variables for public Get and Set */
-    input_ControlVarInit( p_input );
-
     /* */
     if( !priv->b_preparsing )
     {
@@ -879,11 +883,7 @@ static void InitTitle( input_thread_t * p_input )
     priv->i_title_offset = p_master->i_title_offset;
     priv->i_seekpoint_offset = p_master->i_seekpoint_offset;
     if( priv->i_title > 0 )
-    {
-        /* Setup variables */
-        input_ControlVarNavigation( p_input );
         input_SendEventTitle( p_input, 0 );
-    }
 
     /* Global flag */
     priv->b_can_pace_control = p_master->b_can_pace_control;
@@ -1419,9 +1419,6 @@ static void End( input_thread_t * p_input )
     /* We are at the end */
     input_ChangeState( p_input, END_S );
 
-    /* Clean control variables */
-    input_ControlVarStop( p_input );
-
     /* Stop es out activity */
     es_out_SetMode( priv->p_es_out, ES_OUT_MODE_NONE );
 
@@ -2618,10 +2615,12 @@ static input_source_t *InputSourceNew( input_thread_t *p_input,
     }
 
     /* Get infos from (access_)demux */
+    int capabilites = 0;
     bool b_can_seek;
     if( demux_Control( in->p_demux, DEMUX_CAN_SEEK, &b_can_seek ) )
         b_can_seek = false;
-    var_SetBool( p_input, "can-seek", b_can_seek );
+    if( b_can_seek )
+        capabilites |= VLC_INPUT_CAPABILITIES_SEEKABLE;
 
     if( demux_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE,
                        &in->b_can_pace_control ) )
@@ -2648,9 +2647,12 @@ static input_source_t *InputSourceNew( input_thread_t *p_input,
 
     demux_Control( in->p_demux, DEMUX_CAN_PAUSE, &in->b_can_pause );
 
-    var_SetBool( p_input, "can-pause", in->b_can_pause || !in->b_can_pace_control ); /* XXX temporary because of es_out_timeshift*/
-    var_SetBool( p_input, "can-rate", !in->b_can_pace_control || in->b_can_rate_control ); /* XXX temporary because of es_out_timeshift*/
-    var_SetBool( p_input, "can-rewind", !in->b_rescale_ts && !in->b_can_pace_control && in->b_can_rate_control );
+    if( in->b_can_pause || !in->b_can_pace_control )
+        capabilites |= VLC_INPUT_CAPABILITIES_PAUSEABLE;
+    if( !in->b_can_pace_control || in->b_can_rate_control )
+        capabilites |= VLC_INPUT_CAPABILITIES_CHANGE_RATE;
+    if( !in->b_rescale_ts && !in->b_can_pace_control && in->b_can_rate_control )
+        capabilites |= VLC_INPUT_CAPABILITIES_REWINDABLE;
 
     /* Set record capabilities */
     if( demux_Control( in->p_demux, DEMUX_CAN_RECORD, &in->b_can_stream_record ) )
@@ -2658,11 +2660,14 @@ static input_source_t *InputSourceNew( input_thread_t *p_input,
 #ifdef ENABLE_SOUT
     if( !var_GetBool( p_input, "input-record-native" ) )
         in->b_can_stream_record = false;
-    var_SetBool( p_input, "can-record", true );
+    capabilites |= VLC_INPUT_CAPABILITIES_RECORDABLE;
 #else
-    var_SetBool( p_input, "can-record", in->b_can_stream_record );
+    if( in->b_can_stream_record )
+        capabilites |= VLC_INPUT_CAPABILITIES_RECORDABLE;
 #endif
 
+    input_SendEventCapabilities( p_input, capabilites );
+
     /* get attachment
      * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
     if( !input_priv(p_input)->b_preparsing )
diff --git a/src/input/input_internal.h b/src/input/input_internal.h
index 99f59790fa..cd34546976 100644
--- a/src/input/input_internal.h
+++ b/src/input/input_internal.h
@@ -103,6 +103,9 @@ typedef struct input_thread_private_t
 {
     struct input_thread_t input;
 
+    input_thread_events_cb events_cb;
+    void *events_data;
+
     /* Global properties */
     bool        b_preparsing;
     bool        b_can_pause;
@@ -269,10 +272,6 @@ void input_ExtractAttachmentAndCacheArt( input_thread_t *, const char *name );
  ***************************************************************************/
 
 /* var.c */
-void input_ControlVarInit ( input_thread_t * );
-void input_ControlVarStop( input_thread_t * );
-void input_ControlVarNavigation( input_thread_t * );
-void input_ControlVarTitle( input_thread_t *, int i_title );
 
 void input_ConfigVarInit ( input_thread_t * );
 
diff --git a/src/input/var.c b/src/input/var.c
index bd585df7b2..8c92194eb7 100644
--- a/src/input/var.c
+++ b/src/input/var.c
@@ -75,6 +75,8 @@ static int RecordCallback( vlc_object_t *p_this, char const *psz_cmd,
 static int FrameNextCallback( vlc_object_t *p_this, char const *psz_cmd,
                               vlc_value_t oldval, vlc_value_t newval,
                               void *p_data );
+static void input_LegacyVarTitle( input_thread_t *p_input, int i_title );
+static void input_LegacyVarNavigation( input_thread_t *p_input );
 
 typedef struct
 {
@@ -122,14 +124,274 @@ static const vlc_input_callback_t p_input_title_navigation_callbacks[] =
 };
 #undef CALLBACK
 
+static void Trigger( input_thread_t *p_input, int i_type )
+{
+    var_SetInteger( p_input, "intf-event", i_type );
+}
+static void VarListAdd( input_thread_t *p_input,
+                        const char *psz_variable, int i_event,
+                        int i_value, const char *psz_text )
+{
+    vlc_value_t val;
+
+    val.i_int = i_value;
+
+    var_Change( p_input, psz_variable, VLC_VAR_ADDCHOICE, val, psz_text );
+
+    Trigger( p_input, i_event );
+}
+static void VarListDel( input_thread_t *p_input,
+                        const char *psz_variable, int i_event,
+                        int i_value )
+{
+    vlc_value_t val;
+
+    if( i_value >= 0 )
+    {
+        val.i_int = i_value;
+        var_Change( p_input, psz_variable, VLC_VAR_DELCHOICE, val );
+    }
+    else
+    {
+        var_Change( p_input, psz_variable, VLC_VAR_CLEARCHOICES );
+    }
+
+    Trigger( p_input, i_event );
+}
+static void VarListSelect( input_thread_t *p_input,
+                           const char *psz_variable, int i_event,
+                           int i_value )
+{
+    vlc_value_t val;
+
+    val.i_int = i_value;
+    var_Change( p_input, psz_variable, VLC_VAR_SETVALUE, val );
+
+    Trigger( p_input, i_event );
+}
+static const char *GetEsVarName( enum es_format_category_e i_cat )
+{
+    switch( i_cat )
+    {
+    case VIDEO_ES:
+        return "video-es";
+    case AUDIO_ES:
+        return "audio-es";
+    case SPU_ES:
+        return "spu-es";
+    default:
+        return NULL;
+    }
+}
+
+void input_LegacyEvents( input_thread_t *p_input,
+                         const struct vlc_input_event *event, void *user_data )
+{
+    (void) user_data;
+    vlc_value_t val;
+
+    switch( event->type )
+    {
+        case INPUT_EVENT_STATE:
+            val.i_int = event->state;
+            var_Change( p_input, "state", VLC_VAR_SETVALUE, val );
+            break;
+        case INPUT_EVENT_DEAD:
+            break;
+        case INPUT_EVENT_RATE:
+            val.f_float = event->rate;
+            var_Change( p_input, "rate", VLC_VAR_SETVALUE, val );
+            break;
+        case INPUT_EVENT_CAPABILITIES:
+            var_SetBool( p_input, "can-seek",
+                         event->capabilities | VLC_INPUT_CAPABILITIES_SEEKABLE );
+            var_SetBool( p_input, "can-pause",
+                         event->capabilities | VLC_INPUT_CAPABILITIES_PAUSEABLE );
+            var_SetBool( p_input, "can-rate",
+                         event->capabilities | VLC_INPUT_CAPABILITIES_CHANGE_RATE );
+            var_SetBool( p_input, "can-rewind",
+                         event->capabilities | VLC_INPUT_CAPABILITIES_REWINDABLE );
+            var_SetBool( p_input, "can-record",
+                         event->capabilities | VLC_INPUT_CAPABILITIES_RECORDABLE );
+            break;
+        case INPUT_EVENT_POSITION:
+            val.f_float = event->position.percentage;
+            var_Change( p_input, "position", VLC_VAR_SETVALUE, val );
+            val.i_int = event->position.ms;
+            var_Change( p_input, "time", VLC_VAR_SETVALUE, val );
+            break;
+        case INPUT_EVENT_LENGTH:
+            /* FIXME ugly + what about meta change event ? */
+            if( var_GetInteger( p_input, "length" ) == event->length )
+                return;
+            val.i_int = event->length;
+            var_Change( p_input, "length", VLC_VAR_SETVALUE, val );
+            break;
+        case INPUT_EVENT_TITLE:
+            val.i_int = event->title;
+            var_Change( p_input, "title", VLC_VAR_SETVALUE, val );
+            input_LegacyVarNavigation( p_input );
+            input_LegacyVarTitle( p_input, event->title );
+            break;
+        case INPUT_EVENT_CHAPTER:
+            /* "chapter" */
+            val.i_int = event->chapter.seekpoint;
+            var_Change( p_input, "chapter", VLC_VAR_SETVALUE, val );
+
+            /* "title %2u" */
+            char psz_title[sizeof ("title ") + 3 * sizeof (int)];
+            sprintf( psz_title, "title %2u", event->chapter.title );
+            var_Change( p_input, psz_title, VLC_VAR_SETVALUE, val );
+            break;
+        case INPUT_EVENT_PROGRAM:
+            switch (event->program.action)
+            {
+                case VLC_INPUT_PROGRAM_ADDED:
+                    VarListAdd( p_input, "program", INPUT_EVENT_PROGRAM,
+                                event->program.id, event->program.title );
+                    break;
+                case VLC_INPUT_PROGRAM_DELETED:
+                    VarListDel( p_input, "program", INPUT_EVENT_PROGRAM,
+                                event->program.id );
+                    break;
+                case VLC_INPUT_PROGRAM_SELECTED:
+                    VarListSelect( p_input, "program", INPUT_EVENT_PROGRAM,
+                                   event->program.id );
+                    break;
+                case VLC_INPUT_PROGRAM_SCRAMBLED:
+                    if( var_GetInteger( p_input, "program" ) != event->program.id  )
+                        return;
+                    var_SetBool( p_input, "program-scrambled", event->program.scrambled );
+                    break;
+            }
+            break;
+        case INPUT_EVENT_ES:
+            switch (event->es.action)
+            {
+                case VLC_INPUT_ES_ADDED:
+                {
+                    const char *varname = GetEsVarName( event->es.cat );
+                    if( varname )
+                        VarListAdd( p_input, varname, INPUT_EVENT_ES,
+                                    event->es.id, event->es.title );
+                    break;
+                }
+                case VLC_INPUT_ES_DELETED:
+                {
+                    const char *varname = GetEsVarName( event->es.cat );
+                    if( varname )
+                        VarListDel( p_input, varname, INPUT_EVENT_ES,
+                                    event->es.id );
+                    break;
+                }
+                case VLC_INPUT_ES_SELECTED:
+                {
+                    const char *varname = GetEsVarName( event->es.cat );
+                    if( varname )
+                        VarListSelect( p_input, varname, INPUT_EVENT_ES,
+                                       event->es.id );
+                    break;
+                }
+            }
+            break;
+        case INPUT_EVENT_TELETEXT:
+            switch (event->teletext.action)
+            {
+                case VLC_INPUT_TELETEXT_ADDED:
+                    VarListAdd( p_input, "teletext-es", INPUT_EVENT_TELETEXT,
+                                event->teletext.id, event->teletext.title );
+                    break;
+                case VLC_INPUT_TELETEXT_DELETED:
+                    VarListDel( p_input, "teletext-es", INPUT_EVENT_TELETEXT,
+                                event->teletext.id );
+                    break;
+                case VLC_INPUT_TELETEXT_SELECTED:
+                    VarListSelect( p_input, "teletext-es", INPUT_EVENT_TELETEXT,
+                                   event->teletext.id );
+                    break;
+            }
+            break;
+        case INPUT_EVENT_RECORD:
+            val.b_bool = event->record;
+            var_Change( p_input, "record", VLC_VAR_SETVALUE, val );
+            break;
+        case INPUT_EVENT_ITEM_META:
+            break;
+        case INPUT_EVENT_ITEM_INFO:
+            break;
+        case INPUT_EVENT_ITEM_EPG:
+            break;
+        case INPUT_EVENT_STATISTICS:
+            break;
+        case INPUT_EVENT_SIGNAL:
+            val.f_float = event->signal.quality;
+            var_Change( p_input, "signal-quality", VLC_VAR_SETVALUE, val );
+            val.f_float = event->signal.strength;
+            var_Change( p_input, "signal-strength", VLC_VAR_SETVALUE, val );
+            break;
+        case INPUT_EVENT_AUDIO_DELAY:
+            val.i_int = event->audio_delay;
+            var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, val );
+            break;
+        case INPUT_EVENT_SUBTITLE_DELAY:
+            val.i_int = event->subtitle_delay;
+            var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, val );
+            break;
+        case INPUT_EVENT_BOOKMARK:
+            break;
+        case INPUT_EVENT_CACHE:
+            val.f_float = event->cache;
+            var_Change( p_input, "cache", VLC_VAR_SETVALUE, val );
+            break;
+        case INPUT_EVENT_AOUT:
+            break;
+        case INPUT_EVENT_VOUT:
+            break;
+    }
+    Trigger( p_input, event->type );
+}
+
 /*****************************************************************************
- * input_ControlVarInit:
- *  Create all control object variables with their callbacks
+ * input_LegacyVarInit:
+ * Create all control object variables with their callbacks
  *****************************************************************************/
-void input_ControlVarInit ( input_thread_t *p_input )
+void input_LegacyVarInit ( input_thread_t *p_input )
 {
     vlc_value_t val;
 
+    var_Create( p_input, "can-seek", VLC_VAR_BOOL );
+    var_SetBool( p_input, "can-seek", true ); /* Fixed later*/
+
+    var_Create( p_input, "can-pause", VLC_VAR_BOOL );
+    var_SetBool( p_input, "can-pause", true ); /* Fixed later*/
+
+    var_Create( p_input, "can-rate", VLC_VAR_BOOL );
+    var_SetBool( p_input, "can-rate", false );
+
+    var_Create( p_input, "can-rewind", VLC_VAR_BOOL );
+    var_SetBool( p_input, "can-rewind", false );
+
+    var_Create( p_input, "can-record", VLC_VAR_BOOL );
+    var_SetBool( p_input, "can-record", false ); /* Fixed later*/
+
+    var_Create( p_input, "record", VLC_VAR_BOOL );
+    var_SetBool( p_input, "record", false );
+
+    var_Create( p_input, "teletext-es", VLC_VAR_INTEGER );
+    var_SetInteger( p_input, "teletext-es", -1 );
+
+    var_Create( p_input, "cache", VLC_VAR_FLOAT );
+    var_SetFloat( p_input, "cache", 0.0 );
+
+    var_Create( p_input, "signal-quality", VLC_VAR_FLOAT );
+    var_SetFloat( p_input, "signal-quality", -1 );
+
+    var_Create( p_input, "signal-strength", VLC_VAR_FLOAT );
+    var_SetFloat( p_input, "signal-strength", -1 );
+
+    var_Create( p_input, "program-scrambled", VLC_VAR_BOOL );
+    var_SetBool( p_input, "program-scrambled", false );
+
     /* State */
     var_Create( p_input, "state", VLC_VAR_INTEGER );
     val.i_int = input_priv(p_input)->i_state;
@@ -214,9 +476,9 @@ void input_ControlVarInit ( input_thread_t *p_input )
 }
 
 /*****************************************************************************
- * input_ControlVarStop:
+ * input_LegacyVarStop:
  *****************************************************************************/
-void input_ControlVarStop( input_thread_t *p_input )
+void input_LegacyVarStop( input_thread_t *p_input )
 {
     if( !input_priv(p_input)->b_preparsing )
         InputDelCallbacks( p_input, p_input_callbacks );
@@ -241,10 +503,10 @@ void input_ControlVarStop( input_thread_t *p_input )
 }
 
 /*****************************************************************************
- * input_ControlVarNavigation:
+ * input_LegacyVarNavigation:
  *  Create all remaining control object variables
  *****************************************************************************/
-void input_ControlVarNavigation( input_thread_t *p_input )
+static void input_LegacyVarNavigation( input_thread_t *p_input )
 {
     /* Create more command variables */
     if( input_priv(p_input)->i_title > 1 )
@@ -352,10 +614,10 @@ void input_ControlVarNavigation( input_thread_t *p_input )
 }
 
 /*****************************************************************************
- * input_ControlVarTitle:
+ * input_LegacyVarTitle:
  *  Create all variables for a title
  *****************************************************************************/
-void input_ControlVarTitle( input_thread_t *p_input, int i_title )
+static void input_LegacyVarTitle( input_thread_t *p_input, int i_title )
 {
     const input_title_t *t = input_priv(p_input)->title[i_title];
     vlc_value_t text;
@@ -468,39 +730,6 @@ void input_ConfigVarInit ( input_thread_t *p_input )
                     VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
     }
 
-    var_Create( p_input, "can-seek", VLC_VAR_BOOL );
-    var_SetBool( p_input, "can-seek", true ); /* Fixed later*/
-
-    var_Create( p_input, "can-pause", VLC_VAR_BOOL );
-    var_SetBool( p_input, "can-pause", true ); /* Fixed later*/
-
-    var_Create( p_input, "can-rate", VLC_VAR_BOOL );
-    var_SetBool( p_input, "can-rate", false );
-
-    var_Create( p_input, "can-rewind", VLC_VAR_BOOL );
-    var_SetBool( p_input, "can-rewind", false );
-
-    var_Create( p_input, "can-record", VLC_VAR_BOOL );
-    var_SetBool( p_input, "can-record", false ); /* Fixed later*/
-
-    var_Create( p_input, "record", VLC_VAR_BOOL );
-    var_SetBool( p_input, "record", false );
-
-    var_Create( p_input, "teletext-es", VLC_VAR_INTEGER );
-    var_SetInteger( p_input, "teletext-es", -1 );
-
-    var_Create( p_input, "signal-quality", VLC_VAR_FLOAT );
-    var_SetFloat( p_input, "signal-quality", -1 );
-
-    var_Create( p_input, "signal-strength", VLC_VAR_FLOAT );
-    var_SetFloat( p_input, "signal-strength", -1 );
-
-    var_Create( p_input, "program-scrambled", VLC_VAR_BOOL );
-    var_SetBool( p_input, "program-scrambled", false );
-
-    var_Create( p_input, "cache", VLC_VAR_FLOAT );
-    var_SetFloat( p_input, "cache", 0.0 );
-
     /* */
     var_Create( p_input, "input-record-native", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
 
diff --git a/src/input/vlm.c b/src/input/vlm.c
index 792f8facf9..14bb65e904 100644
--- a/src/input/vlm.c
+++ b/src/input/vlm.c
@@ -64,32 +64,37 @@ typedef struct preparse_data_t
     bool b_mux;
 } preparse_data_t;
 
-static int InputEventPreparse( vlc_object_t *p_this, char const *psz_cmd,
-                               vlc_value_t oldval, vlc_value_t newval, void *p_data )
+static void InputEventPreparse( input_thread_t *p_input,
+                                const struct vlc_input_event *p_event,
+                                void *p_user_data )
 {
-    VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
-    preparse_data_t *p_pre = p_data;
+    (void) p_input;
+    preparse_data_t *p_pre = p_user_data;
 
-    if( newval.i_int == INPUT_EVENT_DEAD ||
-        ( p_pre->b_mux && newval.i_int == INPUT_EVENT_ITEM_META ) )
-        vlc_sem_post( p_pre->p_sem );
-
-    return VLC_SUCCESS;
+    switch( p_event->type )
+    {
+        case INPUT_EVENT_DEAD:
+            vlc_sem_post( p_pre->p_sem );
+            break;
+        case INPUT_EVENT_ITEM_META:
+            if( p_pre->b_mux )
+                vlc_sem_post( p_pre->p_sem );
+            break;
+        default:
+            break;
+    }
 }
 
-static int InputEvent( vlc_object_t *p_this, char const *psz_cmd,
-                       vlc_value_t oldval, vlc_value_t newval,
-                       void *p_data )
+static void InputEvent( input_thread_t *p_input,
+                        const struct vlc_input_event *p_event,
+                        void *p_user_data )
 {
-    VLC_UNUSED(psz_cmd);
-    VLC_UNUSED(oldval);
-    input_thread_t *p_input = (input_thread_t *)p_this;
     vlm_t *p_vlm = libvlc_priv( p_input->obj.libvlc )->p_vlm;
     assert( p_vlm );
-    vlm_media_sys_t *p_media = p_data;
+    vlm_media_sys_t *p_media = p_user_data;
     const char *psz_instance_name = NULL;
 
-    if( newval.i_int == INPUT_EVENT_STATE )
+    if( p_event->type == INPUT_EVENT_STATE )
     {
         for( int i = 0; i < p_media->i_instance; i++ )
         {
@@ -99,14 +104,15 @@ static int InputEvent( vlc_object_t *p_this, char const *psz_cmd,
                 break;
             }
         }
-        vlm_SendEventMediaInstanceState( p_vlm, p_media->cfg.id, p_media->cfg.psz_name, psz_instance_name, var_GetInteger( p_input, "state" ) );
+        vlm_SendEventMediaInstanceState( p_vlm, p_media->cfg.id,
+            p_media->cfg.psz_name, psz_instance_name,
+            p_event->state );
 
         vlc_mutex_lock( &p_vlm->lock_manage );
         p_vlm->input_state_changed = true;
         vlc_cond_signal( &p_vlm->wait_manage );
         vlc_mutex_unlock( &p_vlm->lock_manage );
     }
-    return VLC_SUCCESS;
 }
 
 static vlc_mutex_t vlm_mutex = VLC_STATIC_MUTEX;
@@ -623,17 +629,14 @@ static int vlm_OnMediaUpdate( vlm_t *p_vlm, vlm_media_sys_t *p_media )
             sout_description_data_t data;
             TAB_INIT(data.i_es, data.es);
 
-            p_input = input_Create( p_vlm->p_vod, p_media->vod.p_item, psz_header, NULL, NULL );
+            vlc_sem_t sem_preparse;
+            vlc_sem_init( &sem_preparse, 0 );
+            preparse_data_t preparse = { .p_sem = &sem_preparse,
+                                .b_mux = (p_cfg->vod.psz_mux != NULL) };
+            p_input = input_Create( p_vlm->p_vod, InputEventPreparse, &preparse,
+                                    p_media->vod.p_item, psz_header, NULL, NULL );
             if( p_input )
             {
-                vlc_sem_t sem_preparse;
-                vlc_sem_init( &sem_preparse, 0 );
-
-                preparse_data_t preparse = { .p_sem = &sem_preparse,
-                                    .b_mux = (p_cfg->vod.psz_mux != NULL) };
-                var_AddCallback( p_input, "intf-event", InputEventPreparse,
-                                 &preparse );
-
                 data.sem = &sem_preparse;
                 var_Create( p_input, "sout-description-data", VLC_VAR_ADDRESS );
                 var_SetAddress( p_input, "sout-description-data", &data );
@@ -641,13 +644,10 @@ static int vlm_OnMediaUpdate( vlm_t *p_vlm, vlm_media_sys_t *p_media )
                 if( !input_Start( p_input ) )
                     vlc_sem_wait( &sem_preparse );
 
-                var_DelCallback( p_input, "intf-event", InputEventPreparse,
-                                 &preparse );
-
                 input_Stop( p_input );
                 input_Close( p_input );
-                vlc_sem_destroy( &sem_preparse );
             }
+            vlc_sem_destroy( &sem_preparse );
             free( psz_header );
 
             /* XXX: Don't do it that way, but properly use a new input item ref. */
@@ -995,17 +995,14 @@ static int vlm_ControlMediaInstanceStart( vlm_t *p_vlm, int64_t id, const char *
 
     if( asprintf( &psz_log, _("Media: %s"), p_media->cfg.psz_name ) != -1 )
     {
-        p_instance->p_input = input_Create( p_instance->p_parent,
+        p_instance->p_input = input_Create( p_instance->p_parent, InputEvent, p_media,
                                             p_instance->p_item, psz_log,
                                             p_instance->p_input_resource,
                                             NULL );
         if( p_instance->p_input )
         {
-            var_AddCallback( p_instance->p_input, "intf-event", InputEvent, p_media );
-
             if( input_Start( p_instance->p_input ) != VLC_SUCCESS )
             {
-                var_DelCallback( p_instance->p_input, "intf-event", InputEvent, p_media );
                 input_Close( p_instance->p_input );
                 p_instance->p_input = NULL;
             }
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 4c0145d98b..ec43e57124 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -208,6 +208,9 @@ input_Stop
 input_vaControl
 input_SetTime
 input_SetPosition
+input_LegacyVarInit
+input_LegacyVarStop
+input_LegacyEvents
 vlc_readdir_helper_init
 vlc_readdir_helper_finish
 vlc_readdir_helper_additem
diff --git a/src/playlist/thread.c b/src/playlist/thread.c
index ef96d92d3a..0aa539baf1 100644
--- a/src/playlist/thread.c
+++ b/src/playlist/thread.c
@@ -35,6 +35,7 @@
 #include <vlc_rand.h>
 #include <vlc_renderer_discovery.h>
 #include "playlist_internal.h"
+#include "../input/input_internal.h"
 
 /*****************************************************************************
  * Local prototypes
@@ -214,20 +215,23 @@ static bool PlayItem( playlist_t *p_playlist, playlist_item_t *p_item )
 
     libvlc_MetadataCancel( p_playlist->obj.libvlc, p_item );
 
-    input_thread_t *p_input_thread = input_Create( p_playlist, p_input, NULL,
+    input_thread_t *p_input_thread = input_Create( p_playlist,
+                                                   input_LegacyEvents, NULL,
+                                                   p_input, NULL,
                                                    p_sys->p_input_resource,
                                                    p_renderer );
     if( p_renderer )
         vlc_renderer_item_release( p_renderer );
     if( likely(p_input_thread != NULL) )
     {
+        input_LegacyVarInit( p_input_thread );
         var_AddCallback( p_input_thread, "intf-event",
                          InputEvent, p_playlist );
-
         if( input_Start( p_input_thread ) )
         {
             var_DelCallback( p_input_thread, "intf-event",
                              InputEvent, p_playlist );
+            input_LegacyVarStop( p_input_thread );
             vlc_object_release( p_input_thread );
             p_input_thread = NULL;
         }
@@ -452,7 +456,7 @@ static void LoopInput( playlist_t *p_playlist )
     if( !var_InheritBool( p_input, "sout-keep" ) )
         input_resource_TerminateSout( p_sys->p_input_resource );
     var_DelCallback( p_input, "intf-event", InputEvent, p_playlist );
-
+    input_LegacyVarStop( p_input );
     input_Close( p_input );
     PL_LOCK;
 }
diff --git a/src/preparser/preparser.c b/src/preparser/preparser.c
index 4331aae441..09ac510345 100644
--- a/src/preparser/preparser.c
+++ b/src/preparser/preparser.c
@@ -39,33 +39,31 @@ struct input_preparser_t
     atomic_bool deactivated;
 };
 
-static int InputEvent( vlc_object_t* obj, const char* varname,
-    vlc_value_t old, vlc_value_t cur, void* worker )
+static void InputEvent( input_thread_t *input,
+                        const struct vlc_input_event *event,
+                        void *worker )
 {
-    VLC_UNUSED( obj ); VLC_UNUSED( varname ); VLC_UNUSED( old );
+    VLC_UNUSED( input );
 
-    if( cur.i_int == INPUT_EVENT_DEAD )
+    if( event->type == INPUT_EVENT_DEAD )
         background_worker_RequestProbe( worker );
-
-    return VLC_SUCCESS;
 }
 
 static int PreparserOpenInput( void* preparser_, void* item_, void** out )
 {
     input_preparser_t* preparser = preparser_;
 
-    input_thread_t* input = input_CreatePreparser( preparser->owner, item_ );
+    input_thread_t* input = input_CreatePreparser( preparser->owner, InputEvent,
+                                                   preparser->worker, item_ );
     if( !input )
     {
         input_item_SignalPreparseEnded( item_, ITEM_PREPARSE_FAILED );
         return VLC_EGENERIC;
     }
 
-    var_AddCallback( input, "intf-event", InputEvent, preparser->worker );
     if( input_Start( input ) )
     {
         input_Close( input );
-        var_DelCallback( input, "intf-event", InputEvent, preparser->worker );
         input_item_SignalPreparseEnded( item_, ITEM_PREPARSE_FAILED );
         return VLC_EGENERIC;
     }
@@ -87,8 +85,6 @@ static void PreparserCloseInput( void* preparser_, void* input_ )
     input_thread_t* input = input_;
     input_item_t* item = input_priv(input)->p_item;
 
-    var_DelCallback( input, "intf-event", InputEvent, preparser->worker );
-
     int status;
     switch( input_GetState( input ) )
     {
-- 
2.18.0



More information about the vlc-devel mailing list