demux: mp4: set bitmap mask when possible
[vlc.git] / src / preparser / preparser.c
blobb7497964d0b94180cde1c54e319719e5bd2d7e6b
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>
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"
33 #include "fetcher.h"
35 struct input_preparser_t
37 vlc_object_t* owner;
38 input_fetcher_t* fetcher;
39 struct background_worker* worker;
40 atomic_bool deactivated;
43 typedef struct input_preparser_req_t
45 input_item_t *item;
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_thread_t* input;
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 const input_preparser_callbacks_t *cbs,
63 void *userdata)
65 input_preparser_req_t *req = malloc(sizeof(*req));
66 if (unlikely(!req))
67 return NULL;
69 req->item = item;
70 req->cbs = cbs;
71 req->userdata = userdata;
72 vlc_atomic_rc_init(&req->rc);
74 input_item_Hold(item);
76 return req;
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);
89 free(req);
93 static void InputEvent( input_thread_t *input,
94 const struct vlc_input_event *event, void *task_ )
96 VLC_UNUSED( input );
97 input_preparser_task_t* task = task_;
99 switch( event->type )
101 case INPUT_EVENT_STATE:
102 atomic_store( &task->state, event->state );
103 break;
105 case INPUT_EVENT_DEAD:
106 atomic_store( &task->done, true );
107 background_worker_RequestProbe( task->preparser->worker );
108 break;
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);
114 break;
116 default: ;
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 ) )
127 goto error;
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,
134 task, req->item );
135 if( !task->input )
136 goto error;
138 task->req = req;
139 task->preparse_status = -1;
141 if( input_Start( task->input ) )
143 input_Close( task->input );
144 goto error;
147 *out = task;
149 return VLC_SUCCESS;
151 error:
152 free( task );
153 if (req->cbs && req->cbs->on_preparse_ended)
154 req->cbs->on_preparse_ended(req->item, ITEM_PREPARSE_FAILED, req->userdata);
155 return VLC_EGENERIC;
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)
167 VLC_UNUSED(item);
168 VLC_UNUSED(fetched);
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);
177 ReqRelease(req);
178 free(task);
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;
194 int status;
195 switch( atomic_load( &task->state ) )
197 case END_S:
198 status = ITEM_PREPARSE_DONE;
199 break;
200 case ERROR_S:
201 status = ITEM_PREPARSE_FAILED;
202 break;
203 default:
204 status = ITEM_PREPARSE_TIMEOUT;
207 input_Stop( input );
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))
216 ReqHold(task->req);
217 return;
221 free(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 ) )
251 free( preparser );
252 return NULL;
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" );
262 return preparser;
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 ) )
271 return;
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 );
278 switch( i_type )
280 case ITEM_TYPE_NODE:
281 case ITEM_TYPE_FILE:
282 case ITEM_TYPE_DIRECTORY:
283 case ITEM_TYPE_PLAYLIST:
284 if( !b_net || i_options & META_REQUEST_OPTION_SCOPE_NETWORK )
285 break;
286 /* fallthrough */
287 default:
288 if (cbs && cbs->on_preparse_ended)
289 cbs->on_preparse_ended(item, ITEM_PREPARSE_SKIPPED, cbs_userdata);
290 return;
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);
299 ReqRelease(req);
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,
308 cbs, cbs_userdata );
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 );
329 free( preparser );