[vlc-commits] stream_extractor: split joint capability into two
Filip Roséen
git at videolan.org
Tue Feb 21 15:55:38 CET 2017
vlc | branch: master | Filip Roséen <filip at atch.se> | Thu Feb 16 22:07:48 2017 +0100| [17eb062e87cd15bf7baff4ecf861e0cdfed22fa8] | committer: Jean-Baptiste Kempf
stream_extractor: split joint capability into two
These changes splits the functionality for a stream-extractor into two
different objects, one being a stream_extractor_t (used to extract
data for an entity within a stream based on an identifier), and the
other, stream_directory_t, is to list entities within a stream.
Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=17eb062e87cd15bf7baff4ecf861e0cdfed22fa8
---
include/vlc_stream_extractor.h | 126 +++++++++---------
src/input/input.c | 2 +-
src/input/stream_extractor.c | 286 +++++++++++++++++++++++++++--------------
src/libvlccore.sym | 1 +
4 files changed, 261 insertions(+), 154 deletions(-)
diff --git a/include/vlc_stream_extractor.h b/include/vlc_stream_extractor.h
index 36bbd13..b1782dc 100644
--- a/include/vlc_stream_extractor.h
+++ b/include/vlc_stream_extractor.h
@@ -35,101 +35,109 @@ extern "C" {
*
* A \em stream-extractor can do one of two things;
*
- * - either it lists the logical entries within a stream, or;
- * - it extracts the data associated with one of those entries based
- * on a unique identifier.
+ * - lists the logical entries within a stream:
+ * - type = \ref stream_directory_t
+ * - capability = "stream_directory"
+ *
+ * - extract data associated with one specific entry within a stream:
+ * - type = \ref stream_extractor_t
+ * - capability = "stream_extractor"
*
* @{
*
**/
-struct stream_extractor_t {
+
+typedef struct stream_extractor_t {
VLC_COMMON_MEMBERS
- union {
- /**
- * Callbacks for entity extraction
- *
- * The following callbacks shall be populated if the stream_extractor is
- * used to extract a specific entity from the source-stream. Each
- * callback shall behave as those, with the same name, specified in \ref
- * stream_t.
- *
- **/
- struct {
- ssize_t (*pf_read)(struct stream_extractor_t *, void *buf, size_t len);
- block_t* (*pf_block)(struct stream_extractor_t *, bool *eof);
- int (*pf_seek)(struct stream_extractor_t *, uint64_t);
- int (*pf_control)(struct stream_extractor_t *, int i_query, va_list);
-
- } stream;
-
- /**
- * Callbacks for stream directory listing
- *
- * These callbacks are used when a stream is to be treated as a
- * directory, it shall behave as those, with the same name, specified
- * in \ref stream_t.
- *
- **/
- struct {
- int (*pf_readdir)(struct stream_extractor_t *, input_item_node_t *);
-
- } directory;
-
- };
-
- void* p_sys; /**< Private data pointer */
- stream_t* source; /**< The source stream */
- char* identifier; /**< name of requested entity to extract, or NULL
- ** when requested to list directories */
-};
-
-typedef struct stream_extractor_t stream_extractor_t;
+ /**
+ * \name Callbacks for entity extraction
+ *
+ * The following members shall be populated as specified by the
+ * documentation associated with \ref stream_t for the equivalent name.
+ *
+ * @{
+ **/
+ ssize_t (*pf_read)(struct stream_extractor_t*, void* buf, size_t len);
+ block_t* (*pf_block)(struct stream_extractor_t*, bool* eof);
+ int (*pf_seek)(struct stream_extractor_t*, uint64_t);
+ int (*pf_control)(struct stream_extractor_t*, int request, va_list args);
+ /** @} */
+
+ char const* identifier; /**< the name of the entity to be extracted */
+ stream_t* source; /**< the source stream to be consumed */
+ void* p_sys; /**< private opaque handle to be used by the module */
+
+} stream_extractor_t;
+
+typedef struct stream_directory_t {
+ VLC_COMMON_MEMBERS;
+
+ /**
+ * \name Callbacks for stream directories
+ *
+ * The following members shall be populated as specified by the
+ * documentation associated with \ref stream_t for the equivalent name.
+ *
+ * @{
+ **/
+ int (*pf_readdir)(struct stream_directory_t*, input_item_node_t* );
+ /** @} */
+
+ stream_t* source; /**< the source stream to be consumed */
+ void* p_sys; /**< private opaque handle to be used by the module */
+
+} stream_directory_t;
/**
* Create a relative MRL for the associated entity
*
- * This function shall be used by stream_extractor_t's in order to
- * generate a MRL that refers to an entity within the stream. Normally
+ * This function shall be used by stream_directory_t's in order to
+ * generate an MRL that refers to an entity within the stream. Normally
* this function will only be invoked within `pf_readdir` in order to
* get the virtual path of the listed items.
*
* \warning the returned value is to be freed by the caller
*
- * \param extractor the stream_extractor_t in which the entity belongs
+ * \param extractor the stream_directory_t for which the entity belongs
* \param subentry the name of the entity in question
*
* \return a pointer to the resulting MRL on success, NULL on failure
**/
-VLC_API char* vlc_stream_extractor_CreateMRL( stream_extractor_t*,
+VLC_API char* vlc_stream_extractor_CreateMRL( stream_directory_t*,
char const* subentry );
/**
- * Construct a new stream_extractor-based stream
- *
- * This function is used to attach a stream extractor to an already
- * existing stream.
+ * \name Attach a stream-extractor to the passed stream
*
- * If \p identifier is `NULL`, `*stream` is guaranteed to refer to a
- * directory, otherwise \p identifier denotes the specific subentry
- * that one would like to access within the stream.
- *
- * If \p identifier is not NULL, `*stream` will refer to data for the
- * entity in question.
+ * These functions are used to attach a stream extractor to an already existing
+ * stream. As hinted by their names, \ref vlc_stream_extractor_Attach will
+ * attach an \em entity-extractor, whereas \ref vlc_stream_directory_Attach
+ * will attach a \em stream-directory.
*
* \param[out] stream a pointer-to-pointer to stream, `*stream` will
* refer to the attached stream on success, and left
* untouched on failure.
- * \param identifier NULL or a c-style string referring to the desired entity
+ * \param identifier (if present) NULL or a c-style string referring to the
+ * desired entity
* \param module_name NULL or an explicit stream-extractor module name
*
* \return VLC_SUCCESS if a stream-extractor was successfully
* attached, an error-code on failure.
+ *
+ * @{
**/
VLC_API int vlc_stream_extractor_Attach( stream_t** source,
char const* identifier,
char const* module_name );
+
+VLC_API int vlc_stream_directory_Attach( stream_t** source,
+ char const* module_name );
+/**
+ * @}
+ */
+
/**
* @}
*/
diff --git a/src/input/input.c b/src/input/input.c
index 08a8abb..5a28c8a 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -2299,7 +2299,7 @@ InputStreamHandleAnchor( input_source_t *source, stream_t **stream,
if( remaining == 0 )
{
- if( vlc_stream_extractor_Attach( stream, NULL, NULL ) )
+ if( vlc_stream_directory_Attach( stream, NULL ) )
msg_Dbg( source, "attach of directory extractor failed" );
return VLC_SUCCESS;
diff --git a/src/input/stream_extractor.c b/src/input/stream_extractor.c
index 573ba9d..68d76f1 100644
--- a/src/input/stream_extractor.c
+++ b/src/input/stream_extractor.c
@@ -38,7 +38,7 @@
#include "mrl_helpers.h"
/**
- * \defgroup stream_extractor_Private Stream Extractor Private
+ * \defgroup stream_extractor_Internals Stream Extractor Internals
* \ingroup stream_extractor
* \internal
* @{
@@ -46,40 +46,95 @@
**/
struct stream_extractor_private {
- stream_extractor_t public;
- stream_t* stream;
- module_t* module;
-
- vlc_object_t* owner;
+ union {
+ stream_extractor_t extractor;
+ stream_directory_t directory;
+ };
+
+ /**
+ * Callback to handle initialization
+ *
+ * \ref pf_init will be called after successful module probing to initialize
+ * the relevant members of the underlying stream-extractor object, as well
+ * as the wrapping stream.
+ **/
+ int (*pf_init)( struct stream_extractor_private*, stream_t* );
+
+ /**
+ * Callback to handle clean-up
+ *
+ * \ref pf_clean, unless NULL, will be called when the stream-extractor is to
+ * be destroyed, and shall be used to clean-up resources (acquired during
+ * initialization, see \ref pf_init).
+ */
+ void (*pf_clean)( struct stream_extractor_private* );
+
+ stream_t* wrapper; /**< the wrapping \ref stream_t used to access the
+ underlying stream-extractor */
+
+ stream_t* source; /**< the source stream consumed by the stream-extractor */
+ module_t* module; /**< the stream-extractor module */
+
+ vlc_object_t* object; /**< the underlying stream-extractor object */
};
/**
- * Release the private data associated with a stream-extractor
+ * Create an MRL for a specific sub-entry
*
+ * This internal function is used to create an MRL that refers to \subentry
+ * within \ref base, see \ref mrl_helpers for further information.
+ **/
+
+static char*
+StreamExtractorCreateMRL( char const* base, char const* subentry )
+{
+ struct vlc_memstream buffer;
+ char* escaped;
+
+ if( mrl_EscapeFragmentIdentifier( &escaped, subentry ) )
+ return NULL;
+
+ if( vlc_memstream_open( &buffer ) )
+ {
+ free( escaped );
+ return NULL;
+ }
+
+ vlc_memstream_puts( &buffer, base );
+
+ if( !strstr( base, "#" ) )
+ vlc_memstream_putc( &buffer, '#' );
+
+ vlc_memstream_printf( &buffer, "!/%s", escaped );
+
+ free( escaped );
+ return vlc_memstream_close( &buffer ) ? NULL : buffer.ptr;
+}
+
+/**
+ * Release the private data associated with a stream-extractor
* \param priv pointer to the private section
*/
static void se_Release( struct stream_extractor_private* priv )
{
- free( priv->public.identifier );
+ if( priv->pf_clean )
+ priv->pf_clean( priv );
if( priv->module )
{
- module_unneed( &priv->public, priv->module );
- vlc_stream_Delete( priv->public.source );
+ module_unneed( priv->object, priv->module );
+
+ if( priv->source )
+ vlc_stream_Delete( priv->source );
}
- vlc_object_release( &priv->public );
+ vlc_object_release( priv->object );
}
/**
- * \defgroup stream_extractor_Callbacks Stream Extractor Callbacks
- * \ingroup stream_extractor
+ * \name Callbacks to forward work to the underlying stream-extractor
+ *
* @{
- * \file
- * These functions simply forwards the relevant stream-request to
- * the underlying stream-extractor. They are a basic form of
- * type-erasure in that the outside world sees a stream_t, but the
- * work is actually done by a stream_extractor_t.
*/
static void
@@ -92,42 +147,41 @@ static ssize_t
se_StreamRead( stream_t* stream, void* buf, size_t len )
{
struct stream_extractor_private* priv = stream->p_sys;
- stream_extractor_t* extractor = &priv->public;
- return extractor->stream.pf_read( extractor, buf, len );
+ return priv->extractor.pf_read( &priv->extractor, buf, len );
}
static block_t*
se_StreamBlock( stream_t* stream, bool* eof )
{
struct stream_extractor_private* priv = stream->p_sys;
- stream_extractor_t* extractor = &priv->public;
- return extractor->stream.pf_block( extractor, eof );
+ return priv->extractor.pf_block( &priv->extractor, eof );
}
static int
se_StreamSeek( stream_t* stream, uint64_t offset )
{
struct stream_extractor_private* priv = stream->p_sys;
- stream_extractor_t* extractor = &priv->public;
- return extractor->stream.pf_seek( extractor, offset );
+ return priv->extractor.pf_seek( &priv->extractor, offset );
}
static int
-se_StreamReadDir( stream_t* stream, input_item_node_t* node )
+se_ReadDir( stream_t* stream, input_item_node_t* node )
{
struct stream_extractor_private* priv = stream->p_sys;
- stream_extractor_t* extractor = &priv->public;
- return extractor->directory.pf_readdir( extractor, node );
+ return priv->directory.pf_readdir( &priv->directory, node );
}
static int
se_StreamControl( stream_t* stream, int req, va_list args )
{
struct stream_extractor_private* priv = stream->p_sys;
- stream_extractor_t* extractor = &priv->public;
+ return priv->extractor.pf_control( &priv->extractor, req, args );
+}
- if( extractor->identifier )
- return extractor->stream.pf_control( extractor, req, args );
+static int
+se_DirControl( stream_t* stream, int req, va_list args )
+{
+ (void)stream;
if( req == STREAM_IS_DIRECTORY )
{
@@ -137,83 +191,134 @@ se_StreamControl( stream_t* stream, int req, va_list args )
return VLC_EGENERIC;
}
+
+/**
+ * @}
+ **/
+
+/**
+ * \name stream-extractor resource handlers
+ * \ingroup stream_extractor
+ * @{
+ */
+
+static int
+se_InitStream( struct stream_extractor_private* priv, stream_t* s )
+{
+ if( priv->extractor.pf_read ) s->pf_read = se_StreamRead;
+ else s->pf_block = se_StreamBlock;
+
+ s->pf_seek = se_StreamSeek;
+ s->pf_control = se_StreamControl;
+ s->psz_url = StreamExtractorCreateMRL( priv->extractor.source->psz_url,
+ priv->extractor.identifier );
+ if( unlikely( !s->psz_url ) )
+ return VLC_ENOMEM;
+
+ return VLC_SUCCESS;
+}
+
+static void
+se_CleanStream( struct stream_extractor_private* priv )
+{
+ free( (char*)priv->extractor.identifier );
+}
+
+static int
+se_InitDirectory( struct stream_extractor_private* priv, stream_t* s )
+{
+ stream_directory_t* directory = &priv->directory;
+
+ s->pf_readdir = se_ReadDir;
+ s->pf_control = se_DirControl;
+ s->psz_url = strdup( directory->source->psz_url );
+
+ if( unlikely( !s->psz_url ) )
+ return VLC_EGENERIC;
+
+ return VLC_SUCCESS;
+}
+
/**
* @}
**/
/**
- * Initialize the public stream_t for a stream_extractor_t
+ * Create the public stream_t that wraps a stream-extractor
*
- * This function simply initializes the relevant data-members of the
- * public stream_t which is a handle to the internal
- * stream_extractor_t.
+ * This initializes the relevant data-members of the public stream_t which is
+ * used to read from the underlying stream-extractor.
*
- * \param obj the private section of the stream_extractor_t
+ * \param priv the private section of the stream_extractor_t
* \param source the source stream which the stream_extractor_t should
* will read from
* \return VLC_SUCCESS on success, an error-code on failure.
**/
static int
-se_InitStream( struct stream_extractor_private* priv, stream_t* source )
+se_AttachWrapper( struct stream_extractor_private* priv, stream_t* source )
{
- stream_t* s = vlc_stream_CommonNew( priv->public.obj.parent,
- se_StreamDelete );
- if( unlikely( !s ) )
- return VLC_EGENERIC;
-
- if( priv->public.identifier )
- {
- if( priv->public.stream.pf_read ) s->pf_read = se_StreamRead;
- else s->pf_block = se_StreamBlock;
-
- s->pf_seek = se_StreamSeek;
- s->psz_url = vlc_stream_extractor_CreateMRL( &priv->public,
- priv->public.identifier );
- }
- else
- {
- s->pf_readdir = se_StreamReadDir;
- s->psz_url = source->psz_url ? strdup( source->psz_url ) : NULL;
- }
+ stream_t* s = vlc_stream_CommonNew( source->obj.parent, se_StreamDelete );
+ if( unlikely( !s ) )
+ return VLC_ENOMEM;
- if( source->psz_url && unlikely( !s->psz_url ) )
+ if( priv->pf_init( priv, s ) )
{
stream_CommonDelete( s );
return VLC_EGENERIC;
}
- priv->stream = s;
- priv->stream->pf_control = se_StreamControl;
- priv->stream->p_input = source->p_input;
- priv->stream->p_sys = priv;
+ priv->wrapper = s;
+ priv->wrapper->p_input = source->p_input;
+ priv->wrapper->p_sys = priv;
+
+ priv->source = source;
return VLC_SUCCESS;
}
-int
-vlc_stream_extractor_Attach( stream_t** source, char const* identifier,
- char const* module_name )
+static int
+StreamExtractorAttach( stream_t** source, char const* identifier,
+ char const* module_name )
{
+ char const* capability = identifier ? "stream_extractor"
+ : "stream_directory";
+
struct stream_extractor_private* priv = vlc_custom_create(
- (*source)->obj.parent, sizeof( *priv ), "stream_extractor" );
+ (*source)->obj.parent, sizeof( *priv ), capability );
if( unlikely( !priv ) )
return VLC_ENOMEM;
- priv->public.identifier = identifier ? strdup( identifier ) : NULL;
+ if( strcmp( capability, "stream_extractor" ) == 0 )
+ {
+ priv->object = VLC_OBJECT( &priv->extractor );
- if( unlikely( identifier && !priv->public.identifier ) )
- goto error;
+ priv->pf_init = se_InitStream;
+ priv->pf_clean = se_CleanStream;
+
+ priv->extractor.source = *source;
+ priv->extractor.identifier = strdup( identifier );
+
+ if( unlikely( !priv->extractor.identifier ) )
+ goto error;
+ }
+ else
+ {
+ priv->object = VLC_OBJECT( &priv->directory );
+
+ priv->pf_init = se_InitDirectory;
+ priv->pf_clean = NULL;
+
+ priv->directory.source = *source;
+ }
- priv->public.source = *source;
- priv->module = module_need( &priv->public, "stream_extractor",
- module_name, true );
+ priv->module = module_need( priv->object, capability, module_name, true );
- if( !priv->module || se_InitStream( priv, *source ) )
+ if( !priv->module || se_AttachWrapper( priv, *source ) )
goto error;
- *source = priv->stream;
+ *source = priv->wrapper;
return VLC_SUCCESS;
error:
@@ -221,31 +326,24 @@ error:
return VLC_EGENERIC;
}
-char*
-vlc_stream_extractor_CreateMRL( stream_extractor_t* extractor,
- char const* subentry )
+int
+vlc_stream_directory_Attach( stream_t** source, char const* module_name )
{
- struct vlc_memstream buffer;
- char* escaped;
-
- if( mrl_EscapeFragmentIdentifier( &escaped, subentry ) )
- return NULL;
-
- if( vlc_memstream_open( &buffer ) )
- {
- free( escaped );
- return NULL;
- }
-
- vlc_memstream_puts( &buffer, extractor->source->psz_url );
-
- if( !strstr( extractor->source->psz_url, "#" ) )
- vlc_memstream_putc( &buffer, '#' );
+ return StreamExtractorAttach( source, NULL, module_name );
+}
- vlc_memstream_printf( &buffer, "!/%s", escaped );
+int
+vlc_stream_extractor_Attach( stream_t** source, char const* identifier,
+ char const* module_name )
+{
+ return StreamExtractorAttach( source, identifier, module_name );
+}
- free( escaped );
- return vlc_memstream_close( &buffer ) ? NULL : buffer.ptr;
+char*
+vlc_stream_extractor_CreateMRL( stream_directory_t* directory,
+ char const* subentry )
+{
+ return StreamExtractorCreateMRL( directory->source->psz_url, subentry );
}
/**
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 150409e..455a03b 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -394,6 +394,7 @@ spu_ChangeFilters
spu_Render
spu_RegisterChannel
spu_ClearChannel
+vlc_stream_directory_Attach
vlc_stream_extractor_Attach
vlc_stream_extractor_CreateMRL
vlc_stream_Block
More information about the vlc-commits
mailing list