qml: history.push changes view by default
[vlc.git] / src / preparser / preparser.c
blob723feb96dc7eb15105be08323f1f27d25d6fd036
1 /*****************************************************************************
2 * preparser.c
3 *****************************************************************************
4 * Copyright © 2017-2017 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 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <vlc_common.h>
26 #include <vlc_atomic.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 input_preparser_t
36 vlc_object_t* owner;
37 input_fetcher_t* fetcher;
38 struct background_worker* worker;
39 atomic_bool deactivated;
42 typedef struct input_preparser_req_t
44 input_item_t *item;
45 input_item_meta_request_option_t options;
46 const input_preparser_callbacks_t *cbs;
47 void *userdata;
48 vlc_atomic_rc_t rc;
49 } input_preparser_req_t;
51 typedef struct input_preparser_task_t
53 input_preparser_req_t *req;
54 input_preparser_t* preparser;
55 int preparse_status;
56 input_item_parser_id_t *parser;
57 atomic_int state;
58 atomic_bool done;
59 } input_preparser_task_t;
61 static input_preparser_req_t *ReqCreate(input_item_t *item,
62 input_item_meta_request_option_t options,
63 const input_preparser_callbacks_t *cbs,
64 void *userdata)
66 input_preparser_req_t *req = malloc(sizeof(*req));
67 if (unlikely(!req))
68 return NULL;
70 req->item = item;
71 req->options = options;
72 req->cbs = cbs;
73 req->userdata = userdata;
74 vlc_atomic_rc_init(&req->rc);
76 input_item_Hold(item);
78 return req;
81 static void ReqHold(input_preparser_req_t *req)
83 vlc_atomic_rc_inc(&req->rc);
86 static void ReqRelease(input_preparser_req_t *req)
88 if (vlc_atomic_rc_dec(&req->rc))
90 input_item_Release(req->item);
91 free(req);
95 static void OnParserEnded(input_item_t *item, int status, void *task_)
97 VLC_UNUSED(item);
98 input_preparser_task_t* task = task_;
100 atomic_store( &task->state, status );
101 atomic_store( &task->done, true );
102 background_worker_RequestProbe( task->preparser->worker );
105 static void OnParserSubtreeAdded(input_item_t *item, input_item_node_t *subtree,
106 void *task_)
108 VLC_UNUSED(item);
109 input_preparser_task_t* task = task_;
110 input_preparser_req_t *req = task->req;
112 if (req->cbs && req->cbs->on_subtree_added)
113 req->cbs->on_subtree_added(req->item, subtree, req->userdata);
116 static int PreparserOpenInput( void* preparser_, void* req_, void** out )
118 input_preparser_t* preparser = preparser_;
119 input_preparser_req_t *req = req_;
120 input_preparser_task_t* task = malloc( sizeof *task );
122 if( unlikely( !task ) )
123 goto error;
125 static const input_item_parser_cbs_t cbs = {
126 .on_ended = OnParserEnded,
127 .on_subtree_added = OnParserSubtreeAdded,
130 atomic_init( &task->state, VLC_ETIMEOUT );
131 atomic_init( &task->done, false );
133 task->preparser = preparser_;
134 task->req = req;
135 task->preparse_status = -1;
136 task->parser = input_item_Parse( req->item, preparser->owner, &cbs,
137 task );
138 if( !task->parser )
139 goto error;
141 *out = task;
143 return VLC_SUCCESS;
145 error:
146 free( task );
147 if (req->cbs && req->cbs->on_preparse_ended)
148 req->cbs->on_preparse_ended(req->item, ITEM_PREPARSE_FAILED, req->userdata);
149 return VLC_EGENERIC;
152 static int PreparserProbeInput( void* preparser_, void* task_ )
154 input_preparser_task_t* task = task_;
155 return atomic_load( &task->done );
156 VLC_UNUSED( preparser_ );
159 static void on_art_fetch_ended(input_item_t *item, bool fetched, void *userdata)
161 VLC_UNUSED(item);
162 VLC_UNUSED(fetched);
163 input_preparser_task_t *task = userdata;
164 input_preparser_req_t *req = task->req;
166 input_item_SetPreparsed(req->item, true);
168 if (req->cbs && req->cbs->on_preparse_ended)
169 req->cbs->on_preparse_ended(req->item, task->preparse_status, req->userdata);
171 ReqRelease(req);
172 free(task);
175 static const input_fetcher_callbacks_t input_fetcher_callbacks = {
176 .on_art_fetch_ended = on_art_fetch_ended,
179 static void PreparserCloseInput( void* preparser_, void* task_ )
181 input_preparser_task_t* task = task_;
182 input_preparser_req_t *req = task->req;
184 input_preparser_t* preparser = preparser_;
185 input_item_t* item = req->item;
187 int status;
188 switch( atomic_load( &task->state ) )
190 case VLC_SUCCESS:
191 status = ITEM_PREPARSE_DONE;
192 break;
193 case VLC_ETIMEOUT:
194 status = ITEM_PREPARSE_TIMEOUT;
195 break;
196 default:
197 status = ITEM_PREPARSE_FAILED;
198 break;
201 input_item_parser_id_Release( task->parser );
203 if( preparser->fetcher && (req->options & META_REQUEST_OPTION_FETCH_ANY) )
205 task->preparse_status = status;
206 ReqHold(task->req);
207 if (!input_fetcher_Push(preparser->fetcher, item,
208 req->options & META_REQUEST_OPTION_FETCH_ANY,
209 &input_fetcher_callbacks, task))
211 return;
213 ReqRelease(task->req);
216 free(task);
218 input_item_SetPreparsed( item, true );
219 if (req->cbs && req->cbs->on_preparse_ended)
220 req->cbs->on_preparse_ended(req->item, status, req->userdata);
223 static void ReqHoldVoid(void *item) { ReqHold(item); }
224 static void ReqReleaseVoid(void *item) { ReqRelease(item); }
226 input_preparser_t* input_preparser_New( vlc_object_t *parent )
228 input_preparser_t* preparser = malloc( sizeof *preparser );
230 struct background_worker_config conf = {
231 .default_timeout = VLC_TICK_FROM_MS(var_InheritInteger( parent, "preparse-timeout" )),
232 .max_threads = var_InheritInteger( parent, "preparse-threads" ),
233 .pf_start = PreparserOpenInput,
234 .pf_probe = PreparserProbeInput,
235 .pf_stop = PreparserCloseInput,
236 .pf_release = ReqReleaseVoid,
237 .pf_hold = ReqHoldVoid
241 if( likely( preparser ) )
242 preparser->worker = background_worker_New( preparser, &conf );
244 if( unlikely( !preparser || !preparser->worker ) )
246 free( preparser );
247 return NULL;
250 preparser->owner = parent;
251 preparser->fetcher = input_fetcher_New( parent );
252 atomic_init( &preparser->deactivated, false );
254 if( unlikely( !preparser->fetcher ) )
255 msg_Warn( parent, "unable to create art fetcher" );
257 return preparser;
260 void input_preparser_Push( input_preparser_t *preparser,
261 input_item_t *item, input_item_meta_request_option_t i_options,
262 const input_preparser_callbacks_t *cbs, void *cbs_userdata,
263 int timeout, void *id )
265 if( atomic_load( &preparser->deactivated ) )
266 return;
268 vlc_mutex_lock( &item->lock );
269 enum input_item_type_e i_type = item->i_type;
270 int b_net = item->b_net;
271 if( i_options & META_REQUEST_OPTION_DO_INTERACT )
272 item->b_preparse_interact = true;
273 vlc_mutex_unlock( &item->lock );
275 switch( i_type )
277 case ITEM_TYPE_NODE:
278 case ITEM_TYPE_FILE:
279 case ITEM_TYPE_DIRECTORY:
280 case ITEM_TYPE_PLAYLIST:
281 if( !b_net || i_options & META_REQUEST_OPTION_SCOPE_NETWORK )
282 break;
283 /* fallthrough */
284 default:
285 if (cbs && cbs->on_preparse_ended)
286 cbs->on_preparse_ended(item, ITEM_PREPARSE_SKIPPED, cbs_userdata);
287 return;
290 struct input_preparser_req_t *req = ReqCreate(item, i_options,
291 cbs, cbs_userdata);
293 if (background_worker_Push(preparser->worker, req, id, timeout))
294 if (req->cbs && cbs->on_preparse_ended)
295 cbs->on_preparse_ended(item, ITEM_PREPARSE_FAILED, cbs_userdata);
297 ReqRelease(req);
300 void input_preparser_fetcher_Push( input_preparser_t *preparser,
301 input_item_t *item, input_item_meta_request_option_t options,
302 const input_fetcher_callbacks_t *cbs, void *cbs_userdata )
304 if( preparser->fetcher )
305 input_fetcher_Push( preparser->fetcher, item, options,
306 cbs, cbs_userdata );
309 void input_preparser_Cancel( input_preparser_t *preparser, void *id )
311 background_worker_Cancel( preparser->worker, id );
314 void input_preparser_Deactivate( input_preparser_t* preparser )
316 atomic_store( &preparser->deactivated, true );
317 background_worker_Cancel( preparser->worker, NULL );
320 void input_preparser_Delete( input_preparser_t *preparser )
322 background_worker_Delete( preparser->worker );
324 if( preparser->fetcher )
325 input_fetcher_Delete( preparser->fetcher );
327 free( preparser );