gui: macos: use float for rate
[vlc.git] / src / preparser / preparser.c
blob9c35bc12bd0d8d0527b87817127c9cbf09743a2e
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 const input_preparser_callbacks_t *cbs;
46 void *userdata;
47 vlc_atomic_rc_t rc;
48 } input_preparser_req_t;
50 typedef struct input_preparser_task_t
52 input_preparser_req_t *req;
53 input_preparser_t* preparser;
54 int preparse_status;
55 input_thread_t* input;
56 atomic_int state;
57 atomic_bool done;
58 } input_preparser_task_t;
60 static input_preparser_req_t *ReqCreate(input_item_t *item,
61 const input_preparser_callbacks_t *cbs,
62 void *userdata)
64 input_preparser_req_t *req = malloc(sizeof(*req));
65 if (unlikely(!req))
66 return NULL;
68 req->item = item;
69 req->cbs = cbs;
70 req->userdata = userdata;
71 vlc_atomic_rc_init(&req->rc);
73 input_item_Hold(item);
75 return req;
78 static void ReqHold(input_preparser_req_t *req)
80 vlc_atomic_rc_inc(&req->rc);
83 static void ReqRelease(input_preparser_req_t *req)
85 if (vlc_atomic_rc_dec(&req->rc))
87 input_item_Release(req->item);
88 free(req);
92 static void InputEvent( input_thread_t *input,
93 const struct vlc_input_event *event, void *task_ )
95 VLC_UNUSED( input );
96 input_preparser_task_t* task = task_;
98 switch( event->type )
100 case INPUT_EVENT_STATE:
101 atomic_store( &task->state, event->state );
102 break;
104 case INPUT_EVENT_DEAD:
105 atomic_store( &task->done, true );
106 background_worker_RequestProbe( task->preparser->worker );
107 break;
108 case INPUT_EVENT_SUBITEMS:
110 input_preparser_req_t *req = task->req;
111 if (req->cbs && req->cbs->on_subtree_added)
112 req->cbs->on_subtree_added(req->item, event->subitems, req->userdata);
113 break;
115 default: ;
119 static int PreparserOpenInput( void* preparser_, void* req_, void** out )
121 input_preparser_t* preparser = preparser_;
122 input_preparser_req_t *req = req_;
123 input_preparser_task_t* task = malloc( sizeof *task );
125 if( unlikely( !task ) )
126 goto error;
128 atomic_init( &task->state, INIT_S );
129 atomic_init( &task->done, false );
131 task->preparser = preparser_;
132 task->input = input_CreatePreparser( preparser->owner, InputEvent,
133 task, req->item );
134 if( !task->input )
135 goto error;
137 task->req = req;
138 task->preparse_status = -1;
140 if( input_Start( task->input ) )
142 input_Close( task->input );
143 goto error;
146 *out = task;
148 return VLC_SUCCESS;
150 error:
151 free( task );
152 if (req->cbs && req->cbs->on_preparse_ended)
153 req->cbs->on_preparse_ended(req->item, ITEM_PREPARSE_FAILED, req->userdata);
154 return VLC_EGENERIC;
157 static int PreparserProbeInput( void* preparser_, void* task_ )
159 input_preparser_task_t* task = task_;
160 return atomic_load( &task->done );
161 VLC_UNUSED( preparser_ );
164 static void on_art_fetch_ended(input_item_t *item, bool fetched, void *userdata)
166 VLC_UNUSED(item);
167 VLC_UNUSED(fetched);
168 input_preparser_task_t *task = userdata;
169 input_preparser_req_t *req = task->req;
171 input_item_SetPreparsed(req->item, true);
173 if (req->cbs && req->cbs->on_preparse_ended)
174 req->cbs->on_preparse_ended(req->item, task->preparse_status, req->userdata);
176 ReqRelease(req);
177 free(task);
180 static const input_fetcher_callbacks_t input_fetcher_callbacks = {
181 .on_art_fetch_ended = on_art_fetch_ended,
184 static void PreparserCloseInput( void* preparser_, void* task_ )
186 input_preparser_task_t* task = task_;
187 input_preparser_req_t *req = task->req;
189 input_preparser_t* preparser = preparser_;
190 input_thread_t* input = task->input;
191 input_item_t* item = input_priv(task->input)->p_item;
193 int status;
194 switch( atomic_load( &task->state ) )
196 case END_S:
197 status = ITEM_PREPARSE_DONE;
198 break;
199 case ERROR_S:
200 status = ITEM_PREPARSE_FAILED;
201 break;
202 default:
203 status = ITEM_PREPARSE_TIMEOUT;
206 input_Stop( input );
207 input_Close( input );
209 if( preparser->fetcher )
211 task->preparse_status = status;
212 if (!input_fetcher_Push(preparser->fetcher, item, 0,
213 &input_fetcher_callbacks, task))
215 ReqHold(task->req);
216 return;
220 free(task);
222 input_item_SetPreparsed( item, true );
223 if (req->cbs && req->cbs->on_preparse_ended)
224 req->cbs->on_preparse_ended(req->item, status, req->userdata);
227 static void ReqHoldVoid(void *item) { ReqHold(item); }
228 static void ReqReleaseVoid(void *item) { ReqRelease(item); }
230 input_preparser_t* input_preparser_New( vlc_object_t *parent )
232 input_preparser_t* preparser = malloc( sizeof *preparser );
234 struct background_worker_config conf = {
235 .default_timeout = VLC_TICK_FROM_MS(var_InheritInteger( parent, "preparse-timeout" )),
236 .max_threads = var_InheritInteger( parent, "preparse-threads" ),
237 .pf_start = PreparserOpenInput,
238 .pf_probe = PreparserProbeInput,
239 .pf_stop = PreparserCloseInput,
240 .pf_release = ReqReleaseVoid,
241 .pf_hold = ReqHoldVoid
245 if( likely( preparser ) )
246 preparser->worker = background_worker_New( preparser, &conf );
248 if( unlikely( !preparser || !preparser->worker ) )
250 free( preparser );
251 return NULL;
254 preparser->owner = parent;
255 preparser->fetcher = input_fetcher_New( parent );
256 atomic_init( &preparser->deactivated, false );
258 if( unlikely( !preparser->fetcher ) )
259 msg_Warn( parent, "unable to create art fetcher" );
261 return preparser;
264 void input_preparser_Push( input_preparser_t *preparser,
265 input_item_t *item, input_item_meta_request_option_t i_options,
266 const input_preparser_callbacks_t *cbs, void *cbs_userdata,
267 int timeout, void *id )
269 if( atomic_load( &preparser->deactivated ) )
270 return;
272 vlc_mutex_lock( &item->lock );
273 enum input_item_type_e i_type = item->i_type;
274 int b_net = item->b_net;
275 vlc_mutex_unlock( &item->lock );
277 switch( i_type )
279 case ITEM_TYPE_NODE:
280 case ITEM_TYPE_FILE:
281 case ITEM_TYPE_DIRECTORY:
282 case ITEM_TYPE_PLAYLIST:
283 if( !b_net || i_options & META_REQUEST_OPTION_SCOPE_NETWORK )
284 break;
285 /* fallthrough */
286 default:
287 if (cbs && cbs->on_preparse_ended)
288 cbs->on_preparse_ended(item, ITEM_PREPARSE_SKIPPED, cbs_userdata);
289 return;
292 struct input_preparser_req_t *req = ReqCreate(item, cbs, cbs_userdata);
294 if (background_worker_Push(preparser->worker, req, id, timeout))
295 if (req->cbs && cbs->on_preparse_ended)
296 cbs->on_preparse_ended(item, ITEM_PREPARSE_FAILED, cbs_userdata);
298 ReqRelease(req);
301 void input_preparser_fetcher_Push( input_preparser_t *preparser,
302 input_item_t *item, input_item_meta_request_option_t options,
303 const input_fetcher_callbacks_t *cbs, void *cbs_userdata )
305 if( preparser->fetcher )
306 input_fetcher_Push( preparser->fetcher, item, options,
307 cbs, cbs_userdata );
310 void input_preparser_Cancel( input_preparser_t *preparser, void *id )
312 background_worker_Cancel( preparser->worker, id );
315 void input_preparser_Deactivate( input_preparser_t* preparser )
317 atomic_store( &preparser->deactivated, true );
318 background_worker_Cancel( preparser->worker, NULL );
321 void input_preparser_Delete( input_preparser_t *preparser )
323 background_worker_Delete( preparser->worker );
325 if( preparser->fetcher )
326 input_fetcher_Delete( preparser->fetcher );
328 free( preparser );