stream_extractor: store and forward volume information

Also propagates missing volume information to directories listing.
Until now it was assumed archives only had direcoty info in the first
volume.
This commit is contained in:
François Cartegnie 2023-08-31 17:50:55 +07:00 committed by Steve Lhomme
parent b84d09bd98
commit 9856c789ec
6 changed files with 103 additions and 36 deletions

View File

@ -64,6 +64,8 @@ typedef struct stream_extractor_t {
int (*pf_control)(struct stream_extractor_t*, int request, va_list args);
/** @} */
char ** volumes;
size_t volumes_count;
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 */
@ -84,6 +86,8 @@ typedef struct stream_directory_t {
int (*pf_readdir)(struct stream_directory_t*, input_item_node_t* );
/** @} */
char ** volumes;
size_t volumes_count;
stream_t* source; /**< the source stream to be consumed */
void* p_sys; /**< private opaque handle to be used by the module */
@ -146,6 +150,8 @@ VLC_API char* vlc_stream_extractor_CreateMRL( stream_directory_t *extractor,
* \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
* \param volumes media additional volumes MRLs
* \param volumes_count number of additional volumes
*
* \return VLC_SUCCESS if a stream-extractor was successfully
* attached, an error-code on failure.
@ -154,11 +160,13 @@ VLC_API char* vlc_stream_extractor_CreateMRL( stream_directory_t *extractor,
**/
VLC_API int vlc_stream_extractor_Attach( stream_t** source,
char const* identifier,
char const* module_name );
char const* identifier,
char const* module_name,
const char **volumes, size_t volumes_count );
VLC_API int vlc_stream_directory_Attach( stream_t** source,
char const* module_name );
char const* module_name,
const char **volumes, size_t volumes_count );
/**
* @}
*/

View File

@ -227,7 +227,7 @@ bool ThemeLoader::unarchive( const std::string& fileName, const std::string &tem
}
stream_t* stream = input.get();
if( vlc_stream_directory_Attach( &stream, NULL ) )
if( vlc_stream_directory_Attach( &stream, NULL, NULL, 0 ) )
{
msg_Err( getIntf(), "unable to attach stream_directory, treat as XML!" );
}

View File

@ -110,7 +110,7 @@ static int vlclua_directory_stream_new( lua_State *L )
stream_t *p_stream = vlc_stream_NewURL( p_this, psz_url );
if( !p_stream )
return vlclua_error( L );
if( vlc_stream_directory_Attach( &p_stream, NULL ) != VLC_SUCCESS )
if( vlc_stream_directory_Attach( &p_stream, NULL, NULL, 0 ) != VLC_SUCCESS )
{
vlc_stream_Delete( p_stream );
return vlclua_error( L );

View File

@ -2552,7 +2552,9 @@ InputStreamHandleAnchor( input_thread_t *p_input, input_source_t *source,
return VLC_EGENERIC;
}
if( vlc_stream_directory_Attach( stream, NULL ) )
if( vlc_stream_directory_Attach( stream, NULL,
(const char **) mrli.volumes.pp_elems,
mrli.volumes.i_count ) )
msg_Dbg( p_input, "attachment of directory-extractor failed for %s",
(*stream)->psz_url );
@ -2701,6 +2703,7 @@ static int InputSourceInit( input_source_t *in, input_thread_t *p_input,
}
}
char *psz_newanchor = NULL;
if( strcasecmp( psz_access, "concat" ) )
{ /* Autodetect extra files if none specified */
int count;
@ -2708,28 +2711,16 @@ static int InputSourceInit( input_source_t *in, input_thread_t *p_input,
TAB_INIT( count, tab );
InputGetExtraFiles( p_input, &count, &tab, &psz_access, psz_mrl );
if( count > 0 )
for( int i = 0; i < count; i++ )
{
char *list = NULL;
for( int i = 0; i < count; i++ )
char *psz = mrl_AppendAnchorFragment( psz_newanchor ? psz_newanchor : psz_anchor, tab[i] );
if( psz )
{
char *str;
if( asprintf( &str, "%s,%s", list ? list : psz_mrl,
tab[i] ) < 0 )
break;
free( tab[i] );
free( list );
list = str;
}
var_Create( p_input, "concat-list", VLC_VAR_STRING );
if( likely(list != NULL) )
{
var_SetString( p_input, "concat-list", list );
free( list );
free( psz_newanchor );
psz_newanchor = psz;
}
free( tab[i] );
}
TAB_CLEAN( count, tab );
}
@ -2746,12 +2737,13 @@ static int InputSourceInit( input_source_t *in, input_thread_t *p_input,
if( es_out )
in->p_demux = InputDemuxNew( p_input, es_out, in, url,
psz_demux, psz_anchor );
psz_demux, psz_newanchor ? psz_newanchor : psz_anchor );
free( url );
}
else
in->p_demux = NULL;
free( psz_newanchor );
free( psz_demux_var );
free( psz_dup );

View File

@ -89,6 +89,36 @@ mrl_EscapeFragmentIdentifier( char const* payload )
return mstream.ptr;
}
static inline char *
mrl_AppendAnchorFragment( const char *anchor, char const *payload )
{
struct vlc_memstream mstream;
if( vlc_memstream_open( &mstream ) )
return NULL;
if( anchor )
vlc_memstream_puts( &mstream, anchor );
else
vlc_memstream_putc( &mstream, '#' );
char *escaped = mrl_EscapeFragmentIdentifier( payload );
if( escaped == NULL )
{
if( !vlc_memstream_close( &mstream ) )
free( mstream.ptr );
return NULL;
}
vlc_memstream_puts( &mstream, "!+" );
vlc_memstream_puts( &mstream, escaped );
free( escaped );
if( vlc_memstream_close( &mstream ) )
return NULL;
return mstream.ptr;
}
struct mrl_info
{
vlc_array_t identifiers;

View File

@ -218,7 +218,8 @@ se_InitStream( struct stream_extractor_private* priv, stream_t* s )
s->pf_control = se_StreamControl;
s->psz_url = StreamExtractorCreateMRL( priv->extractor.source->psz_url,
priv->extractor.identifier,
NULL, 0 );
(char const **) priv->extractor.volumes,
priv->extractor.volumes_count );
if( unlikely( !s->psz_url ) )
return VLC_ENOMEM;
@ -226,9 +227,20 @@ se_InitStream( struct stream_extractor_private* priv, stream_t* s )
}
static void
se_CleanStream( struct stream_extractor_private* priv )
se_CleanStreamExtractor( struct stream_extractor_private* priv )
{
free( (char*)priv->extractor.identifier );
for( size_t i=0; i<priv->extractor.volumes_count; i++ )
free( priv->extractor.volumes[i] );
free( priv->extractor.volumes );
}
static void
se_CleanStreamDirectory( struct stream_extractor_private* priv )
{
for( size_t i=0; i<priv->directory.volumes_count; i++ )
free( priv->directory.volumes[i] );
free( priv->directory.volumes );
}
static int
@ -288,7 +300,7 @@ se_AttachWrapper( struct stream_extractor_private* priv, stream_t* source )
static int
StreamExtractorAttach( stream_t** source, char const* identifier,
char const* module_name )
char const* module_name, const char **volumes, size_t volumes_count )
{
const bool extractor = identifier != NULL;
char const* capability = extractor ? "stream_extractor"
@ -300,27 +312,49 @@ StreamExtractorAttach( stream_t** source, char const* identifier,
if( unlikely( !priv ) )
return VLC_ENOMEM;
char ***dst_volumes;
size_t * dst_volumes_count;
if( extractor )
{
priv->object = VLC_OBJECT( &priv->extractor );
priv->pf_init = se_InitStream;
priv->pf_clean = se_CleanStream;
priv->pf_clean = se_CleanStreamExtractor;
priv->extractor.source = *source;
priv->extractor.identifier = strdup( identifier );
if( unlikely( !priv->extractor.identifier ) )
goto error;
dst_volumes = &priv->extractor.volumes;
dst_volumes_count = &priv->extractor.volumes_count;
}
else
{
priv->object = VLC_OBJECT( &priv->directory );
priv->pf_init = se_InitDirectory;
priv->pf_clean = NULL;
priv->pf_clean = se_CleanStreamDirectory;
priv->directory.source = *source;
dst_volumes = &priv->directory.volumes;
dst_volumes_count = &priv->directory.volumes_count;
}
if( volumes_count )
{
*dst_volumes = malloc(volumes_count * sizeof(char *));
if( unlikely(!*dst_volumes) )
goto error;
for( *dst_volumes_count=0; *dst_volumes_count<volumes_count; (*dst_volumes_count)++ )
{
(*dst_volumes)[*dst_volumes_count] = strdup(volumes[*dst_volumes_count]);
if( unlikely(!(*dst_volumes)[*dst_volumes_count]) )
goto error;
}
}
priv->module = module_need( priv->object, capability, module_name, true );
@ -337,16 +371,17 @@ error:
}
int
vlc_stream_directory_Attach( stream_t** source, char const* module_name )
vlc_stream_directory_Attach( stream_t** source, char const* module_name,
const char **volumes, size_t volumes_count )
{
return StreamExtractorAttach( source, NULL, module_name );
return StreamExtractorAttach( source, NULL, module_name, volumes, volumes_count );
}
int
vlc_stream_extractor_Attach( stream_t** source, char const* identifier,
char const* module_name )
char const* module_name, const char **volumes, size_t volumes_count )
{
return StreamExtractorAttach( source, identifier, module_name );
return StreamExtractorAttach( source, identifier, module_name, volumes, volumes_count );
}
int
@ -359,7 +394,9 @@ stream_extractor_AttachParsed( stream_t** source, const struct mrl_info *mrli )
{
char* id = vlc_array_item_at_index( &mrli->identifiers, idx );
if( vlc_stream_extractor_Attach( source, id, NULL ) )
if( vlc_stream_extractor_Attach( source, id, NULL,
(char const **) mrli->volumes.pp_elems,
mrli->volumes.i_count ) )
break;
++idx;