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
23 #include "wine/list.h"
27 /* gstreamer calls our callbacks from threads that Wine did not create. Some
28 * callbacks execute code which requires Wine to have created the thread
29 * (critical sections, debug logging, dshow client code). Since gstreamer can't
30 * provide an API to override its thread creation, we have to intercept all
31 * callbacks in code which avoids the Wine thread requirement, and then
32 * dispatch those callbacks on a thread that is known to be created by Wine.
34 * This file must not contain any code that depends on the Wine TEB!
37 static void call_cb(struct cb_data
*cbdata
)
39 pthread_mutex_init(&cbdata
->lock
, NULL
);
40 pthread_cond_init(&cbdata
->cond
, NULL
);
44 /* The thread which triggered gstreamer to call this callback may
45 * already hold a critical section. If so, executing the callback on a
46 * worker thread can cause a deadlock. If we are already on a Wine
47 * thread, then there is no need to run this callback on a worker
48 * thread anyway, which avoids the deadlock issue. */
49 perform_cb(NULL
, cbdata
);
51 pthread_cond_destroy(&cbdata
->cond
);
52 pthread_mutex_destroy(&cbdata
->lock
);
57 pthread_mutex_lock(&cb_list_lock
);
59 list_add_tail(&cb_list
, &cbdata
->entry
);
60 pthread_cond_broadcast(&cb_list_cond
);
62 pthread_mutex_lock(&cbdata
->lock
);
64 pthread_mutex_unlock(&cb_list_lock
);
66 while(!cbdata
->finished
)
67 pthread_cond_wait(&cbdata
->cond
, &cbdata
->lock
);
69 pthread_mutex_unlock(&cbdata
->lock
);
71 pthread_cond_destroy(&cbdata
->cond
);
72 pthread_mutex_destroy(&cbdata
->lock
);
75 GstBusSyncReply
watch_bus_wrapper(GstBus
*bus
, GstMessage
*msg
, gpointer user
)
77 struct cb_data cbdata
= { WATCH_BUS
};
79 cbdata
.u
.watch_bus_data
.bus
= bus
;
80 cbdata
.u
.watch_bus_data
.msg
= msg
;
81 cbdata
.u
.watch_bus_data
.user
= user
;
85 return cbdata
.u
.watch_bus_data
.ret
;
88 void existing_new_pad_wrapper(GstElement
*bin
, GstPad
*pad
, gpointer user
)
90 struct cb_data cbdata
= { EXISTING_NEW_PAD
};
92 cbdata
.u
.existing_new_pad_data
.bin
= bin
;
93 cbdata
.u
.existing_new_pad_data
.pad
= pad
;
94 cbdata
.u
.existing_new_pad_data
.user
= user
;
99 gboolean
query_function_wrapper(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
101 struct cb_data cbdata
= { QUERY_FUNCTION
};
103 cbdata
.u
.query_function_data
.pad
= pad
;
104 cbdata
.u
.query_function_data
.parent
= parent
;
105 cbdata
.u
.query_function_data
.query
= query
;
109 return cbdata
.u
.query_function_data
.ret
;
112 gboolean
activate_mode_wrapper(GstPad
*pad
, GstObject
*parent
, GstPadMode mode
, gboolean activate
)
114 struct cb_data cbdata
= { ACTIVATE_MODE
};
116 cbdata
.u
.activate_mode_data
.pad
= pad
;
117 cbdata
.u
.activate_mode_data
.parent
= parent
;
118 cbdata
.u
.activate_mode_data
.mode
= mode
;
119 cbdata
.u
.activate_mode_data
.activate
= activate
;
123 return cbdata
.u
.activate_mode_data
.ret
;
126 void no_more_pads_wrapper(GstElement
*decodebin
, gpointer user
)
128 struct cb_data cbdata
= { NO_MORE_PADS
};
130 cbdata
.u
.no_more_pads_data
.decodebin
= decodebin
;
131 cbdata
.u
.no_more_pads_data
.user
= user
;
136 GstFlowReturn
request_buffer_src_wrapper(GstPad
*pad
, GstObject
*parent
, guint64 ofs
, guint len
,
139 struct cb_data cbdata
= { REQUEST_BUFFER_SRC
};
141 cbdata
.u
.request_buffer_src_data
.pad
= pad
;
142 cbdata
.u
.request_buffer_src_data
.parent
= parent
;
143 cbdata
.u
.request_buffer_src_data
.ofs
= ofs
;
144 cbdata
.u
.request_buffer_src_data
.len
= len
;
145 cbdata
.u
.request_buffer_src_data
.buf
= buf
;
149 return cbdata
.u
.request_buffer_src_data
.ret
;
152 gboolean
event_src_wrapper(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
154 struct cb_data cbdata
= { EVENT_SRC
};
156 cbdata
.u
.event_src_data
.pad
= pad
;
157 cbdata
.u
.event_src_data
.parent
= parent
;
158 cbdata
.u
.event_src_data
.event
= event
;
162 return cbdata
.u
.event_src_data
.ret
;
165 gboolean
event_sink_wrapper(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
167 struct cb_data cbdata
= { EVENT_SINK
};
169 cbdata
.u
.event_sink_data
.pad
= pad
;
170 cbdata
.u
.event_sink_data
.parent
= parent
;
171 cbdata
.u
.event_sink_data
.event
= event
;
175 return cbdata
.u
.event_sink_data
.ret
;
178 GstFlowReturn
got_data_sink_wrapper(GstPad
*pad
, GstObject
*parent
, GstBuffer
*buf
)
180 struct cb_data cbdata
= { GOT_DATA_SINK
};
182 cbdata
.u
.got_data_sink_data
.pad
= pad
;
183 cbdata
.u
.got_data_sink_data
.parent
= parent
;
184 cbdata
.u
.got_data_sink_data
.buf
= buf
;
188 return cbdata
.u
.got_data_sink_data
.ret
;
191 GstFlowReturn
got_data_wrapper(GstPad
*pad
, GstObject
*parent
, GstBuffer
*buf
)
193 struct cb_data cbdata
= { GOT_DATA
};
195 cbdata
.u
.got_data_data
.pad
= pad
;
196 cbdata
.u
.got_data_data
.parent
= parent
;
197 cbdata
.u
.got_data_data
.buf
= buf
;
201 return cbdata
.u
.got_data_data
.ret
;
204 void removed_decoded_pad_wrapper(GstElement
*bin
, GstPad
*pad
, gpointer user
)
206 struct cb_data cbdata
= { REMOVED_DECODED_PAD
};
208 cbdata
.u
.removed_decoded_pad_data
.bin
= bin
;
209 cbdata
.u
.removed_decoded_pad_data
.pad
= pad
;
210 cbdata
.u
.removed_decoded_pad_data
.user
= user
;
215 GstAutoplugSelectResult
autoplug_blacklist_wrapper(GstElement
*bin
, GstPad
*pad
,
216 GstCaps
*caps
, GstElementFactory
*fact
, gpointer user
)
218 struct cb_data cbdata
= { AUTOPLUG_BLACKLIST
};
220 cbdata
.u
.autoplug_blacklist_data
.bin
= bin
;
221 cbdata
.u
.autoplug_blacklist_data
.pad
= pad
;
222 cbdata
.u
.autoplug_blacklist_data
.caps
= caps
;
223 cbdata
.u
.autoplug_blacklist_data
.fact
= fact
;
224 cbdata
.u
.autoplug_blacklist_data
.user
= user
;
228 return cbdata
.u
.autoplug_blacklist_data
.ret
;
231 void unknown_type_wrapper(GstElement
*bin
, GstPad
*pad
, GstCaps
*caps
, gpointer user
)
233 struct cb_data cbdata
= { UNKNOWN_TYPE
};
235 cbdata
.u
.unknown_type_data
.bin
= bin
;
236 cbdata
.u
.unknown_type_data
.pad
= pad
;
237 cbdata
.u
.unknown_type_data
.caps
= caps
;
238 cbdata
.u
.unknown_type_data
.user
= user
;
243 void release_sample_wrapper(gpointer data
)
245 struct cb_data cbdata
= { RELEASE_SAMPLE
};
247 cbdata
.u
.release_sample_data
.data
= data
;
252 void Gstreamer_transform_pad_added_wrapper(GstElement
*filter
, GstPad
*pad
, gpointer user
)
254 struct cb_data cbdata
= { TRANSFORM_PAD_ADDED
};
256 cbdata
.u
.transform_pad_added_data
.filter
= filter
;
257 cbdata
.u
.transform_pad_added_data
.pad
= pad
;
258 cbdata
.u
.transform_pad_added_data
.user
= user
;
263 gboolean
query_sink_wrapper(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
265 struct cb_data cbdata
= { QUERY_SINK
};
267 cbdata
.u
.query_sink_data
.pad
= pad
;
268 cbdata
.u
.query_sink_data
.parent
= parent
;
269 cbdata
.u
.query_sink_data
.query
= query
;
273 return cbdata
.u
.query_sink_data
.ret
;