wined3d: Move swapchain buffer discarding to wined3d_cs_exec_present().
[wine.git] / dlls / winegstreamer / gst_cbs.c
blobbf7103b1606bbad2b8975d5f1869e01fa7cea99e
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);
53 pthread_mutex_lock(&cbdata->lock);
54 cbdata->finished = 1;
55 pthread_cond_broadcast(&cbdata->cond);
56 pthread_mutex_unlock(&cbdata->lock);
59 static DWORD WINAPI dispatch_thread(void *user)
61 struct cb_data *cbdata;
63 CoInitializeEx(NULL, COINIT_MULTITHREADED);
65 pthread_mutex_lock(&cb_list_lock);
67 while (1)
69 while (list_empty(&cb_list)) pthread_cond_wait(&cb_list_cond, &cb_list_lock);
71 cbdata = LIST_ENTRY(list_head(&cb_list), struct cb_data, entry);
72 list_remove(&cbdata->entry);
73 TrySubmitThreadpoolCallback(&perform_cb, cbdata, NULL);
76 pthread_mutex_unlock(&cb_list_lock);
78 CoUninitialize();
80 return 0;
83 void start_dispatch_thread(void)
85 pthread_key_create(&wine_gst_key, NULL);
86 CloseHandle(CreateThread(NULL, 0, &dispatch_thread, NULL, 0, NULL));
89 /* gstreamer calls our callbacks from threads that Wine did not create. Some
90 * callbacks execute code which requires Wine to have created the thread
91 * (critical sections, debug logging, dshow client code). Since gstreamer can't
92 * provide an API to override its thread creation, we have to intercept all
93 * callbacks in code which avoids the Wine thread requirement, and then
94 * dispatch those callbacks on a thread that is known to be created by Wine.
96 * This thread must not run any code that depends on the Wine TEB!
99 static void call_cb(struct cb_data *cbdata)
101 pthread_mutex_init(&cbdata->lock, NULL);
102 pthread_cond_init(&cbdata->cond, NULL);
103 cbdata->finished = 0;
105 if(is_wine_thread()){
106 /* The thread which triggered gstreamer to call this callback may
107 * already hold a critical section. If so, executing the callback on a
108 * worker thread can cause a deadlock. If we are already on a Wine
109 * thread, then there is no need to run this callback on a worker
110 * thread anyway, which avoids the deadlock issue. */
111 perform_cb(NULL, cbdata);
113 pthread_cond_destroy(&cbdata->cond);
114 pthread_mutex_destroy(&cbdata->lock);
116 return;
119 pthread_mutex_lock(&cb_list_lock);
121 list_add_tail(&cb_list, &cbdata->entry);
122 pthread_cond_broadcast(&cb_list_cond);
124 pthread_mutex_lock(&cbdata->lock);
126 pthread_mutex_unlock(&cb_list_lock);
128 while(!cbdata->finished)
129 pthread_cond_wait(&cbdata->cond, &cbdata->lock);
131 pthread_mutex_unlock(&cbdata->lock);
133 pthread_cond_destroy(&cbdata->cond);
134 pthread_mutex_destroy(&cbdata->lock);
137 GstBusSyncReply watch_bus_wrapper(GstBus *bus, GstMessage *msg, gpointer user)
139 struct cb_data cbdata = { WATCH_BUS };
141 cbdata.u.watch_bus_data.bus = bus;
142 cbdata.u.watch_bus_data.msg = msg;
143 cbdata.u.watch_bus_data.user = user;
145 call_cb(&cbdata);
147 return cbdata.u.watch_bus_data.ret;
150 void existing_new_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user)
152 struct cb_data cbdata = { EXISTING_NEW_PAD };
154 cbdata.u.pad_added_data.element = bin;
155 cbdata.u.pad_added_data.pad = pad;
156 cbdata.u.pad_added_data.user = user;
158 call_cb(&cbdata);
161 gboolean query_function_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
163 struct cb_data cbdata = { QUERY_FUNCTION };
165 cbdata.u.query_function_data.pad = pad;
166 cbdata.u.query_function_data.parent = parent;
167 cbdata.u.query_function_data.query = query;
169 call_cb(&cbdata);
171 return cbdata.u.query_function_data.ret;
174 gboolean activate_mode_wrapper(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
176 struct cb_data cbdata = { ACTIVATE_MODE };
178 cbdata.u.activate_mode_data.pad = pad;
179 cbdata.u.activate_mode_data.parent = parent;
180 cbdata.u.activate_mode_data.mode = mode;
181 cbdata.u.activate_mode_data.activate = activate;
183 call_cb(&cbdata);
185 return cbdata.u.activate_mode_data.ret;
188 void no_more_pads_wrapper(GstElement *element, gpointer user)
190 struct cb_data cbdata = { NO_MORE_PADS };
192 cbdata.u.no_more_pads_data.element = element;
193 cbdata.u.no_more_pads_data.user = user;
195 call_cb(&cbdata);
198 GstFlowReturn request_buffer_src_wrapper(GstPad *pad, GstObject *parent, guint64 ofs, guint len,
199 GstBuffer **buf)
201 struct cb_data cbdata = { REQUEST_BUFFER_SRC };
203 cbdata.u.getrange_data.pad = pad;
204 cbdata.u.getrange_data.parent = parent;
205 cbdata.u.getrange_data.ofs = ofs;
206 cbdata.u.getrange_data.len = len;
207 cbdata.u.getrange_data.buf = buf;
209 call_cb(&cbdata);
211 return cbdata.u.getrange_data.ret;
214 gboolean event_src_wrapper(GstPad *pad, GstObject *parent, GstEvent *event)
216 struct cb_data cbdata = { EVENT_SRC };
218 cbdata.u.event_src_data.pad = pad;
219 cbdata.u.event_src_data.parent = parent;
220 cbdata.u.event_src_data.event = event;
222 call_cb(&cbdata);
224 return cbdata.u.event_src_data.ret;
227 gboolean event_sink_wrapper(GstPad *pad, GstObject *parent, GstEvent *event)
229 struct cb_data cbdata = { EVENT_SINK };
231 cbdata.u.event_sink_data.pad = pad;
232 cbdata.u.event_sink_data.parent = parent;
233 cbdata.u.event_sink_data.event = event;
235 call_cb(&cbdata);
237 return cbdata.u.event_sink_data.ret;
240 GstFlowReturn got_data_sink_wrapper(GstPad *pad, GstObject *parent, GstBuffer *buf)
242 struct cb_data cbdata = { GOT_DATA_SINK };
244 cbdata.u.got_data_sink_data.pad = pad;
245 cbdata.u.got_data_sink_data.parent = parent;
246 cbdata.u.got_data_sink_data.buf = buf;
248 call_cb(&cbdata);
250 return cbdata.u.got_data_sink_data.ret;
253 void removed_decoded_pad_wrapper(GstElement *bin, GstPad *pad, gpointer user)
255 struct cb_data cbdata = { REMOVED_DECODED_PAD };
257 cbdata.u.pad_removed_data.element = bin;
258 cbdata.u.pad_removed_data.pad = pad;
259 cbdata.u.pad_removed_data.user = user;
261 call_cb(&cbdata);
264 GstAutoplugSelectResult autoplug_blacklist_wrapper(GstElement *bin, GstPad *pad,
265 GstCaps *caps, GstElementFactory *fact, gpointer user)
267 struct cb_data cbdata = { AUTOPLUG_BLACKLIST };
269 cbdata.u.autoplug_blacklist_data.bin = bin;
270 cbdata.u.autoplug_blacklist_data.pad = pad;
271 cbdata.u.autoplug_blacklist_data.caps = caps;
272 cbdata.u.autoplug_blacklist_data.fact = fact;
273 cbdata.u.autoplug_blacklist_data.user = user;
275 call_cb(&cbdata);
277 return cbdata.u.autoplug_blacklist_data.ret;
280 void unknown_type_wrapper(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer user)
282 struct cb_data cbdata = { UNKNOWN_TYPE };
284 cbdata.u.unknown_type_data.bin = bin;
285 cbdata.u.unknown_type_data.pad = pad;
286 cbdata.u.unknown_type_data.caps = caps;
287 cbdata.u.unknown_type_data.user = user;
289 call_cb(&cbdata);
292 gboolean query_sink_wrapper(GstPad *pad, GstObject *parent, GstQuery *query)
294 struct cb_data cbdata = { QUERY_SINK };
296 cbdata.u.query_sink_data.pad = pad;
297 cbdata.u.query_sink_data.parent = parent;
298 cbdata.u.query_sink_data.query = query;
300 call_cb(&cbdata);
302 return cbdata.u.query_sink_data.ret;