[vlc-devel] [PATCH] input: Don't probe the stream when controlling a demux_Filter
Hugo Beauzée-Luyssen
hugo at beauzee.fr
Wed Jan 10 18:06:31 CET 2018
When a stream filter is active, attempting to read any file which
demux doesn't implement DEMUX_CAN_PAUSE, DEMUX_CAN_CONTROL_PACE,
DEMUX_GET_PTS_DELAY or DEMUX_SET_PAUSE_STATE will cause undefined
behavior when accessing demux_t::s
---
src/input/demux.c | 139 ++++++++++++++++++++++++++++++------------------------
1 file changed, 77 insertions(+), 62 deletions(-)
diff --git a/src/input/demux.c b/src/input/demux.c
index 18b64b5f31..e594014ac0 100644
--- a/src/input/demux.c
+++ b/src/input/demux.c
@@ -155,6 +155,7 @@ typedef struct demux_priv_t
{
demux_t demux;
void (*destroy)(demux_t *);
+ int (*control)( demux_t *, int, va_list );
} demux_priv_t;
static void demux_DestroyDemux(demux_t *demux)
@@ -191,6 +192,80 @@ static int demux_Probe(void *func, va_list ap)
return probe(VLC_OBJECT(demux));
}
+static int demux_ControlInternal( demux_t *demux, int query, ... )
+{
+ int ret;
+ va_list ap;
+
+ va_start( ap, query );
+ ret = demux->pf_control( demux, query, ap );
+ va_end( ap );
+ return ret;
+}
+
+int demux_vaControl( demux_t *demux, int query, va_list args )
+{
+ demux_priv_t *priv = (demux_priv_t *)demux;
+ return priv->control( demux, query, args );
+}
+
+static int demux_vaControlInner( demux_t *demux, int query, va_list args )
+{
+ if( demux->s != NULL )
+ switch( query )
+ {
+ /* Legacy fallback for missing getters in synchronous demuxers */
+ case DEMUX_CAN_PAUSE:
+ case DEMUX_CAN_CONTROL_PACE:
+ case DEMUX_GET_PTS_DELAY:
+ {
+ int ret;
+ va_list ap;
+
+ va_copy( ap, args );
+ ret = demux->pf_control( demux, query, args );
+ if( ret != VLC_SUCCESS )
+ ret = vlc_stream_vaControl( demux->s, query, ap );
+ va_end( ap );
+ return ret;
+ }
+
+ /* Some demuxers need to control pause directly (e.g. adaptive),
+ * but many legacy demuxers do not understand pause at all.
+ * If DEMUX_CAN_PAUSE is not implemented, bypass the demuxer and
+ * byte stream. If DEMUX_CAN_PAUSE is implemented and pause is
+ * supported, pause the demuxer normally. Else, something went very
+ * wrong.
+ *
+ * Note that this requires asynchronous/threaded demuxers to
+ * always return VLC_SUCCESS for DEMUX_CAN_PAUSE, so that they are
+ * never bypassed. Otherwise, we would reenter demux->s callbacks
+ * and break thread safety. At the time of writing, asynchronous or
+ * threaded *non-access* demuxers do not exist and are not fully
+ * supported by the input thread, so this is theoretical. */
+ case DEMUX_SET_PAUSE_STATE:
+ {
+ bool can_pause;
+
+ if( demux_ControlInternal( demux, DEMUX_CAN_PAUSE,
+ &can_pause ) )
+ return vlc_stream_vaControl( demux->s, query, args );
+
+ /* The caller shall not pause if pause is unsupported. */
+ assert( can_pause );
+ break;
+ }
+ }
+
+ return demux->pf_control( demux, query, args );
+}
+
+static int demux_vaControlFilter( demux_t *demux, int query, va_list args )
+{
+ // Do not probe the stream in the context of a demux filter.
+ return demux->pf_control( demux, query, args );
+}
+
/*****************************************************************************
* demux_NewAdvanced:
* if s is NULL then load a access_demux
@@ -245,6 +320,7 @@ demux_t *demux_NewAdvanced( vlc_object_t *p_obj, input_thread_t *p_parent_input,
p_demux->p_sys = NULL;
p_demux->info.i_update = 0;
priv->destroy = s ? demux_DestroyDemux : demux_DestroyAccessDemux;
+ priv->control = demux_vaControlInner;
if( s != NULL )
{
@@ -303,68 +379,6 @@ void demux_Delete( demux_t *p_demux )
#define static_control_match(foo) \
static_assert((unsigned) DEMUX_##foo == STREAM_##foo, "Mismatch")
-static int demux_ControlInternal( demux_t *demux, int query, ... )
-{
- int ret;
- va_list ap;
-
- va_start( ap, query );
- ret = demux->pf_control( demux, query, ap );
- va_end( ap );
- return ret;
-}
-
-int demux_vaControl( demux_t *demux, int query, va_list args )
-{
- if( demux->s != NULL )
- switch( query )
- {
- /* Legacy fallback for missing getters in synchronous demuxers */
- case DEMUX_CAN_PAUSE:
- case DEMUX_CAN_CONTROL_PACE:
- case DEMUX_GET_PTS_DELAY:
- {
- int ret;
- va_list ap;
-
- va_copy( ap, args );
- ret = demux->pf_control( demux, query, args );
- if( ret != VLC_SUCCESS )
- ret = vlc_stream_vaControl( demux->s, query, ap );
- va_end( ap );
- return ret;
- }
-
- /* Some demuxers need to control pause directly (e.g. adaptive),
- * but many legacy demuxers do not understand pause at all.
- * If DEMUX_CAN_PAUSE is not implemented, bypass the demuxer and
- * byte stream. If DEMUX_CAN_PAUSE is implemented and pause is
- * supported, pause the demuxer normally. Else, something went very
- * wrong.
- *
- * Note that this requires asynchronous/threaded demuxers to
- * always return VLC_SUCCESS for DEMUX_CAN_PAUSE, so that they are
- * never bypassed. Otherwise, we would reenter demux->s callbacks
- * and break thread safety. At the time of writing, asynchronous or
- * threaded *non-access* demuxers do not exist and are not fully
- * supported by the input thread, so this is theoretical. */
- case DEMUX_SET_PAUSE_STATE:
- {
- bool can_pause;
-
- if( demux_ControlInternal( demux, DEMUX_CAN_PAUSE,
- &can_pause ) )
- return vlc_stream_vaControl( demux->s, query, args );
-
- /* The caller shall not pause if pause is unsupported. */
- assert( can_pause );
- break;
- }
- }
-
- return demux->pf_control( demux, query, args );
-}
-
/*****************************************************************************
* demux_vaControlHelper:
*****************************************************************************/
@@ -593,6 +607,7 @@ static demux_t *demux_FilterNew( demux_t *p_next, const char *p_name )
p_demux->psz_filepath = NULL;
p_demux->out = NULL;
priv->destroy = demux_DestroyDemuxFilter;
+ priv->control = demux_vaControlFilter;
p_demux->p_module =
module_need( p_demux, "demux_filter", p_name, p_name != NULL );
--
2.11.0
More information about the vlc-devel
mailing list