[vlc-devel] [PATCH 1/8] stream_extractor: split joint capability into two
Rémi Denis-Courmont
remi at remlab.net
Sat Feb 18 09:06:29 CET 2017
Le torstaina 16. helmikuuta 2017, 22.44.11 EET Filip Roséen a écrit :
> 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.
>
> Summary of changes:
>
> - update and refine documentation belonging to stream-extractors
> - stream_extractor_t is now stream_extractor_t and stream_directory_t
> - expose new function vlc_stream_directory_Attach to probe for a
> stream_directory to attach to a stream.
> ---
> include/vlc_stream_extractor.h | 118 +++++++++--------
> src/input/input.c | 2 +-
> src/input/stream_extractor.c | 286
> +++++++++++++++++++++++++++-------------- src/libvlccore.sym |
> 1 +
> 4 files changed, 257 insertions(+), 150 deletions(-)
>
> diff --git a/include/vlc_stream_extractor.h b/include/vlc_stream_extractor.h
> index 36bbd13131..42cf6cd58c 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 = stream_directory_t
> + * - capability = "stream_directory"
> + *
> + * - extract data associated with one specific entry within a stream:
> + * - type = stream_extractor_t
> + * - capability = "stream_extractor"
> *
> * @{
> *
> **/
> +
> 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 */
> + /**
> + * \name Callbacks for entity extraction
> + *
> + * The following members shall be populated as specified by the
> + * documentation associated with \stream_t for the equivalent name.
Does this actually work? It looks weird; I´d expect \ref stream_t or such...
> + *
> + * @{
> + **/
> + 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 */
This is valid but I don´t know why a very few developpers do this. The defacto
standard is qualifier before type.
> + stream_t* source; /**< the source stream to be consumed */
> + void* p_sys; /**< private opaque handle to be used by the module
> */ +};
> +
> +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 \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 */
> };
>
> typedef struct stream_extractor_t stream_extractor_t;
> +typedef struct stream_directory_t stream_directory_t;
Should be merged with the struct typedef (when possible).
>
> /**
> * 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
The (...).
> *
> - * \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.
> - *
> - * 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.
> + * \name Attach a stream-extractor to the passed 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, \vlc_stream_extractor_Attach
> will attach + * an entity-extractor, whereas \vlc_stream_directory_Attach
> will attach a + * 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 9eead35fb5..faab520bf9 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 573ba9d199..57a9a87a68 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
> + *
> + * \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* );
I don´t really get why this is needed inside a private structure.
> +
> + /**
> + * Callback to handle clean-up
> + *
> + * \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 \pf_init).
> + */
> + void (*pf_clean)( struct stream_extractor_private* );
Ditto.
> +
> + stream_t* wrapper; /**< the wrapping 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 \base, see \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 150409e073..455a03b2fe 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
--
雷米‧德尼-库尔蒙
https://www.remlab.net/
More information about the vlc-devel
mailing list