vlc | branch: master | Filip Roséen <[email protected]> | 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 <[email protected]> > 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 _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
