2 * GStreamer parser backend
4 * Copyright 2010 Maarten Lankhorst for CodeWeavers
5 * Copyright 2010 Aric Stewart for CodeWeavers
6 * Copyright 2019-2020 Zebediah Figura
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include <gst/video/video.h>
35 #include <gst/audio/audio.h>
40 #include "unix_private.h"
44 GST_AUTOPLUG_SELECT_TRY
,
45 GST_AUTOPLUG_SELECT_EXPOSE
,
46 GST_AUTOPLUG_SELECT_SKIP
,
47 } GstAutoplugSelectResult
;
49 /* GStreamer callbacks may be called on threads not created by Wine, and
50 * therefore cannot access the Wine TEB. This means that we must use GStreamer
51 * debug logging instead of Wine debug logging. In order to be safe we forbid
52 * any use of Wine debug logging in this entire file. */
54 GST_DEBUG_CATEGORY(wine
);
55 #define GST_CAT_DEFAULT wine
57 typedef BOOL (*init_gst_cb
)(struct wg_parser
*parser
);
63 struct wg_parser_stream
**streams
;
64 unsigned int stream_count
;
66 GstElement
*container
, *decodebin
;
68 GstPad
*my_src
, *their_sink
;
70 guint64 file_size
, start_offset
, next_offset
, stop_offset
;
71 guint64 next_pull_offset
;
73 pthread_t push_thread
;
75 pthread_mutex_t mutex
;
77 pthread_cond_t init_cond
;
78 bool no_more_pads
, has_duration
, error
;
80 pthread_cond_t read_cond
, read_done_cond
;
92 bool unlimited_buffering
;
95 struct wg_parser_stream
97 struct wg_parser
*parser
;
99 GstPad
*their_src
, *post_sink
, *post_src
, *my_sink
;
102 struct wg_format preferred_format
, current_format
;
104 pthread_cond_t event_cond
, event_empty_cond
;
108 bool flushing
, eos
, enabled
, has_caps
;
113 static NTSTATUS
wg_parser_get_stream_count(void *args
)
115 struct wg_parser_get_stream_count_params
*params
= args
;
117 params
->count
= params
->parser
->stream_count
;
121 static NTSTATUS
wg_parser_get_stream(void *args
)
123 struct wg_parser_get_stream_params
*params
= args
;
125 params
->stream
= params
->parser
->streams
[params
->index
];
129 static NTSTATUS
wg_parser_get_next_read_offset(void *args
)
131 struct wg_parser_get_next_read_offset_params
*params
= args
;
132 struct wg_parser
*parser
= params
->parser
;
134 pthread_mutex_lock(&parser
->mutex
);
136 while (parser
->sink_connected
&& !parser
->read_request
.size
)
137 pthread_cond_wait(&parser
->read_cond
, &parser
->mutex
);
139 if (!parser
->sink_connected
)
141 pthread_mutex_unlock(&parser
->mutex
);
142 return VFW_E_WRONG_STATE
;
145 params
->offset
= parser
->read_request
.offset
;
146 params
->size
= parser
->read_request
.size
;
148 pthread_mutex_unlock(&parser
->mutex
);
152 static NTSTATUS
wg_parser_push_data(void *args
)
154 const struct wg_parser_push_data_params
*params
= args
;
155 struct wg_parser
*parser
= params
->parser
;
156 const void *data
= params
->data
;
157 uint32_t size
= params
->size
;
159 pthread_mutex_lock(&parser
->mutex
);
167 /* Note that we don't allocate the buffer until we have a size.
168 * midiparse passes a NULL buffer and a size of UINT_MAX, in an
169 * apparent attempt to read the whole input stream at once. */
170 if (!parser
->read_request
.buffer
)
171 parser
->read_request
.buffer
= gst_buffer_new_and_alloc(size
);
172 gst_buffer_map(parser
->read_request
.buffer
, &map_info
, GST_MAP_WRITE
);
173 memcpy(map_info
.data
, data
, size
);
174 gst_buffer_unmap(parser
->read_request
.buffer
, &map_info
);
175 parser
->read_request
.ret
= GST_FLOW_OK
;
179 parser
->read_request
.ret
= GST_FLOW_EOS
;
184 parser
->read_request
.ret
= GST_FLOW_ERROR
;
186 parser
->read_request
.done
= true;
187 parser
->read_request
.size
= 0;
189 pthread_mutex_unlock(&parser
->mutex
);
190 pthread_cond_signal(&parser
->read_done_cond
);
195 static NTSTATUS
wg_parser_stream_get_preferred_format(void *args
)
197 const struct wg_parser_stream_get_preferred_format_params
*params
= args
;
199 *params
->format
= params
->stream
->preferred_format
;
203 static NTSTATUS
wg_parser_stream_enable(void *args
)
205 const struct wg_parser_stream_enable_params
*params
= args
;
206 struct wg_parser_stream
*stream
= params
->stream
;
207 const struct wg_format
*format
= params
->format
;
209 stream
->current_format
= *format
;
210 stream
->enabled
= true;
212 if (format
->major_type
== WG_MAJOR_TYPE_VIDEO
)
214 bool flip
= (format
->u
.video
.height
< 0);
216 switch (format
->u
.video
.format
)
218 case WG_VIDEO_FORMAT_BGRA
:
219 case WG_VIDEO_FORMAT_BGRx
:
220 case WG_VIDEO_FORMAT_BGR
:
221 case WG_VIDEO_FORMAT_RGB15
:
222 case WG_VIDEO_FORMAT_RGB16
:
226 case WG_VIDEO_FORMAT_AYUV
:
227 case WG_VIDEO_FORMAT_I420
:
228 case WG_VIDEO_FORMAT_NV12
:
229 case WG_VIDEO_FORMAT_UYVY
:
230 case WG_VIDEO_FORMAT_YUY2
:
231 case WG_VIDEO_FORMAT_YV12
:
232 case WG_VIDEO_FORMAT_YVYU
:
233 case WG_VIDEO_FORMAT_UNKNOWN
:
234 case WG_VIDEO_FORMAT_CINEPAK
:
238 gst_util_set_object_arg(G_OBJECT(stream
->flip
), "method", flip
? "vertical-flip" : "none");
241 gst_pad_push_event(stream
->my_sink
, gst_event_new_reconfigure());
245 static NTSTATUS
wg_parser_stream_disable(void *args
)
247 struct wg_parser_stream
*stream
= args
;
249 stream
->enabled
= false;
253 static NTSTATUS
wg_parser_stream_get_buffer(void *args
)
255 const struct wg_parser_stream_get_buffer_params
*params
= args
;
256 struct wg_parser_buffer
*wg_buffer
= params
->buffer
;
257 struct wg_parser_stream
*stream
= params
->stream
;
258 struct wg_parser
*parser
= stream
->parser
;
261 pthread_mutex_lock(&parser
->mutex
);
263 while (!stream
->eos
&& !stream
->buffer
)
264 pthread_cond_wait(&stream
->event_cond
, &parser
->mutex
);
266 /* Note that we can both have a buffer and stream->eos, in which case we
267 * must return the buffer. */
268 if ((buffer
= stream
->buffer
))
270 /* FIXME: Should we use gst_segment_to_stream_time_full()? Under what
271 * circumstances is the stream time not equal to the buffer PTS? Note
272 * that this will need modification to wg_parser_stream_notify_qos() as
275 if ((wg_buffer
->has_pts
= GST_BUFFER_PTS_IS_VALID(buffer
)))
276 wg_buffer
->pts
= GST_BUFFER_PTS(buffer
) / 100;
277 if ((wg_buffer
->has_duration
= GST_BUFFER_DURATION_IS_VALID(buffer
)))
278 wg_buffer
->duration
= GST_BUFFER_DURATION(buffer
) / 100;
279 wg_buffer
->discontinuity
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_DISCONT
);
280 wg_buffer
->preroll
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_LIVE
);
281 wg_buffer
->delta
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_DELTA_UNIT
);
282 wg_buffer
->size
= gst_buffer_get_size(buffer
);
284 pthread_mutex_unlock(&parser
->mutex
);
288 pthread_mutex_unlock(&parser
->mutex
);
292 static NTSTATUS
wg_parser_stream_copy_buffer(void *args
)
294 const struct wg_parser_stream_copy_buffer_params
*params
= args
;
295 struct wg_parser_stream
*stream
= params
->stream
;
296 struct wg_parser
*parser
= stream
->parser
;
297 uint32_t offset
= params
->offset
;
298 uint32_t size
= params
->size
;
300 pthread_mutex_lock(&parser
->mutex
);
304 pthread_mutex_unlock(&parser
->mutex
);
305 return VFW_E_WRONG_STATE
;
308 assert(offset
< stream
->map_info
.size
);
309 assert(offset
+ size
<= stream
->map_info
.size
);
310 memcpy(params
->data
, stream
->map_info
.data
+ offset
, size
);
312 pthread_mutex_unlock(&parser
->mutex
);
316 static NTSTATUS
wg_parser_stream_release_buffer(void *args
)
318 struct wg_parser_stream
*stream
= args
;
319 struct wg_parser
*parser
= stream
->parser
;
321 pthread_mutex_lock(&parser
->mutex
);
323 assert(stream
->buffer
);
325 gst_buffer_unmap(stream
->buffer
, &stream
->map_info
);
326 gst_buffer_unref(stream
->buffer
);
327 stream
->buffer
= NULL
;
329 pthread_mutex_unlock(&parser
->mutex
);
330 pthread_cond_signal(&stream
->event_empty_cond
);
335 static NTSTATUS
wg_parser_stream_get_duration(void *args
)
337 struct wg_parser_stream_get_duration_params
*params
= args
;
339 params
->duration
= params
->stream
->duration
;
343 static NTSTATUS
wg_parser_stream_seek(void *args
)
345 GstSeekType start_type
= GST_SEEK_TYPE_SET
, stop_type
= GST_SEEK_TYPE_SET
;
346 const struct wg_parser_stream_seek_params
*params
= args
;
347 DWORD start_flags
= params
->start_flags
;
348 DWORD stop_flags
= params
->stop_flags
;
349 GstSeekFlags flags
= 0;
351 if (start_flags
& AM_SEEKING_SeekToKeyFrame
)
352 flags
|= GST_SEEK_FLAG_KEY_UNIT
;
353 if (start_flags
& AM_SEEKING_Segment
)
354 flags
|= GST_SEEK_FLAG_SEGMENT
;
355 if (!(start_flags
& AM_SEEKING_NoFlush
))
356 flags
|= GST_SEEK_FLAG_FLUSH
;
358 if ((start_flags
& AM_SEEKING_PositioningBitsMask
) == AM_SEEKING_NoPositioning
)
359 start_type
= GST_SEEK_TYPE_NONE
;
360 if ((stop_flags
& AM_SEEKING_PositioningBitsMask
) == AM_SEEKING_NoPositioning
)
361 stop_type
= GST_SEEK_TYPE_NONE
;
363 if (!gst_pad_push_event(params
->stream
->my_sink
, gst_event_new_seek(params
->rate
, GST_FORMAT_TIME
,
364 flags
, start_type
, params
->start_pos
* 100, stop_type
, params
->stop_pos
* 100)))
365 GST_ERROR("Failed to seek.\n");
370 static NTSTATUS
wg_parser_stream_notify_qos(void *args
)
372 const struct wg_parser_stream_notify_qos_params
*params
= args
;
373 struct wg_parser_stream
*stream
= params
->stream
;
374 GstClockTime stream_time
;
377 /* We return timestamps in stream time, i.e. relative to the start of the
378 * file (or other medium), but gst_event_new_qos() expects the timestamp in
380 stream_time
= gst_segment_to_running_time(&stream
->segment
, GST_FORMAT_TIME
, params
->timestamp
* 100);
381 if (stream_time
== -1)
383 /* This can happen legitimately if the sample falls outside of the
384 * segment bounds. GStreamer elements shouldn't present the sample in
385 * that case, but DirectShow doesn't care. */
386 GST_LOG("Ignoring QoS event.\n");
390 if (!(event
= gst_event_new_qos(params
->underflow
? GST_QOS_TYPE_UNDERFLOW
: GST_QOS_TYPE_OVERFLOW
,
391 params
->proportion
, params
->diff
* 100, stream_time
)))
392 GST_ERROR("Failed to create QOS event.\n");
393 gst_pad_push_event(stream
->my_sink
, event
);
398 static GstAutoplugSelectResult
autoplug_select_cb(GstElement
*bin
, GstPad
*pad
,
399 GstCaps
*caps
, GstElementFactory
*fact
, gpointer user
)
401 const char *name
= gst_element_factory_get_longname(fact
);
403 GST_INFO("Using \"%s\".", name
);
405 if (strstr(name
, "Player protection"))
407 GST_WARNING("Blacklisted a/52 decoder because it only works in Totem.");
408 return GST_AUTOPLUG_SELECT_SKIP
;
410 if (!strcmp(name
, "Fluendo Hardware Accelerated Video Decoder"))
412 GST_WARNING("Disabled video acceleration since it breaks in wine.");
413 return GST_AUTOPLUG_SELECT_SKIP
;
415 return GST_AUTOPLUG_SELECT_TRY
;
418 static void no_more_pads_cb(GstElement
*element
, gpointer user
)
420 struct wg_parser
*parser
= user
;
422 GST_DEBUG("parser %p.", parser
);
424 pthread_mutex_lock(&parser
->mutex
);
425 parser
->no_more_pads
= true;
426 pthread_mutex_unlock(&parser
->mutex
);
427 pthread_cond_signal(&parser
->init_cond
);
430 static gboolean
sink_event_cb(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
432 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
433 struct wg_parser
*parser
= stream
->parser
;
435 GST_LOG("stream %p, type \"%s\".", stream
, GST_EVENT_TYPE_NAME(event
));
439 case GST_EVENT_SEGMENT
:
442 const GstSegment
*segment
;
444 gst_event_parse_segment(event
, &segment
);
446 if (segment
->format
!= GST_FORMAT_TIME
)
448 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(segment
->format
));
452 gst_segment_copy_into(segment
, &stream
->segment
);
457 pthread_mutex_lock(&parser
->mutex
);
459 pthread_mutex_unlock(&parser
->mutex
);
461 pthread_cond_signal(&stream
->event_cond
);
463 pthread_cond_signal(&parser
->init_cond
);
466 case GST_EVENT_FLUSH_START
:
469 pthread_mutex_lock(&parser
->mutex
);
471 stream
->flushing
= true;
472 pthread_cond_signal(&stream
->event_empty_cond
);
476 gst_buffer_unmap(stream
->buffer
, &stream
->map_info
);
477 gst_buffer_unref(stream
->buffer
);
478 stream
->buffer
= NULL
;
481 pthread_mutex_unlock(&parser
->mutex
);
485 case GST_EVENT_FLUSH_STOP
:
489 gst_event_parse_flush_stop(event
, &reset_time
);
492 gst_segment_init(&stream
->segment
, GST_FORMAT_UNDEFINED
);
494 pthread_mutex_lock(&parser
->mutex
);
498 stream
->flushing
= false;
500 pthread_mutex_unlock(&parser
->mutex
);
508 gst_event_parse_caps(event
, &caps
);
509 pthread_mutex_lock(&parser
->mutex
);
510 wg_format_from_caps(&stream
->preferred_format
, caps
);
511 stream
->has_caps
= true;
512 pthread_mutex_unlock(&parser
->mutex
);
513 pthread_cond_signal(&parser
->init_cond
);
518 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
520 gst_event_unref(event
);
524 static GstFlowReturn
sink_chain_cb(GstPad
*pad
, GstObject
*parent
, GstBuffer
*buffer
)
526 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
527 struct wg_parser
*parser
= stream
->parser
;
529 GST_LOG("stream %p, buffer %p.", stream
, buffer
);
531 if (!stream
->enabled
)
533 gst_buffer_unref(buffer
);
537 /* Allow this buffer to be flushed by GStreamer. We are effectively
538 * implementing a queue object here. */
540 pthread_mutex_lock(&parser
->mutex
);
542 while (!stream
->flushing
&& stream
->buffer
)
543 pthread_cond_wait(&stream
->event_empty_cond
, &parser
->mutex
);
544 if (stream
->flushing
)
546 pthread_mutex_unlock(&parser
->mutex
);
547 GST_DEBUG("Stream is flushing; discarding buffer.");
548 gst_buffer_unref(buffer
);
549 return GST_FLOW_FLUSHING
;
552 if (!gst_buffer_map(buffer
, &stream
->map_info
, GST_MAP_READ
))
554 pthread_mutex_unlock(&parser
->mutex
);
555 GST_ERROR("Failed to map buffer.\n");
556 gst_buffer_unref(buffer
);
557 return GST_FLOW_ERROR
;
560 stream
->buffer
= buffer
;
562 pthread_mutex_unlock(&parser
->mutex
);
563 pthread_cond_signal(&stream
->event_cond
);
565 /* The chain callback is given a reference to the buffer. Transfer that
566 * reference to the stream object, which will release it in
567 * wg_parser_stream_release_buffer(). */
569 GST_LOG("Buffer queued.");
573 static gboolean
sink_query_cb(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
575 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
577 GST_LOG("stream %p, type \"%s\".", stream
, gst_query_type_get_name(query
->type
));
583 GstCaps
*caps
, *filter
, *temp
;
586 gst_query_parse_caps(query
, &filter
);
589 caps
= wg_format_to_caps(&stream
->current_format
);
591 caps
= gst_caps_new_any();
595 str
= gst_caps_to_string(caps
);
596 GST_LOG("Stream caps are \"%s\".", str
);
601 temp
= gst_caps_intersect(caps
, filter
);
602 gst_caps_unref(caps
);
606 gst_query_set_caps_result(query
, caps
);
607 gst_caps_unref(caps
);
611 case GST_QUERY_ACCEPT_CAPS
:
613 struct wg_format format
;
617 if (!stream
->enabled
)
619 gst_query_set_accept_caps_result(query
, TRUE
);
623 gst_query_parse_accept_caps(query
, &caps
);
624 wg_format_from_caps(&format
, caps
);
625 ret
= wg_format_compare(&format
, &stream
->current_format
);
626 if (!ret
&& gst_debug_category_get_threshold(GST_CAT_DEFAULT
) >= GST_LEVEL_WARNING
)
628 gchar
*str
= gst_caps_to_string(caps
);
629 GST_WARNING("Rejecting caps \"%s\".", str
);
632 gst_query_set_accept_caps_result(query
, ret
);
637 return gst_pad_query_default (pad
, parent
, query
);
641 GstElement
*create_element(const char *name
, const char *plugin_set
)
645 if (!(element
= gst_element_factory_make(name
, NULL
)))
646 fprintf(stderr
, "winegstreamer: failed to create %s, are %u-bit GStreamer \"%s\" plugins installed?\n",
647 name
, 8 * (unsigned int)sizeof(void *), plugin_set
);
651 static struct wg_parser_stream
*create_stream(struct wg_parser
*parser
)
653 struct wg_parser_stream
*stream
, **new_array
;
656 if (!(new_array
= realloc(parser
->streams
, (parser
->stream_count
+ 1) * sizeof(*parser
->streams
))))
658 parser
->streams
= new_array
;
660 if (!(stream
= calloc(1, sizeof(*stream
))))
663 gst_segment_init(&stream
->segment
, GST_FORMAT_UNDEFINED
);
665 stream
->parser
= parser
;
666 pthread_cond_init(&stream
->event_cond
, NULL
);
667 pthread_cond_init(&stream
->event_empty_cond
, NULL
);
669 sprintf(pad_name
, "qz_sink_%u", parser
->stream_count
);
670 stream
->my_sink
= gst_pad_new(pad_name
, GST_PAD_SINK
);
671 gst_pad_set_element_private(stream
->my_sink
, stream
);
672 gst_pad_set_chain_function(stream
->my_sink
, sink_chain_cb
);
673 gst_pad_set_event_function(stream
->my_sink
, sink_event_cb
);
674 gst_pad_set_query_function(stream
->my_sink
, sink_query_cb
);
676 parser
->streams
[parser
->stream_count
++] = stream
;
680 static void free_stream(struct wg_parser_stream
*stream
)
682 if (stream
->their_src
)
684 if (stream
->post_sink
)
686 gst_object_unref(stream
->post_src
);
687 gst_object_unref(stream
->post_sink
);
688 stream
->post_src
= stream
->post_sink
= NULL
;
690 gst_object_unref(stream
->their_src
);
692 gst_object_unref(stream
->my_sink
);
694 pthread_cond_destroy(&stream
->event_cond
);
695 pthread_cond_destroy(&stream
->event_empty_cond
);
700 static void pad_added_cb(GstElement
*element
, GstPad
*pad
, gpointer user
)
702 struct wg_parser
*parser
= user
;
703 struct wg_parser_stream
*stream
;
708 GST_LOG("parser %p, element %p, pad %p.", parser
, element
, pad
);
710 if (gst_pad_is_linked(pad
))
713 caps
= gst_pad_query_caps(pad
, NULL
);
714 name
= gst_structure_get_name(gst_caps_get_structure(caps
, 0));
716 if (!(stream
= create_stream(parser
)))
719 if (!strcmp(name
, "video/x-raw"))
721 GstElement
*deinterlace
, *vconv
, *flip
, *vconv2
;
723 /* DirectShow can express interlaced video, but downstream filters can't
724 * necessarily consume it. In particular, the video renderer can't. */
725 if (!(deinterlace
= create_element("deinterlace", "good")))
728 /* decodebin considers many YUV formats to be "raw", but some quartz
729 * filters can't handle those. Also, videoflip can't handle all "raw"
730 * formats either. Add a videoconvert to swap color spaces. */
731 if (!(vconv
= create_element("videoconvert", "base")))
734 /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
735 if (!(flip
= create_element("videoflip", "good")))
738 /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert
739 * to do the final conversion. */
740 if (!(vconv2
= create_element("videoconvert", "base")))
743 /* The bin takes ownership of these elements. */
744 gst_bin_add(GST_BIN(parser
->container
), deinterlace
);
745 gst_element_sync_state_with_parent(deinterlace
);
746 gst_bin_add(GST_BIN(parser
->container
), vconv
);
747 gst_element_sync_state_with_parent(vconv
);
748 gst_bin_add(GST_BIN(parser
->container
), flip
);
749 gst_element_sync_state_with_parent(flip
);
750 gst_bin_add(GST_BIN(parser
->container
), vconv2
);
751 gst_element_sync_state_with_parent(vconv2
);
753 gst_element_link(deinterlace
, vconv
);
754 gst_element_link(vconv
, flip
);
755 gst_element_link(flip
, vconv2
);
757 stream
->post_sink
= gst_element_get_static_pad(deinterlace
, "sink");
758 stream
->post_src
= gst_element_get_static_pad(vconv2
, "src");
761 else if (!strcmp(name
, "audio/x-raw"))
765 /* Currently our dsound can't handle 64-bit formats or all
766 * surround-sound configurations. Native dsound can't always handle
767 * 64-bit formats either. Add an audioconvert to allow changing bit
768 * depth and channel count. */
769 if (!(convert
= create_element("audioconvert", "base")))
772 gst_bin_add(GST_BIN(parser
->container
), convert
);
773 gst_element_sync_state_with_parent(convert
);
775 stream
->post_sink
= gst_element_get_static_pad(convert
, "sink");
776 stream
->post_src
= gst_element_get_static_pad(convert
, "src");
779 if (stream
->post_sink
)
781 if ((ret
= gst_pad_link(pad
, stream
->post_sink
)) < 0)
783 GST_ERROR("Failed to link decodebin source pad to post-processing elements, error %s.",
784 gst_pad_link_get_name(ret
));
785 gst_object_unref(stream
->post_sink
);
786 stream
->post_sink
= NULL
;
790 if ((ret
= gst_pad_link(stream
->post_src
, stream
->my_sink
)) < 0)
792 GST_ERROR("Failed to link post-processing elements to our sink pad, error %s.",
793 gst_pad_link_get_name(ret
));
794 gst_object_unref(stream
->post_src
);
795 stream
->post_src
= NULL
;
796 gst_object_unref(stream
->post_sink
);
797 stream
->post_sink
= NULL
;
801 else if ((ret
= gst_pad_link(pad
, stream
->my_sink
)) < 0)
803 GST_ERROR("Failed to link decodebin source pad to our sink pad, error %s.",
804 gst_pad_link_get_name(ret
));
808 gst_pad_set_active(stream
->my_sink
, 1);
809 gst_object_ref(stream
->their_src
= pad
);
811 gst_caps_unref(caps
);
814 static void pad_removed_cb(GstElement
*element
, GstPad
*pad
, gpointer user
)
816 struct wg_parser
*parser
= user
;
820 GST_LOG("parser %p, element %p, pad %p.", parser
, element
, pad
);
822 for (i
= 0; i
< parser
->stream_count
; ++i
)
824 struct wg_parser_stream
*stream
= parser
->streams
[i
];
826 if (stream
->their_src
== pad
)
828 if (stream
->post_sink
)
829 gst_pad_unlink(stream
->their_src
, stream
->post_sink
);
831 gst_pad_unlink(stream
->their_src
, stream
->my_sink
);
832 gst_object_unref(stream
->their_src
);
833 stream
->their_src
= NULL
;
838 name
= gst_pad_get_name(pad
);
839 GST_WARNING("No pin matching pad \"%s\" found.", name
);
843 static GstFlowReturn
src_getrange_cb(GstPad
*pad
, GstObject
*parent
,
844 guint64 offset
, guint size
, GstBuffer
**buffer
)
846 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
849 GST_LOG("pad %p, offset %" G_GINT64_MODIFIER
"u, size %u, buffer %p.", pad
, offset
, size
, *buffer
);
851 if (offset
== GST_BUFFER_OFFSET_NONE
)
852 offset
= parser
->next_pull_offset
;
853 parser
->next_pull_offset
= offset
+ size
;
857 /* asfreader occasionally asks for zero bytes. gst_buffer_map() will
858 * return NULL in this case. Avoid confusing the read thread by asking
859 * it for zero bytes. */
861 *buffer
= gst_buffer_new_and_alloc(0);
862 gst_buffer_set_size(*buffer
, 0);
863 GST_LOG("Returning empty buffer.");
867 pthread_mutex_lock(&parser
->mutex
);
869 assert(!parser
->read_request
.size
);
870 parser
->read_request
.buffer
= *buffer
;
871 parser
->read_request
.offset
= offset
;
872 parser
->read_request
.size
= size
;
873 parser
->read_request
.done
= false;
874 pthread_cond_signal(&parser
->read_cond
);
876 /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect
877 * the upstream pin to flush if necessary. We should never be blocked on
878 * read_thread() not running. */
880 while (!parser
->read_request
.done
)
881 pthread_cond_wait(&parser
->read_done_cond
, &parser
->mutex
);
883 *buffer
= parser
->read_request
.buffer
;
884 ret
= parser
->read_request
.ret
;
886 pthread_mutex_unlock(&parser
->mutex
);
888 GST_LOG("Request returned %s.", gst_flow_get_name(ret
));
893 static gboolean
src_query_cb(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
895 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
898 GST_LOG("parser %p, type %s.", parser
, GST_QUERY_TYPE_NAME(query
));
900 switch (GST_QUERY_TYPE(query
))
902 case GST_QUERY_DURATION
:
903 gst_query_parse_duration(query
, &format
, NULL
);
904 if (format
== GST_FORMAT_PERCENT
)
906 gst_query_set_duration(query
, GST_FORMAT_PERCENT
, GST_FORMAT_PERCENT_MAX
);
909 else if (format
== GST_FORMAT_BYTES
)
911 gst_query_set_duration(query
, GST_FORMAT_BYTES
, parser
->file_size
);
916 case GST_QUERY_SEEKING
:
917 gst_query_parse_seeking (query
, &format
, NULL
, NULL
, NULL
);
918 if (format
!= GST_FORMAT_BYTES
)
920 GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format
));
923 gst_query_set_seeking(query
, GST_FORMAT_BYTES
, 1, 0, parser
->file_size
);
926 case GST_QUERY_SCHEDULING
:
927 gst_query_set_scheduling(query
, GST_SCHEDULING_FLAG_SEEKABLE
, 1, -1, 0);
928 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PUSH
);
929 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PULL
);
933 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query
));
938 static void *push_data(void *arg
)
940 struct wg_parser
*parser
= arg
;
944 GST_DEBUG("Starting push thread.");
946 if (!(buffer
= gst_buffer_new_allocate(NULL
, 16384, NULL
)))
948 GST_ERROR("Failed to allocate memory.");
952 max_size
= parser
->stop_offset
? parser
->stop_offset
: parser
->file_size
;
959 if (parser
->next_offset
>= max_size
)
961 size
= min(16384, max_size
- parser
->next_offset
);
963 if ((ret
= src_getrange_cb(parser
->my_src
, NULL
, parser
->next_offset
, size
, &buffer
)) < 0)
965 GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret
));
969 parser
->next_offset
+= size
;
971 buffer
->duration
= buffer
->pts
= -1;
972 if ((ret
= gst_pad_push(parser
->my_src
, buffer
)) < 0)
974 GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret
));
979 gst_buffer_unref(buffer
);
981 gst_pad_push_event(parser
->my_src
, gst_event_new_eos());
983 GST_DEBUG("Stopping push thread.");
988 static gboolean
activate_push(GstPad
*pad
, gboolean activate
)
990 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
994 if (parser
->push_thread
)
996 pthread_join(parser
->push_thread
, NULL
);
997 parser
->push_thread
= 0;
1000 else if (!parser
->push_thread
)
1004 if ((ret
= pthread_create(&parser
->push_thread
, NULL
, push_data
, parser
)))
1006 GST_ERROR("Failed to create push thread: %s", strerror(errno
));
1007 parser
->push_thread
= 0;
1014 static gboolean
src_activate_mode_cb(GstPad
*pad
, GstObject
*parent
, GstPadMode mode
, gboolean activate
)
1016 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1018 GST_DEBUG("%s source pad for parser %p in %s mode.",
1019 activate
? "Activating" : "Deactivating", parser
, gst_pad_mode_get_name(mode
));
1023 case GST_PAD_MODE_PULL
:
1025 case GST_PAD_MODE_PUSH
:
1026 return activate_push(pad
, activate
);
1027 case GST_PAD_MODE_NONE
:
1033 static GstBusSyncReply
bus_handler_cb(GstBus
*bus
, GstMessage
*msg
, gpointer user
)
1035 struct wg_parser
*parser
= user
;
1036 gchar
*dbg_info
= NULL
;
1039 GST_DEBUG("parser %p, message type %s.", parser
, GST_MESSAGE_TYPE_NAME(msg
));
1043 case GST_MESSAGE_ERROR
:
1044 gst_message_parse_error(msg
, &err
, &dbg_info
);
1045 fprintf(stderr
, "winegstreamer error: %s: %s\n", GST_OBJECT_NAME(msg
->src
), err
->message
);
1046 fprintf(stderr
, "winegstreamer error: %s: %s\n", GST_OBJECT_NAME(msg
->src
), dbg_info
);
1049 pthread_mutex_lock(&parser
->mutex
);
1050 parser
->error
= true;
1051 pthread_mutex_unlock(&parser
->mutex
);
1052 pthread_cond_signal(&parser
->init_cond
);
1055 case GST_MESSAGE_WARNING
:
1056 gst_message_parse_warning(msg
, &err
, &dbg_info
);
1057 fprintf(stderr
, "winegstreamer warning: %s: %s\n", GST_OBJECT_NAME(msg
->src
), err
->message
);
1058 fprintf(stderr
, "winegstreamer warning: %s: %s\n", GST_OBJECT_NAME(msg
->src
), dbg_info
);
1063 case GST_MESSAGE_DURATION_CHANGED
:
1064 pthread_mutex_lock(&parser
->mutex
);
1065 parser
->has_duration
= true;
1066 pthread_mutex_unlock(&parser
->mutex
);
1067 pthread_cond_signal(&parser
->init_cond
);
1073 gst_message_unref(msg
);
1074 return GST_BUS_DROP
;
1077 static gboolean
src_perform_seek(struct wg_parser
*parser
, GstEvent
*event
)
1079 BOOL thread
= !!parser
->push_thread
;
1080 GstSeekType cur_type
, stop_type
;
1081 GstFormat seek_format
;
1082 GstEvent
*flush_event
;
1088 gst_event_parse_seek(event
, &rate
, &seek_format
, &flags
,
1089 &cur_type
, &cur
, &stop_type
, &stop
);
1091 if (seek_format
!= GST_FORMAT_BYTES
)
1093 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format
));
1097 seqnum
= gst_event_get_seqnum(event
);
1099 /* send flush start */
1100 if (flags
& GST_SEEK_FLAG_FLUSH
)
1102 flush_event
= gst_event_new_flush_start();
1103 gst_event_set_seqnum(flush_event
, seqnum
);
1104 gst_pad_push_event(parser
->my_src
, flush_event
);
1106 gst_pad_set_active(parser
->my_src
, 1);
1109 parser
->next_offset
= parser
->start_offset
= cur
;
1111 /* and prepare to continue streaming */
1112 if (flags
& GST_SEEK_FLAG_FLUSH
)
1114 flush_event
= gst_event_new_flush_stop(TRUE
);
1115 gst_event_set_seqnum(flush_event
, seqnum
);
1116 gst_pad_push_event(parser
->my_src
, flush_event
);
1118 gst_pad_set_active(parser
->my_src
, 1);
1124 static gboolean
src_event_cb(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
1126 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1127 gboolean ret
= TRUE
;
1129 GST_LOG("parser %p, type \"%s\".", parser
, GST_EVENT_TYPE_NAME(event
));
1131 switch (event
->type
)
1133 case GST_EVENT_SEEK
:
1134 ret
= src_perform_seek(parser
, event
);
1137 case GST_EVENT_FLUSH_START
:
1138 case GST_EVENT_FLUSH_STOP
:
1140 case GST_EVENT_RECONFIGURE
:
1144 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
1148 gst_event_unref(event
);
1152 static NTSTATUS
wg_parser_connect(void *args
)
1154 GstStaticPadTemplate src_template
= GST_STATIC_PAD_TEMPLATE("quartz_src",
1155 GST_PAD_SRC
, GST_PAD_ALWAYS
, GST_STATIC_CAPS_ANY
);
1156 const struct wg_parser_connect_params
*params
= args
;
1157 struct wg_parser
*parser
= params
->parser
;
1161 parser
->file_size
= params
->file_size
;
1162 parser
->sink_connected
= true;
1166 parser
->bus
= gst_bus_new();
1167 gst_bus_set_sync_handler(parser
->bus
, bus_handler_cb
, parser
, NULL
);
1170 parser
->container
= gst_bin_new(NULL
);
1171 gst_element_set_bus(parser
->container
, parser
->bus
);
1173 parser
->my_src
= gst_pad_new_from_static_template(&src_template
, "quartz-src");
1174 gst_pad_set_getrange_function(parser
->my_src
, src_getrange_cb
);
1175 gst_pad_set_query_function(parser
->my_src
, src_query_cb
);
1176 gst_pad_set_activatemode_function(parser
->my_src
, src_activate_mode_cb
);
1177 gst_pad_set_event_function(parser
->my_src
, src_event_cb
);
1178 gst_pad_set_element_private(parser
->my_src
, parser
);
1180 parser
->start_offset
= parser
->next_offset
= parser
->stop_offset
= 0;
1181 parser
->next_pull_offset
= 0;
1182 parser
->error
= false;
1184 if (!parser
->init_gst(parser
))
1187 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
1188 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
1189 if (ret
== GST_STATE_CHANGE_FAILURE
)
1191 GST_ERROR("Failed to play stream.\n");
1195 pthread_mutex_lock(&parser
->mutex
);
1197 while (!parser
->no_more_pads
&& !parser
->error
)
1198 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1201 pthread_mutex_unlock(&parser
->mutex
);
1205 for (i
= 0; i
< parser
->stream_count
; ++i
)
1207 struct wg_parser_stream
*stream
= parser
->streams
[i
];
1210 while (!stream
->has_caps
&& !parser
->error
)
1211 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1213 /* GStreamer doesn't actually provide any guarantees about when duration
1214 * is available, even for seekable streams. It's basically built for
1215 * applications that don't care, e.g. movie players that can display
1216 * a duration once it's available, and update it visually if a better
1217 * estimate is found. This doesn't really match well with DirectShow or
1218 * Media Foundation, which both expect duration to be available
1219 * immediately on connecting, so we have to use some complex heuristics
1220 * to try to actually get a usable duration.
1222 * Some elements (avidemux, wavparse, qtdemux) record duration almost
1223 * immediately, before fixing caps. Such elements don't send
1224 * duration-changed messages. Therefore always try querying duration
1225 * after caps have been found.
1227 * Some elements (mpegaudioparse) send duration-changed. In the case of
1228 * a mp3 stream without seek tables it will not be sent immediately, but
1229 * only after enough frames have been parsed to form an estimate. They
1230 * may send it multiple times with increasingly accurate estimates, but
1231 * unfortunately we have no way of knowing whether another estimate will
1232 * be sent, so we always take the first one. We assume that if the
1233 * duration is not immediately available then the element will always
1234 * send duration-changed.
1241 pthread_mutex_unlock(&parser
->mutex
);
1244 if (gst_pad_query_duration(stream
->their_src
, GST_FORMAT_TIME
, &duration
))
1246 stream
->duration
= duration
/ 100;
1252 stream
->duration
= 0;
1253 GST_WARNING("Failed to query duration.\n");
1257 /* Elements based on GstBaseParse send duration-changed before
1258 * actually updating the duration in GStreamer versions prior
1259 * to 1.17.1. See <gstreamer.git:d28e0b4147fe7073b2>. So after
1260 * receiving duration-changed we have to continue polling until
1261 * the query succeeds. */
1262 if (parser
->has_duration
)
1264 pthread_mutex_unlock(&parser
->mutex
);
1266 pthread_mutex_lock(&parser
->mutex
);
1270 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1275 pthread_mutex_unlock(&parser
->mutex
);
1277 parser
->next_offset
= 0;
1281 if (parser
->container
)
1282 gst_element_set_state(parser
->container
, GST_STATE_NULL
);
1283 if (parser
->their_sink
)
1285 gst_object_unref(parser
->their_sink
);
1286 parser
->my_src
= parser
->their_sink
= NULL
;
1289 for (i
= 0; i
< parser
->stream_count
; ++i
)
1290 free_stream(parser
->streams
[i
]);
1291 parser
->stream_count
= 0;
1292 free(parser
->streams
);
1293 parser
->streams
= NULL
;
1295 if (parser
->container
)
1297 gst_element_set_bus(parser
->container
, NULL
);
1298 gst_object_unref(parser
->container
);
1299 parser
->container
= NULL
;
1302 pthread_mutex_lock(&parser
->mutex
);
1303 parser
->sink_connected
= false;
1304 pthread_mutex_unlock(&parser
->mutex
);
1305 pthread_cond_signal(&parser
->read_cond
);
1310 static NTSTATUS
wg_parser_disconnect(void *args
)
1312 struct wg_parser
*parser
= args
;
1315 /* Unblock all of our streams. */
1316 pthread_mutex_lock(&parser
->mutex
);
1317 for (i
= 0; i
< parser
->stream_count
; ++i
)
1319 parser
->streams
[i
]->flushing
= true;
1320 pthread_cond_signal(&parser
->streams
[i
]->event_empty_cond
);
1322 pthread_mutex_unlock(&parser
->mutex
);
1324 gst_element_set_state(parser
->container
, GST_STATE_NULL
);
1325 gst_object_unref(parser
->my_src
);
1326 gst_object_unref(parser
->their_sink
);
1327 parser
->my_src
= parser
->their_sink
= NULL
;
1329 pthread_mutex_lock(&parser
->mutex
);
1330 parser
->sink_connected
= false;
1331 pthread_mutex_unlock(&parser
->mutex
);
1332 pthread_cond_signal(&parser
->read_cond
);
1334 for (i
= 0; i
< parser
->stream_count
; ++i
)
1335 free_stream(parser
->streams
[i
]);
1337 parser
->stream_count
= 0;
1338 free(parser
->streams
);
1339 parser
->streams
= NULL
;
1341 gst_element_set_bus(parser
->container
, NULL
);
1342 gst_object_unref(parser
->container
);
1343 parser
->container
= NULL
;
1348 static BOOL
decodebin_parser_init_gst(struct wg_parser
*parser
)
1350 GstElement
*element
;
1353 if (!(element
= create_element("decodebin", "base")))
1356 gst_bin_add(GST_BIN(parser
->container
), element
);
1357 parser
->decodebin
= element
;
1359 if (parser
->unlimited_buffering
)
1361 g_object_set(parser
->decodebin
, "max-size-buffers", G_MAXUINT
, NULL
);
1362 g_object_set(parser
->decodebin
, "max-size-time", G_MAXUINT64
, NULL
);
1363 g_object_set(parser
->decodebin
, "max-size-bytes", G_MAXUINT
, NULL
);
1366 g_signal_connect(element
, "pad-added", G_CALLBACK(pad_added_cb
), parser
);
1367 g_signal_connect(element
, "pad-removed", G_CALLBACK(pad_removed_cb
), parser
);
1368 g_signal_connect(element
, "autoplug-select", G_CALLBACK(autoplug_select_cb
), parser
);
1369 g_signal_connect(element
, "no-more-pads", G_CALLBACK(no_more_pads_cb
), parser
);
1371 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1373 pthread_mutex_lock(&parser
->mutex
);
1374 parser
->no_more_pads
= false;
1375 pthread_mutex_unlock(&parser
->mutex
);
1377 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1379 GST_ERROR("Failed to link pads, error %d.", ret
);
1386 static BOOL
avi_parser_init_gst(struct wg_parser
*parser
)
1388 GstElement
*element
;
1391 if (!(element
= create_element("avidemux", "good")))
1394 gst_bin_add(GST_BIN(parser
->container
), element
);
1396 g_signal_connect(element
, "pad-added", G_CALLBACK(pad_added_cb
), parser
);
1397 g_signal_connect(element
, "pad-removed", G_CALLBACK(pad_removed_cb
), parser
);
1398 g_signal_connect(element
, "no-more-pads", G_CALLBACK(no_more_pads_cb
), parser
);
1400 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1402 pthread_mutex_lock(&parser
->mutex
);
1403 parser
->no_more_pads
= false;
1404 pthread_mutex_unlock(&parser
->mutex
);
1406 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1408 GST_ERROR("Failed to link pads, error %d.", ret
);
1415 static BOOL
mpeg_audio_parser_init_gst(struct wg_parser
*parser
)
1417 struct wg_parser_stream
*stream
;
1418 GstElement
*element
;
1421 if (!(element
= create_element("mpegaudioparse", "good")))
1424 gst_bin_add(GST_BIN(parser
->container
), element
);
1426 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1427 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1429 GST_ERROR("Failed to link sink pads, error %d.", ret
);
1433 if (!(stream
= create_stream(parser
)))
1436 gst_object_ref(stream
->their_src
= gst_element_get_static_pad(element
, "src"));
1437 if ((ret
= gst_pad_link(stream
->their_src
, stream
->my_sink
)) < 0)
1439 GST_ERROR("Failed to link source pads, error %d.", ret
);
1442 gst_pad_set_active(stream
->my_sink
, 1);
1444 parser
->no_more_pads
= true;
1449 static BOOL
wave_parser_init_gst(struct wg_parser
*parser
)
1451 struct wg_parser_stream
*stream
;
1452 GstElement
*element
;
1455 if (!(element
= create_element("wavparse", "good")))
1458 gst_bin_add(GST_BIN(parser
->container
), element
);
1460 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1461 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1463 GST_ERROR("Failed to link sink pads, error %d.", ret
);
1467 if (!(stream
= create_stream(parser
)))
1470 stream
->their_src
= gst_element_get_static_pad(element
, "src");
1471 gst_object_ref(stream
->their_src
);
1472 if ((ret
= gst_pad_link(stream
->their_src
, stream
->my_sink
)) < 0)
1474 GST_ERROR("Failed to link source pads, error %d.", ret
);
1477 gst_pad_set_active(stream
->my_sink
, 1);
1479 parser
->no_more_pads
= true;
1484 static void init_gstreamer_once(void)
1486 char arg0
[] = "wine";
1487 char arg1
[] = "--gst-disable-registry-fork";
1488 char *args
[] = {arg0
, arg1
, NULL
};
1489 int argc
= ARRAY_SIZE(args
) - 1;
1493 if (!gst_init_check(&argc
, &argv
, &err
))
1495 fprintf(stderr
, "winegstreamer: failed to initialize GStreamer: %s\n", err
->message
);
1500 GST_DEBUG_CATEGORY_INIT(wine
, "WINE", GST_DEBUG_FG_RED
, "Wine GStreamer support");
1502 GST_INFO("GStreamer library version %s; wine built with %d.%d.%d.",
1503 gst_version_string(), GST_VERSION_MAJOR
, GST_VERSION_MINOR
, GST_VERSION_MICRO
);
1506 bool init_gstreamer(void)
1508 static pthread_once_t init_once
= PTHREAD_ONCE_INIT
;
1510 return !pthread_once(&init_once
, init_gstreamer_once
);
1513 static NTSTATUS
wg_parser_create(void *args
)
1515 static const init_gst_cb init_funcs
[] =
1517 [WG_PARSER_DECODEBIN
] = decodebin_parser_init_gst
,
1518 [WG_PARSER_AVIDEMUX
] = avi_parser_init_gst
,
1519 [WG_PARSER_MPEGAUDIOPARSE
] = mpeg_audio_parser_init_gst
,
1520 [WG_PARSER_WAVPARSE
] = wave_parser_init_gst
,
1523 struct wg_parser_create_params
*params
= args
;
1524 struct wg_parser
*parser
;
1526 if (!init_gstreamer())
1529 if (!(parser
= calloc(1, sizeof(*parser
))))
1530 return E_OUTOFMEMORY
;
1532 pthread_mutex_init(&parser
->mutex
, NULL
);
1533 pthread_cond_init(&parser
->init_cond
, NULL
);
1534 pthread_cond_init(&parser
->read_cond
, NULL
);
1535 pthread_cond_init(&parser
->read_done_cond
, NULL
);
1536 parser
->init_gst
= init_funcs
[params
->type
];
1537 parser
->unlimited_buffering
= params
->unlimited_buffering
;
1539 GST_DEBUG("Created winegstreamer parser %p.", parser
);
1540 params
->parser
= parser
;
1544 static NTSTATUS
wg_parser_destroy(void *args
)
1546 struct wg_parser
*parser
= args
;
1550 gst_bus_set_sync_handler(parser
->bus
, NULL
, NULL
, NULL
);
1551 gst_object_unref(parser
->bus
);
1554 pthread_mutex_destroy(&parser
->mutex
);
1555 pthread_cond_destroy(&parser
->init_cond
);
1556 pthread_cond_destroy(&parser
->read_cond
);
1557 pthread_cond_destroy(&parser
->read_done_cond
);
1563 const unixlib_entry_t __wine_unix_call_funcs
[] =
1565 #define X(name) [unix_ ## name] = name
1566 X(wg_parser_create
),
1567 X(wg_parser_destroy
),
1569 X(wg_parser_connect
),
1570 X(wg_parser_disconnect
),
1572 X(wg_parser_get_next_read_offset
),
1573 X(wg_parser_push_data
),
1575 X(wg_parser_get_stream_count
),
1576 X(wg_parser_get_stream
),
1578 X(wg_parser_stream_get_preferred_format
),
1579 X(wg_parser_stream_enable
),
1580 X(wg_parser_stream_disable
),
1582 X(wg_parser_stream_get_buffer
),
1583 X(wg_parser_stream_copy_buffer
),
1584 X(wg_parser_stream_release_buffer
),
1585 X(wg_parser_stream_notify_qos
),
1587 X(wg_parser_stream_get_duration
),
1588 X(wg_parser_stream_seek
),
1590 X(wg_transform_create
),
1591 X(wg_transform_destroy
),
1593 X(wg_transform_push_data
),
1594 X(wg_transform_read_data
),