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
25 #include "wine/list.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
);
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
);
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
);
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
);
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
;
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
;
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
;
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
;
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
;
200 GstFlowReturn
request_buffer_src_wrapper(GstPad
*pad
, GstObject
*parent
, guint64 ofs
, guint len
,
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
304 return cbdata
.u
.query_sink_data
.ret
;
307 GstFlowReturn
bytestream_wrapper_pull_wrapper(GstPad
*pad
, GstObject
*parent
, guint64 ofs
, guint len
,
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;