1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright © 2017-2017 VLC authors and VideoLAN
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 *****************************************************************************/
26 #include <vlc_common.h>
27 #include <vlc_atomic.h>
29 #include "misc/background_worker.h"
30 #include "input/input_interface.h"
31 #include "input/input_internal.h"
32 #include "preparser.h"
35 struct input_preparser_t
38 input_fetcher_t
* fetcher
;
39 struct background_worker
* worker
;
40 atomic_bool deactivated
;
43 typedef struct input_preparser_req_t
46 const input_preparser_callbacks_t
*cbs
;
49 } input_preparser_req_t
;
51 typedef struct input_preparser_task_t
53 input_preparser_req_t
*req
;
54 input_preparser_t
* preparser
;
56 input_thread_t
* input
;
59 } input_preparser_task_t
;
61 static input_preparser_req_t
*ReqCreate(input_item_t
*item
,
62 const input_preparser_callbacks_t
*cbs
,
65 input_preparser_req_t
*req
= malloc(sizeof(*req
));
71 req
->userdata
= userdata
;
72 vlc_atomic_rc_init(&req
->rc
);
74 input_item_Hold(item
);
79 static void ReqHold(input_preparser_req_t
*req
)
81 vlc_atomic_rc_inc(&req
->rc
);
84 static void ReqRelease(input_preparser_req_t
*req
)
86 if (vlc_atomic_rc_dec(&req
->rc
))
88 input_item_Release(req
->item
);
93 static void InputEvent( input_thread_t
*input
,
94 const struct vlc_input_event
*event
, void *task_
)
97 input_preparser_task_t
* task
= task_
;
101 case INPUT_EVENT_STATE
:
102 atomic_store( &task
->state
, event
->state
);
105 case INPUT_EVENT_DEAD
:
106 atomic_store( &task
->done
, true );
107 background_worker_RequestProbe( task
->preparser
->worker
);
109 case INPUT_EVENT_SUBITEMS
:
111 input_preparser_req_t
*req
= task
->req
;
112 if (req
->cbs
&& req
->cbs
->on_subtree_added
)
113 req
->cbs
->on_subtree_added(req
->item
, event
->subitems
, req
->userdata
);
120 static int PreparserOpenInput( void* preparser_
, void* req_
, void** out
)
122 input_preparser_t
* preparser
= preparser_
;
123 input_preparser_req_t
*req
= req_
;
124 input_preparser_task_t
* task
= malloc( sizeof *task
);
126 if( unlikely( !task
) )
129 atomic_init( &task
->state
, INIT_S
);
130 atomic_init( &task
->done
, false );
132 task
->preparser
= preparser_
;
133 task
->input
= input_CreatePreparser( preparser
->owner
, InputEvent
,
139 task
->preparse_status
= -1;
141 if( input_Start( task
->input
) )
143 input_Close( task
->input
);
153 if (req
->cbs
&& req
->cbs
->on_preparse_ended
)
154 req
->cbs
->on_preparse_ended(req
->item
, ITEM_PREPARSE_FAILED
, req
->userdata
);
158 static int PreparserProbeInput( void* preparser_
, void* task_
)
160 input_preparser_task_t
* task
= task_
;
161 return atomic_load( &task
->done
);
162 VLC_UNUSED( preparser_
);
165 static void on_art_fetch_ended(input_item_t
*item
, bool fetched
, void *userdata
)
169 input_preparser_task_t
*task
= userdata
;
170 input_preparser_req_t
*req
= task
->req
;
172 input_item_SetPreparsed(req
->item
, true);
174 if (req
->cbs
&& req
->cbs
->on_preparse_ended
)
175 req
->cbs
->on_preparse_ended(req
->item
, task
->preparse_status
, req
->userdata
);
181 static const input_fetcher_callbacks_t input_fetcher_callbacks
= {
182 .on_art_fetch_ended
= on_art_fetch_ended
,
185 static void PreparserCloseInput( void* preparser_
, void* task_
)
187 input_preparser_task_t
* task
= task_
;
188 input_preparser_req_t
*req
= task
->req
;
190 input_preparser_t
* preparser
= preparser_
;
191 input_thread_t
* input
= task
->input
;
192 input_item_t
* item
= input_priv(task
->input
)->p_item
;
195 switch( atomic_load( &task
->state
) )
198 status
= ITEM_PREPARSE_DONE
;
201 status
= ITEM_PREPARSE_FAILED
;
204 status
= ITEM_PREPARSE_TIMEOUT
;
208 input_Close( input
);
210 if( preparser
->fetcher
)
212 task
->preparse_status
= status
;
213 if (!input_fetcher_Push(preparser
->fetcher
, item
, 0,
214 &input_fetcher_callbacks
, task
))
223 input_item_SetPreparsed( item
, true );
224 if (req
->cbs
&& req
->cbs
->on_preparse_ended
)
225 req
->cbs
->on_preparse_ended(req
->item
, status
, req
->userdata
);
228 static void ReqHoldVoid(void *item
) { ReqHold(item
); }
229 static void ReqReleaseVoid(void *item
) { ReqRelease(item
); }
231 input_preparser_t
* input_preparser_New( vlc_object_t
*parent
)
233 input_preparser_t
* preparser
= malloc( sizeof *preparser
);
235 struct background_worker_config conf
= {
236 .default_timeout
= VLC_TICK_FROM_MS(var_InheritInteger( parent
, "preparse-timeout" )),
237 .max_threads
= var_InheritInteger( parent
, "preparse-threads" ),
238 .pf_start
= PreparserOpenInput
,
239 .pf_probe
= PreparserProbeInput
,
240 .pf_stop
= PreparserCloseInput
,
241 .pf_release
= ReqReleaseVoid
,
242 .pf_hold
= ReqHoldVoid
246 if( likely( preparser
) )
247 preparser
->worker
= background_worker_New( preparser
, &conf
);
249 if( unlikely( !preparser
|| !preparser
->worker
) )
255 preparser
->owner
= parent
;
256 preparser
->fetcher
= input_fetcher_New( parent
);
257 atomic_init( &preparser
->deactivated
, false );
259 if( unlikely( !preparser
->fetcher
) )
260 msg_Warn( parent
, "unable to create art fetcher" );
265 void input_preparser_Push( input_preparser_t
*preparser
,
266 input_item_t
*item
, input_item_meta_request_option_t i_options
,
267 const input_preparser_callbacks_t
*cbs
, void *cbs_userdata
,
268 int timeout
, void *id
)
270 if( atomic_load( &preparser
->deactivated
) )
273 vlc_mutex_lock( &item
->lock
);
274 enum input_item_type_e i_type
= item
->i_type
;
275 int b_net
= item
->b_net
;
276 vlc_mutex_unlock( &item
->lock
);
282 case ITEM_TYPE_DIRECTORY
:
283 case ITEM_TYPE_PLAYLIST
:
284 if( !b_net
|| i_options
& META_REQUEST_OPTION_SCOPE_NETWORK
)
288 if (cbs
&& cbs
->on_preparse_ended
)
289 cbs
->on_preparse_ended(item
, ITEM_PREPARSE_SKIPPED
, cbs_userdata
);
293 struct input_preparser_req_t
*req
= ReqCreate(item
, cbs
, cbs_userdata
);
295 if (background_worker_Push(preparser
->worker
, req
, id
, timeout
))
296 if (req
->cbs
&& cbs
->on_preparse_ended
)
297 cbs
->on_preparse_ended(item
, ITEM_PREPARSE_FAILED
, cbs_userdata
);
302 void input_preparser_fetcher_Push( input_preparser_t
*preparser
,
303 input_item_t
*item
, input_item_meta_request_option_t options
,
304 const input_fetcher_callbacks_t
*cbs
, void *cbs_userdata
)
306 if( preparser
->fetcher
)
307 input_fetcher_Push( preparser
->fetcher
, item
, options
,
311 void input_preparser_Cancel( input_preparser_t
*preparser
, void *id
)
313 background_worker_Cancel( preparser
->worker
, id
);
316 void input_preparser_Deactivate( input_preparser_t
* preparser
)
318 atomic_store( &preparser
->deactivated
, true );
319 background_worker_Cancel( preparser
->worker
, NULL
);
322 void input_preparser_Delete( input_preparser_t
*preparser
)
324 background_worker_Delete( preparser
->worker
);
326 if( preparser
->fetcher
)
327 input_fetcher_Delete( preparser
->fetcher
);