1 /*****************************************************************************
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 *****************************************************************************/
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"
34 struct input_preparser_t
37 input_fetcher_t
* fetcher
;
38 struct background_worker
* worker
;
39 atomic_bool deactivated
;
42 typedef struct input_preparser_req_t
45 const input_preparser_callbacks_t
*cbs
;
48 } input_preparser_req_t
;
50 typedef struct input_preparser_task_t
52 input_preparser_req_t
*req
;
53 input_preparser_t
* preparser
;
55 input_thread_t
* input
;
58 } input_preparser_task_t
;
60 static input_preparser_req_t
*ReqCreate(input_item_t
*item
,
61 const input_preparser_callbacks_t
*cbs
,
64 input_preparser_req_t
*req
= malloc(sizeof(*req
));
70 req
->userdata
= userdata
;
71 vlc_atomic_rc_init(&req
->rc
);
73 input_item_Hold(item
);
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
);
92 static void InputEvent( input_thread_t
*input
,
93 const struct vlc_input_event
*event
, void *task_
)
96 input_preparser_task_t
* task
= task_
;
100 case INPUT_EVENT_STATE
:
101 atomic_store( &task
->state
, event
->state
);
104 case INPUT_EVENT_DEAD
:
105 atomic_store( &task
->done
, true );
106 background_worker_RequestProbe( task
->preparser
->worker
);
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
);
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
) )
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
,
138 task
->preparse_status
= -1;
140 if( input_Start( task
->input
) )
142 input_Close( task
->input
);
152 if (req
->cbs
&& req
->cbs
->on_preparse_ended
)
153 req
->cbs
->on_preparse_ended(req
->item
, ITEM_PREPARSE_FAILED
, req
->userdata
);
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
)
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
);
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
;
194 switch( atomic_load( &task
->state
) )
197 status
= ITEM_PREPARSE_DONE
;
200 status
= ITEM_PREPARSE_FAILED
;
203 status
= ITEM_PREPARSE_TIMEOUT
;
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
))
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
) )
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" );
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
) )
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
);
281 case ITEM_TYPE_DIRECTORY
:
282 case ITEM_TYPE_PLAYLIST
:
283 if( !b_net
|| i_options
& META_REQUEST_OPTION_SCOPE_NETWORK
)
287 if (cbs
&& cbs
->on_preparse_ended
)
288 cbs
->on_preparse_ended(item
, ITEM_PREPARSE_SKIPPED
, cbs_userdata
);
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
);
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
,
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
);