VLSub: Handle incomplete/invalid result sets without crashing
[vlc.git] / src / playlist / preparser.c
blob1122dd7cefe622fbc9ec64241111fb93976266ff
1 /*****************************************************************************
2 * preparser.c
3 *****************************************************************************
4 * Copyright © 2017-2017 VLC authors and VideoLAN
5 * $Id$
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20 *****************************************************************************/
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
26 #include <vlc_common.h>
28 #include "misc/background_worker.h"
29 #include "input/input_interface.h"
30 #include "input/input_internal.h"
31 #include "preparser.h"
32 #include "fetcher.h"
34 struct playlist_preparser_t
36 vlc_object_t* owner;
37 playlist_fetcher_t* fetcher;
38 struct background_worker* worker;
39 atomic_bool deactivated;
42 static int InputEvent( vlc_object_t* obj, const char* varname,
43 vlc_value_t old, vlc_value_t cur, void* worker )
45 VLC_UNUSED( obj ); VLC_UNUSED( varname ); VLC_UNUSED( old );
47 if( cur.i_int == INPUT_EVENT_DEAD )
48 background_worker_RequestProbe( worker );
50 return VLC_SUCCESS;
53 static int PreparserOpenInput( void* preparser_, void* item_, void** out )
55 playlist_preparser_t* preparser = preparser_;
57 input_thread_t* input = input_CreatePreparser( preparser->owner, item_ );
58 if( !input )
60 input_item_SignalPreparseEnded( item_, ITEM_PREPARSE_FAILED );
61 return VLC_EGENERIC;
64 var_AddCallback( input, "intf-event", InputEvent, preparser->worker );
65 if( input_Start( input ) )
67 input_Close( input );
68 var_DelCallback( input, "intf-event", InputEvent, preparser->worker );
69 input_item_SignalPreparseEnded( item_, ITEM_PREPARSE_FAILED );
70 return VLC_EGENERIC;
73 *out = input;
74 return VLC_SUCCESS;
77 static int PreparserProbeInput( void* preparser_, void* input_ )
79 int state = input_GetState( input_ );
80 return state == END_S || state == ERROR_S;
81 VLC_UNUSED( preparser_ );
84 static void PreparserCloseInput( void* preparser_, void* input_ )
86 playlist_preparser_t* preparser = preparser_;
87 input_thread_t* input = input_;
88 input_item_t* item = input_priv(input)->p_item;
90 var_DelCallback( input, "intf-event", InputEvent, preparser->worker );
92 int status;
93 switch( input_GetState( input ) )
95 case END_S:
96 status = ITEM_PREPARSE_DONE;
97 break;
98 case ERROR_S:
99 status = ITEM_PREPARSE_FAILED;
100 break;
101 default:
102 status = ITEM_PREPARSE_TIMEOUT;
105 input_Stop( input );
106 input_Close( input );
108 if( preparser->fetcher )
110 if( !playlist_fetcher_Push( preparser->fetcher, item, 0, status ) )
111 return;
114 input_item_SetPreparsed( item, true );
115 input_item_SignalPreparseEnded( item, status );
118 static void InputItemRelease( void* item ) { input_item_Release( item ); }
119 static void InputItemHold( void* item ) { input_item_Hold( item ); }
121 playlist_preparser_t* playlist_preparser_New( vlc_object_t *parent )
123 playlist_preparser_t* preparser = malloc( sizeof *preparser );
125 struct background_worker_config conf = {
126 .default_timeout = var_InheritInteger( parent, "preparse-timeout" ),
127 .pf_start = PreparserOpenInput,
128 .pf_probe = PreparserProbeInput,
129 .pf_stop = PreparserCloseInput,
130 .pf_release = InputItemRelease,
131 .pf_hold = InputItemHold };
134 if( likely( preparser ) )
135 preparser->worker = background_worker_New( preparser, &conf );
137 if( unlikely( !preparser || !preparser->worker ) )
139 free( preparser );
140 return NULL;
143 preparser->owner = parent;
144 preparser->fetcher = playlist_fetcher_New( parent );
145 atomic_init( &preparser->deactivated, false );
147 if( unlikely( !preparser->fetcher ) )
148 msg_Warn( parent, "unable to create art fetcher" );
150 return preparser;
153 void playlist_preparser_Push( playlist_preparser_t *preparser,
154 input_item_t *item, input_item_meta_request_option_t i_options,
155 int timeout, void *id )
157 if( atomic_load( &preparser->deactivated ) )
158 return;
160 vlc_mutex_lock( &item->lock );
161 int i_type = item->i_type;
162 int b_net = item->b_net;
163 vlc_mutex_unlock( &item->lock );
165 switch( i_type )
167 case ITEM_TYPE_NODE:
168 case ITEM_TYPE_FILE:
169 case ITEM_TYPE_DIRECTORY:
170 case ITEM_TYPE_PLAYLIST:
171 if( !b_net || i_options & META_REQUEST_OPTION_SCOPE_NETWORK )
172 break;
173 default:
174 input_item_SignalPreparseEnded( item, ITEM_PREPARSE_SKIPPED );
175 return;
178 if( background_worker_Push( preparser->worker, item, id, timeout ) )
179 input_item_SignalPreparseEnded( item, ITEM_PREPARSE_FAILED );
182 void playlist_preparser_fetcher_Push( playlist_preparser_t *preparser,
183 input_item_t *item, input_item_meta_request_option_t options )
185 if( preparser->fetcher )
186 playlist_fetcher_Push( preparser->fetcher, item, options, -1 );
189 void playlist_preparser_Cancel( playlist_preparser_t *preparser, void *id )
191 background_worker_Cancel( preparser->worker, id );
194 void playlist_preparser_Deactivate( playlist_preparser_t* preparser )
196 atomic_store( &preparser->deactivated, true );
197 background_worker_Cancel( preparser->worker, NULL );
200 void playlist_preparser_Delete( playlist_preparser_t *preparser )
202 background_worker_Delete( preparser->worker );
204 if( preparser->fetcher )
205 playlist_fetcher_Delete( preparser->fetcher );
207 free( preparser );