mscms/tests: Inline a simple string.
[wine.git] / dlls / winegstreamer / gst_cbs.c
blob51aaefa911d5c5de585a2067873c53ceb66bc297
1 /*
2 * Copyright 2015 Andrew Eikum for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
21 #include <gst/gst.h>
23 #include "objbase.h"
25 #include "wine/list.h"
27 #include "gst_cbs.h"
29 static pthread_key_t wine_gst_key;
31 void mark_wine_thread(void)
33 /* set it to non-NULL to indicate that this is a Wine thread */
34 pthread_setspecific(wine_gst_key, &wine_gst_key);
37 static BOOL is_wine_thread(void)
39 return pthread_getspecific(wine_gst_key) != NULL;
42 static pthread_mutex_t cb_list_lock = PTHREAD_MUTEX_INITIALIZER;
43 static pthread_cond_t cb_list_cond = PTHREAD_COND_INITIALIZER;
44 static struct list cb_list = LIST_INIT(cb_list);
46 static void CALLBACK perform_cb(TP_CALLBACK_INSTANCE *instance, void *user)
48 struct cb_data *cbdata = user;
50 if (cbdata->type < GSTDEMUX_MAX)
51 perform_cb_gstdemux(cbdata);
52 else if (cbdata->type < MEDIA_SOURCE_MAX)
53 perform_cb_media_source(cbdata);
55 pthread_mutex_lock(&cbdata->lock);
56 cbdata->finished = 1;
57 pthread_cond_broadcast(&cbdata->cond);
58 pthread_mutex_unlock(&cbdata->lock);
61 static DWORD WINAPI dispatch_thread(void *user)
63 struct cb_data *cbdata;
65 CoInitializeEx(NULL, COINIT_MULTITHREADED);
67 pthread_mutex_lock(&cb_list_lock);
69 while (1)
71 while (list_empty(&cb_list)) pthread_cond_wait(&cb_list_cond, &cb_list_lock);
73 cbdata = LIST_ENTRY(list_head(&cb_list), struct cb_data, entry);
74 list_remove(&cbdata->entry);
75 TrySubmitThreadpoolCallback(&perform_cb, cbdata, NULL);
78 pthread_mutex_unlock(&cb_list_lock);
80 CoUninitialize();
82 return 0;
85 void start_dispatch_thread(void)
87 pthread_key_create(&wine_gst_key, NULL);
88 CloseHandle(CreateThread(NULL, 0, &dispatch_thread, NULL, 0, NULL));
91 /* gstreamer calls our callbacks from threads that Wine did not create. Some
92 * callbacks execute code which requires Wine to have created the thread
93 * (critical sections, debug logging, dshow client code). Since gstreamer can't
94 * provide an API to override its thread creation, we have to intercept all
95 * callbacks in code which avoids the Wine thread requirement, and then
96 * dispatch those callbacks on a thread that is known to be created by Wine.
98 * This thread must not run any code that depends on the Wine TEB!
101 static void call_cb(struct cb_data *cbdata)
103 pthread_mutex_init(&cbdata->lock, NULL);
104 pthread_cond_init(&cbdata->cond, NULL);
105 cbdata->finished = 0;
107 if(is_wine_thread()){
108 /* The thread which triggered gstreamer to call this callback may
109 * already hold a critical section. If so, executing the callback on a
110 * worker thread can cause a deadlock. If we are already on a Wine
111 * thread, then there is no need to run this callback on a worker
112 * thread anyway, which avoids the deadlock issue. */
113 perform_cb(NULL, cbdata);
115 pthread_cond_destroy(&cbdata->cond);
116 pthread_mutex_destroy(&cbdata->lock);
118 return;
121 pthread_mutex_lock(&cb_list_lock);
123 list_add_tail(&cb_list, &cbdata->entry);
124 pthread_cond_broadcast(&cb_list_cond);
126 pthread_mutex_lock(&cbdata->lock);
128 pthread_mutex_unlock(&cb_list_lock);
130 while(!cbdata->finished)
131 pthread_cond_wait(&cbdata->cond, &cbdata->lock);
133 pthread_mutex_unlock(&cbdata->lock);
135 pthread_cond_destroy(&cbdata->cond);
136 pthread_mutex_destroy(&cbdata->lock);
139 GstBusSyncReply watch_bus_wrapper(GstBus *bus, GstMessage *msg, gpointer user)
141 struct cb_data cbdata = { WATCH_BUS };
143 cbdata.u.watch_bus_data.bus = bus;
144 cbdata.u.watch_bus_data.msg = msg;
145 cbdata.u.watch_bus_data.user = user;
147 call_cb(&cbdata);
149 return cbdata.u.watch_bus_data.ret;
152 void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user)
154 struct cb_data cbdata = { EXISTING_NEW_PAD };
156 cbdata.u.pad_added_data.element = bin;
157 cbdata.u.pad_added_data.pad = pad;
158 cbdata.u.pad_added_data.user = user;
160 call_cb(&cbdata);
163 gboolean query_function_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
165 struct cb_data cbdata = { QUERY_FUNCTION };
167 cbdata.u.query_function_data.pad = pad;
168 cbdata.u.query_function_data.parent = parent;
169 cbdata.u.query_function_data.query = query;
171 call_cb(&cbdata);
173 return cbdata.u.query_function_data.ret;
176 gboolean activate_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
178 struct cb_data cbdata = { ACTIVATE_MODE };
180 cbdata.u.activate_mode_data.pad = pad;
181 cbdata.u.activate_mode_data.parent = parent;
182 cbdata.u.activate_mode_data.mode = mode;
183 cbdata.u.activate_mode_data.activate = activate;
185 call_cb(&cbdata);
187 return cbdata.u.activate_mode_data.ret;
190 void no_more_pads_wrapper(GstElement *element, gpointer user)
192 struct cb_data cbdata = { NO_MORE_PADS };
194 cbdata.u.no_more_pads_data.element = element;
195 cbdata.u.no_more_pads_data.user = user;
197 call_cb(&cbdata);
200 GstFlowReturn request_buffer_src_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
201 GstBuffer **buf)
203 struct cb_data cbdata = { REQUEST_BUFFER_SRC };
205 cbdata.u.getrange_data.pad = pad;
206 cbdata.u.getrange_data.parent = parent;
207 cbdata.u.getrange_data.ofs = ofs;
208 cbdata.u.getrange_data.len = len;
209 cbdata.u.getrange_data.buf = buf;
211 call_cb(&cbdata);
213 return cbdata.u.getrange_data.ret;
216 gboolean event_src_wrapper(GstPad *pad, GstObject *parent, GstEvent *event)
218 struct cb_data cbdata = { EVENT_SRC };
220 cbdata.u.event_src_data.pad = pad;
221 cbdata.u.event_src_data.parent = parent;
222 cbdata.u.event_src_data.event = event;
224 call_cb(&cbdata);
226 return cbdata.u.event_src_data.ret;
229 gboolean event_sink_wrapper(GstPad *pad, GstObject *parent, GstEvent *event)
231 struct cb_data cbdata = { EVENT_SINK };
233 cbdata.u.event_sink_data.pad = pad;
234 cbdata.u.event_sink_data.parent = parent;
235 cbdata.u.event_sink_data.event = event;
237 call_cb(&cbdata);
239 return cbdata.u.event_sink_data.ret;
242 GstFlowReturn got_data_sink_wrapper(GstPad *pad, GstObject *parent, GstBuffer *buf)
244 struct cb_data cbdata = { GOT_DATA_SINK };
246 cbdata.u.got_data_sink_data.pad = pad;
247 cbdata.u.got_data_sink_data.parent = parent;
248 cbdata.u.got_data_sink_data.buf = buf;
250 call_cb(&cbdata);
252 return cbdata.u.got_data_sink_data.ret;
255 void removed_decoded_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user)
257 struct cb_data cbdata = { REMOVED_DECODED_PAD };
259 cbdata.u.pad_removed_data.element = bin;
260 cbdata.u.pad_removed_data.pad = pad;
261 cbdata.u.pad_removed_data.user = user;
263 call_cb(&cbdata);
266 GstAutoplugSelectResult autoplug_blacklist_wrapper(GstElement *bin, GstPad *pad,
267 GstCaps *caps, GstElementFactory *fact, gpointer user)
269 struct cb_data cbdata = { AUTOPLUG_BLACKLIST };
271 cbdata.u.autoplug_blacklist_data.bin = bin;
272 cbdata.u.autoplug_blacklist_data.pad = pad;
273 cbdata.u.autoplug_blacklist_data.caps = caps;
274 cbdata.u.autoplug_blacklist_data.fact = fact;
275 cbdata.u.autoplug_blacklist_data.user = user;
277 call_cb(&cbdata);
279 return cbdata.u.autoplug_blacklist_data.ret;
282 void unknown_type_wrapper(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer user)
284 struct cb_data cbdata = { UNKNOWN_TYPE };
286 cbdata.u.unknown_type_data.bin = bin;
287 cbdata.u.unknown_type_data.pad = pad;
288 cbdata.u.unknown_type_data.caps = caps;
289 cbdata.u.unknown_type_data.user = user;
291 call_cb(&cbdata);
294 gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
296 struct cb_data cbdata = { QUERY_SINK };
298 cbdata.u.query_sink_data.pad = pad;
299 cbdata.u.query_sink_data.parent = parent;
300 cbdata.u.query_sink_data.query = query;
302 call_cb(&cbdata);
304 return cbdata.u.query_sink_data.ret;
307 GstFlowReturn bytestream_wrapper_pull_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
308 GstBuffer **buf)
310 struct cb_data cbdata = { BYTESTREAM_WRAPPER_PULL };
312 cbdata.u.getrange_data.pad = pad;
313 cbdata.u.getrange_data.parent = parent;
314 cbdata.u.getrange_data.ofs = ofs;
315 cbdata.u.getrange_data.len = len;
316 cbdata.u.getrange_data.buf = buf;
318 call_cb(&cbdata);
320 return cbdata.u.getrange_data.ret;
323 gboolean bytestream_query_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
325 struct cb_data cbdata = { BYTESTREAM_QUERY };
327 cbdata.u.query_function_data.pad = pad;
328 cbdata.u.query_function_data.parent = parent;
329 cbdata.u.query_function_data.query = query;
331 call_cb(&cbdata);
333 return cbdata.u.query_function_data.ret;
336 gboolean bytestream_pad_mode_activate_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
338 struct cb_data cbdata = { BYTESTREAM_PAD_MODE_ACTIVATE };
340 cbdata.u.activate_mode_data.pad = pad;
341 cbdata.u.activate_mode_data.parent = parent;
342 cbdata.u.activate_mode_data.mode = mode;
343 cbdata.u.activate_mode_data.activate = activate;
345 call_cb(&cbdata);
347 return cbdata.u.activate_mode_data.ret;
350 gboolean bytestream_pad_event_process_wrapper(GstPad *pad, GstObject *parent, GstEvent *event)
352 struct cb_data cbdata = { BYTESTREAM_PAD_EVENT_PROCESS };
354 cbdata.u.event_src_data.pad = pad;
355 cbdata.u.event_src_data.parent = parent;
356 cbdata.u.event_src_data.event = event;
358 call_cb(&cbdata);
360 return cbdata.u.event_src_data.ret;
363 GstBusSyncReply mf_src_bus_watch_wrapper(GstBus *bus, GstMessage *message, gpointer user)
365 struct cb_data cbdata = { MF_SRC_BUS_WATCH };
367 cbdata.u.watch_bus_data.bus = bus;
368 cbdata.u.watch_bus_data.msg = message;
369 cbdata.u.watch_bus_data.user = user;
371 call_cb(&cbdata);
373 return cbdata.u.watch_bus_data.ret;
376 void mf_src_stream_added_wrapper(GstElement *bin, GstPad *pad, gpointer user)
378 struct cb_data cbdata = { MF_SRC_STREAM_ADDED };
380 cbdata.u.pad_added_data.element = bin;
381 cbdata.u.pad_added_data.pad = pad;
382 cbdata.u.pad_added_data.user = user;
384 call_cb(&cbdata);
387 void mf_src_stream_removed_wrapper(GstElement *element, GstPad *pad, gpointer user)
389 struct cb_data cbdata = { MF_SRC_STREAM_REMOVED };
391 cbdata.u.pad_removed_data.element = element;
392 cbdata.u.pad_removed_data.pad = pad;
393 cbdata.u.pad_removed_data.user = user;
395 call_cb(&cbdata);
398 void mf_src_no_more_pads_wrapper(GstElement *element, gpointer user)
400 struct cb_data cbdata = { MF_SRC_NO_MORE_PADS };
402 cbdata.u.no_more_pads_data.element = element;
403 cbdata.u.no_more_pads_data.user = user;
405 call_cb(&cbdata);