1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2016 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 #ifndef STREAM_EXTRACTOR_H
22 #define STREAM_EXTRACTOR_H
28 #include <vlc_common.h>
29 #include <vlc_stream.h>
30 #include <vlc_stream_extractor.h>
31 #include <vlc_modules.h>
33 #include <vlc_memstream.h>
38 #include "mrl_helpers.h"
41 * \defgroup stream_extractor_Internals Stream Extractor Internals
42 * \ingroup stream_extractor
48 struct stream_extractor_private
{
50 stream_extractor_t extractor
;
51 stream_directory_t directory
;
55 * Callback to handle initialization
57 * \ref pf_init will be called after successful module probing to initialize
58 * the relevant members of the underlying stream-extractor object, as well
59 * as the wrapping stream.
61 int (*pf_init
)( struct stream_extractor_private
*, stream_t
* );
64 * Callback to handle clean-up
66 * \ref pf_clean, unless NULL, will be called when the stream-extractor is to
67 * be destroyed, and shall be used to clean-up resources (acquired during
68 * initialization, see \ref pf_init).
70 void (*pf_clean
)( struct stream_extractor_private
* );
72 stream_t
* wrapper
; /**< the wrapping \ref stream_t used to access the
73 underlying stream-extractor */
75 stream_t
* source
; /**< the source stream consumed by the stream-extractor */
76 module_t
* module
; /**< the stream-extractor module */
78 vlc_object_t
* object
; /**< the underlying stream-extractor object */
82 * Create an MRL for a specific sub-entry
84 * This internal function is used to create an MRL that refers to \subentry
85 * within \ref base, see \ref mrl_helpers for further information.
89 StreamExtractorCreateMRL( char const* base
, char const* subentry
)
91 struct vlc_memstream buffer
;
94 if( mrl_EscapeFragmentIdentifier( &escaped
, subentry
) )
97 if( vlc_memstream_open( &buffer
) )
103 vlc_memstream_puts( &buffer
, base
);
105 if( !strstr( base
, "#" ) )
106 vlc_memstream_putc( &buffer
, '#' );
108 vlc_memstream_printf( &buffer
, "!/%s", escaped
);
111 return vlc_memstream_close( &buffer
) ? NULL
: buffer
.ptr
;
115 * Release the private data associated with a stream-extractor
116 * \param priv pointer to the private section
118 static void se_Release( struct stream_extractor_private
* priv
)
121 priv
->pf_clean( priv
);
125 module_unneed( priv
->object
, priv
->module
);
128 vlc_stream_Delete( priv
->source
);
131 vlc_object_release( priv
->object
);
135 * \name Callbacks to forward work to the underlying stream-extractor
141 se_StreamDelete( stream_t
* stream
)
143 se_Release( stream
->p_sys
);
147 se_StreamRead( stream_t
* stream
, void* buf
, size_t len
)
149 struct stream_extractor_private
* priv
= stream
->p_sys
;
150 return priv
->extractor
.pf_read( &priv
->extractor
, buf
, len
);
154 se_StreamBlock( stream_t
* stream
, bool* eof
)
156 struct stream_extractor_private
* priv
= stream
->p_sys
;
157 return priv
->extractor
.pf_block( &priv
->extractor
, eof
);
161 se_StreamSeek( stream_t
* stream
, uint64_t offset
)
163 struct stream_extractor_private
* priv
= stream
->p_sys
;
164 return priv
->extractor
.pf_seek( &priv
->extractor
, offset
);
168 se_ReadDir( stream_t
* stream
, input_item_node_t
* node
)
170 struct stream_extractor_private
* priv
= stream
->p_sys
;
171 return priv
->directory
.pf_readdir( &priv
->directory
, node
);
175 se_StreamControl( stream_t
* stream
, int req
, va_list args
)
177 struct stream_extractor_private
* priv
= stream
->p_sys
;
178 return priv
->extractor
.pf_control( &priv
->extractor
, req
, args
);
182 se_DirControl( stream_t
* stream
, int req
, va_list args
)
187 if( req
== STREAM_IS_DIRECTORY
)
198 * \name stream-extractor resource handlers
199 * \ingroup stream_extractor
204 se_InitStream( struct stream_extractor_private
* priv
, stream_t
* s
)
206 if( priv
->extractor
.pf_read
) s
->pf_read
= se_StreamRead
;
207 else s
->pf_block
= se_StreamBlock
;
209 s
->pf_seek
= se_StreamSeek
;
210 s
->pf_control
= se_StreamControl
;
211 s
->psz_url
= StreamExtractorCreateMRL( priv
->extractor
.source
->psz_url
,
212 priv
->extractor
.identifier
);
213 if( unlikely( !s
->psz_url
) )
220 se_CleanStream( struct stream_extractor_private
* priv
)
222 free( (char*)priv
->extractor
.identifier
);
226 se_InitDirectory( struct stream_extractor_private
* priv
, stream_t
* s
)
228 stream_directory_t
* directory
= &priv
->directory
;
230 s
->pf_readdir
= se_ReadDir
;
231 s
->pf_control
= se_DirControl
;
232 s
->psz_url
= strdup( directory
->source
->psz_url
);
234 if( unlikely( !s
->psz_url
) )
245 * Create the public stream_t that wraps a stream-extractor
247 * This initializes the relevant data-members of the public stream_t which is
248 * used to read from the underlying stream-extractor.
250 * \param priv the private section of the stream_extractor_t
251 * \param source the source stream which the stream_extractor_t should
253 * \return VLC_SUCCESS on success, an error-code on failure.
256 se_AttachWrapper( struct stream_extractor_private
* priv
, stream_t
* source
)
258 stream_t
* s
= vlc_stream_CommonNew( source
->obj
.parent
, se_StreamDelete
);
263 if( priv
->pf_init( priv
, s
) )
265 stream_CommonDelete( s
);
270 priv
->wrapper
->p_input
= source
->p_input
;
271 priv
->wrapper
->p_sys
= priv
;
273 priv
->source
= source
;
275 if( priv
->wrapper
->pf_read
)
276 priv
->wrapper
= stream_FilterChainNew( priv
->wrapper
, "cache_read" );
277 else if( priv
->wrapper
->pf_block
)
278 priv
->wrapper
= stream_FilterChainNew( priv
->wrapper
, "cache_block" );
284 StreamExtractorAttach( stream_t
** source
, char const* identifier
,
285 char const* module_name
)
287 const bool extractor
= identifier
!= NULL
;
288 char const* capability
= extractor
? "stream_extractor"
289 : "stream_directory";
291 struct stream_extractor_private
* priv
= vlc_custom_create(
292 (*source
)->obj
.parent
, sizeof( *priv
), capability
);
294 if( unlikely( !priv
) )
299 priv
->object
= VLC_OBJECT( &priv
->extractor
);
301 priv
->pf_init
= se_InitStream
;
302 priv
->pf_clean
= se_CleanStream
;
304 priv
->extractor
.source
= *source
;
305 priv
->extractor
.identifier
= strdup( identifier
);
307 if( unlikely( !priv
->extractor
.identifier
) )
312 priv
->object
= VLC_OBJECT( &priv
->directory
);
314 priv
->pf_init
= se_InitDirectory
;
315 priv
->pf_clean
= NULL
;
317 priv
->directory
.source
= *source
;
320 priv
->module
= module_need( priv
->object
, capability
, module_name
, true );
322 if( !priv
->module
|| se_AttachWrapper( priv
, *source
) )
325 *source
= priv
->wrapper
;
334 vlc_stream_directory_Attach( stream_t
** source
, char const* module_name
)
336 return StreamExtractorAttach( source
, NULL
, module_name
);
340 vlc_stream_extractor_Attach( stream_t
** source
, char const* identifier
,
341 char const* module_name
)
343 return StreamExtractorAttach( source
, identifier
, module_name
);
347 stream_extractor_AttachParsed( stream_t
** source
, char const* data
,
348 char const** out_extra
)
350 vlc_array_t identifiers
;
352 if( mrl_FragmentSplit( &identifiers
, out_extra
, data
) )
355 size_t count
= vlc_array_count( &identifiers
);
360 char* id
= vlc_array_item_at_index( &identifiers
, idx
);
362 if( vlc_stream_extractor_Attach( source
, id
, NULL
) )
368 for( size_t i
= 0; i
< count
; ++i
)
369 free( vlc_array_item_at_index( &identifiers
, i
) );
370 vlc_array_clear( &identifiers
);
372 return idx
== count
? VLC_SUCCESS
: VLC_EGENERIC
;
376 vlc_stream_extractor_CreateMRL( stream_directory_t
* directory
,
377 char const* subentry
)
379 return StreamExtractorCreateMRL( directory
->source
->psz_url
, subentry
);
386 #endif /* include-guard */