@ -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_Stream ReadDir ( 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
* Creat e 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
StreamExtractor Attach( 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 ) ;
}
/**