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
;
105 struct wg_parser_event event
;
109 bool flushing
, eos
, enabled
, has_caps
;
114 static NTSTATUS
wg_parser_get_stream_count(void *args
)
116 struct wg_parser_get_stream_count_params
*params
= args
;
118 params
->count
= params
->parser
->stream_count
;
122 static NTSTATUS
wg_parser_get_stream(void *args
)
124 struct wg_parser_get_stream_params
*params
= args
;
126 params
->stream
= params
->parser
->streams
[params
->index
];
130 static NTSTATUS
wg_parser_get_next_read_offset(void *args
)
132 struct wg_parser_get_next_read_offset_params
*params
= args
;
133 struct wg_parser
*parser
= params
->parser
;
135 pthread_mutex_lock(&parser
->mutex
);
137 while (parser
->sink_connected
&& !parser
->read_request
.size
)
138 pthread_cond_wait(&parser
->read_cond
, &parser
->mutex
);
140 if (!parser
->sink_connected
)
142 pthread_mutex_unlock(&parser
->mutex
);
143 return VFW_E_WRONG_STATE
;
146 params
->offset
= parser
->read_request
.offset
;
147 params
->size
= parser
->read_request
.size
;
149 pthread_mutex_unlock(&parser
->mutex
);
153 static NTSTATUS
wg_parser_push_data(void *args
)
155 const struct wg_parser_push_data_params
*params
= args
;
156 struct wg_parser
*parser
= params
->parser
;
157 const void *data
= params
->data
;
158 uint32_t size
= params
->size
;
160 pthread_mutex_lock(&parser
->mutex
);
168 /* Note that we don't allocate the buffer until we have a size.
169 * midiparse passes a NULL buffer and a size of UINT_MAX, in an
170 * apparent attempt to read the whole input stream at once. */
171 if (!parser
->read_request
.buffer
)
172 parser
->read_request
.buffer
= gst_buffer_new_and_alloc(size
);
173 gst_buffer_map(parser
->read_request
.buffer
, &map_info
, GST_MAP_WRITE
);
174 memcpy(map_info
.data
, data
, size
);
175 gst_buffer_unmap(parser
->read_request
.buffer
, &map_info
);
176 parser
->read_request
.ret
= GST_FLOW_OK
;
180 parser
->read_request
.ret
= GST_FLOW_EOS
;
185 parser
->read_request
.ret
= GST_FLOW_ERROR
;
187 parser
->read_request
.done
= true;
188 parser
->read_request
.size
= 0;
190 pthread_mutex_unlock(&parser
->mutex
);
191 pthread_cond_signal(&parser
->read_done_cond
);
196 static NTSTATUS
wg_parser_stream_get_preferred_format(void *args
)
198 const struct wg_parser_stream_get_preferred_format_params
*params
= args
;
200 *params
->format
= params
->stream
->preferred_format
;
204 static NTSTATUS
wg_parser_stream_enable(void *args
)
206 const struct wg_parser_stream_enable_params
*params
= args
;
207 struct wg_parser_stream
*stream
= params
->stream
;
208 const struct wg_format
*format
= params
->format
;
210 stream
->current_format
= *format
;
211 stream
->enabled
= true;
213 if (format
->major_type
== WG_MAJOR_TYPE_VIDEO
)
215 bool flip
= (format
->u
.video
.height
< 0);
217 switch (format
->u
.video
.format
)
219 case WG_VIDEO_FORMAT_BGRA
:
220 case WG_VIDEO_FORMAT_BGRx
:
221 case WG_VIDEO_FORMAT_BGR
:
222 case WG_VIDEO_FORMAT_RGB15
:
223 case WG_VIDEO_FORMAT_RGB16
:
227 case WG_VIDEO_FORMAT_AYUV
:
228 case WG_VIDEO_FORMAT_I420
:
229 case WG_VIDEO_FORMAT_NV12
:
230 case WG_VIDEO_FORMAT_UYVY
:
231 case WG_VIDEO_FORMAT_YUY2
:
232 case WG_VIDEO_FORMAT_YV12
:
233 case WG_VIDEO_FORMAT_YVYU
:
234 case WG_VIDEO_FORMAT_UNKNOWN
:
235 case WG_VIDEO_FORMAT_CINEPAK
:
239 gst_util_set_object_arg(G_OBJECT(stream
->flip
), "method", flip
? "vertical-flip" : "none");
242 gst_pad_push_event(stream
->my_sink
, gst_event_new_reconfigure());
246 static NTSTATUS
wg_parser_stream_disable(void *args
)
248 struct wg_parser_stream
*stream
= args
;
250 stream
->enabled
= false;
254 static NTSTATUS
wg_parser_stream_get_event(void *args
)
256 const struct wg_parser_stream_get_event_params
*params
= args
;
257 struct wg_parser_stream
*stream
= params
->stream
;
258 struct wg_parser
*parser
= stream
->parser
;
260 pthread_mutex_lock(&parser
->mutex
);
262 while (stream
->event
.type
== WG_PARSER_EVENT_NONE
)
263 pthread_cond_wait(&stream
->event_cond
, &parser
->mutex
);
265 *params
->event
= stream
->event
;
267 if (stream
->event
.type
!= WG_PARSER_EVENT_BUFFER
)
269 stream
->event
.type
= WG_PARSER_EVENT_NONE
;
270 pthread_cond_signal(&stream
->event_empty_cond
);
272 pthread_mutex_unlock(&parser
->mutex
);
277 static NTSTATUS
wg_parser_stream_copy_buffer(void *args
)
279 const struct wg_parser_stream_copy_buffer_params
*params
= args
;
280 struct wg_parser_stream
*stream
= params
->stream
;
281 struct wg_parser
*parser
= stream
->parser
;
282 uint32_t offset
= params
->offset
;
283 uint32_t size
= params
->size
;
285 pthread_mutex_lock(&parser
->mutex
);
289 pthread_mutex_unlock(&parser
->mutex
);
290 return VFW_E_WRONG_STATE
;
293 assert(stream
->event
.type
== WG_PARSER_EVENT_BUFFER
);
294 assert(offset
< stream
->map_info
.size
);
295 assert(offset
+ size
<= stream
->map_info
.size
);
296 memcpy(params
->data
, stream
->map_info
.data
+ offset
, size
);
298 pthread_mutex_unlock(&parser
->mutex
);
302 static NTSTATUS
wg_parser_stream_release_buffer(void *args
)
304 struct wg_parser_stream
*stream
= args
;
305 struct wg_parser
*parser
= stream
->parser
;
307 pthread_mutex_lock(&parser
->mutex
);
309 assert(stream
->event
.type
== WG_PARSER_EVENT_BUFFER
);
311 gst_buffer_unmap(stream
->buffer
, &stream
->map_info
);
312 gst_buffer_unref(stream
->buffer
);
313 stream
->buffer
= NULL
;
314 stream
->event
.type
= WG_PARSER_EVENT_NONE
;
316 pthread_mutex_unlock(&parser
->mutex
);
317 pthread_cond_signal(&stream
->event_empty_cond
);
322 static NTSTATUS
wg_parser_stream_get_duration(void *args
)
324 struct wg_parser_stream_get_duration_params
*params
= args
;
326 params
->duration
= params
->stream
->duration
;
330 static NTSTATUS
wg_parser_stream_seek(void *args
)
332 GstSeekType start_type
= GST_SEEK_TYPE_SET
, stop_type
= GST_SEEK_TYPE_SET
;
333 const struct wg_parser_stream_seek_params
*params
= args
;
334 DWORD start_flags
= params
->start_flags
;
335 DWORD stop_flags
= params
->stop_flags
;
336 GstSeekFlags flags
= 0;
338 if (start_flags
& AM_SEEKING_SeekToKeyFrame
)
339 flags
|= GST_SEEK_FLAG_KEY_UNIT
;
340 if (start_flags
& AM_SEEKING_Segment
)
341 flags
|= GST_SEEK_FLAG_SEGMENT
;
342 if (!(start_flags
& AM_SEEKING_NoFlush
))
343 flags
|= GST_SEEK_FLAG_FLUSH
;
345 if ((start_flags
& AM_SEEKING_PositioningBitsMask
) == AM_SEEKING_NoPositioning
)
346 start_type
= GST_SEEK_TYPE_NONE
;
347 if ((stop_flags
& AM_SEEKING_PositioningBitsMask
) == AM_SEEKING_NoPositioning
)
348 stop_type
= GST_SEEK_TYPE_NONE
;
350 if (!gst_pad_push_event(params
->stream
->my_sink
, gst_event_new_seek(params
->rate
, GST_FORMAT_TIME
,
351 flags
, start_type
, params
->start_pos
* 100, stop_type
, params
->stop_pos
* 100)))
352 GST_ERROR("Failed to seek.\n");
357 static NTSTATUS
wg_parser_stream_notify_qos(void *args
)
359 const struct wg_parser_stream_notify_qos_params
*params
= args
;
360 struct wg_parser_stream
*stream
= params
->stream
;
361 GstClockTime stream_time
;
364 /* We return timestamps in stream time, i.e. relative to the start of the
365 * file (or other medium), but gst_event_new_qos() expects the timestamp in
367 stream_time
= gst_segment_to_running_time(&stream
->segment
, GST_FORMAT_TIME
, params
->timestamp
* 100);
368 if (stream_time
== -1)
370 /* This can happen legitimately if the sample falls outside of the
371 * segment bounds. GStreamer elements shouldn't present the sample in
372 * that case, but DirectShow doesn't care. */
373 GST_LOG("Ignoring QoS event.\n");
377 if (!(event
= gst_event_new_qos(params
->underflow
? GST_QOS_TYPE_UNDERFLOW
: GST_QOS_TYPE_OVERFLOW
,
378 params
->proportion
, params
->diff
* 100, stream_time
)))
379 GST_ERROR("Failed to create QOS event.\n");
380 gst_pad_push_event(stream
->my_sink
, event
);
385 static GstAutoplugSelectResult
autoplug_select_cb(GstElement
*bin
, GstPad
*pad
,
386 GstCaps
*caps
, GstElementFactory
*fact
, gpointer user
)
388 const char *name
= gst_element_factory_get_longname(fact
);
390 GST_INFO("Using \"%s\".", name
);
392 if (strstr(name
, "Player protection"))
394 GST_WARNING("Blacklisted a/52 decoder because it only works in Totem.");
395 return GST_AUTOPLUG_SELECT_SKIP
;
397 if (!strcmp(name
, "Fluendo Hardware Accelerated Video Decoder"))
399 GST_WARNING("Disabled video acceleration since it breaks in wine.");
400 return GST_AUTOPLUG_SELECT_SKIP
;
402 return GST_AUTOPLUG_SELECT_TRY
;
405 static void no_more_pads_cb(GstElement
*element
, gpointer user
)
407 struct wg_parser
*parser
= user
;
409 GST_DEBUG("parser %p.", parser
);
411 pthread_mutex_lock(&parser
->mutex
);
412 parser
->no_more_pads
= true;
413 pthread_mutex_unlock(&parser
->mutex
);
414 pthread_cond_signal(&parser
->init_cond
);
417 static GstFlowReturn
queue_stream_event(struct wg_parser_stream
*stream
,
418 const struct wg_parser_event
*event
, GstBuffer
*buffer
)
420 struct wg_parser
*parser
= stream
->parser
;
422 /* Unlike request_buffer_src() [q.v.], we need to watch for GStreamer
423 * flushes here. The difference is that we can be blocked by the streaming
424 * thread not running (or itself flushing on the DirectShow side).
425 * request_buffer_src() can only be blocked by the upstream source, and that
426 * is solved by flushing the upstream source. */
428 pthread_mutex_lock(&parser
->mutex
);
429 while (!stream
->flushing
&& stream
->event
.type
!= WG_PARSER_EVENT_NONE
)
430 pthread_cond_wait(&stream
->event_empty_cond
, &parser
->mutex
);
431 if (stream
->flushing
)
433 pthread_mutex_unlock(&parser
->mutex
);
434 GST_DEBUG("Filter is flushing; discarding event.");
435 return GST_FLOW_FLUSHING
;
439 assert(GST_IS_BUFFER(buffer
));
440 if (!gst_buffer_map(buffer
, &stream
->map_info
, GST_MAP_READ
))
442 pthread_mutex_unlock(&parser
->mutex
);
443 GST_ERROR("Failed to map buffer.\n");
444 return GST_FLOW_ERROR
;
447 stream
->event
= *event
;
448 stream
->buffer
= buffer
;
449 pthread_mutex_unlock(&parser
->mutex
);
450 pthread_cond_signal(&stream
->event_cond
);
451 GST_LOG("Event queued.");
455 static gboolean
sink_event_cb(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
457 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
458 struct wg_parser
*parser
= stream
->parser
;
460 GST_LOG("stream %p, type \"%s\".", stream
, GST_EVENT_TYPE_NAME(event
));
464 case GST_EVENT_SEGMENT
:
467 const GstSegment
*segment
;
469 gst_event_parse_segment(event
, &segment
);
471 if (segment
->format
!= GST_FORMAT_TIME
)
473 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(segment
->format
));
477 gst_segment_copy_into(segment
, &stream
->segment
);
484 struct wg_parser_event stream_event
;
486 stream_event
.type
= WG_PARSER_EVENT_EOS
;
487 queue_stream_event(stream
, &stream_event
, NULL
);
491 pthread_mutex_lock(&parser
->mutex
);
493 pthread_mutex_unlock(&parser
->mutex
);
494 pthread_cond_signal(&parser
->init_cond
);
498 case GST_EVENT_FLUSH_START
:
501 pthread_mutex_lock(&parser
->mutex
);
503 stream
->flushing
= true;
504 pthread_cond_signal(&stream
->event_empty_cond
);
506 if (stream
->event
.type
== WG_PARSER_EVENT_BUFFER
)
508 gst_buffer_unmap(stream
->buffer
, &stream
->map_info
);
509 gst_buffer_unref(stream
->buffer
);
510 stream
->buffer
= NULL
;
512 stream
->event
.type
= WG_PARSER_EVENT_NONE
;
514 pthread_mutex_unlock(&parser
->mutex
);
518 case GST_EVENT_FLUSH_STOP
:
522 gst_event_parse_flush_stop(event
, &reset_time
);
525 gst_segment_init(&stream
->segment
, GST_FORMAT_UNDEFINED
);
529 pthread_mutex_lock(&parser
->mutex
);
530 stream
->flushing
= false;
531 pthread_mutex_unlock(&parser
->mutex
);
540 gst_event_parse_caps(event
, &caps
);
541 pthread_mutex_lock(&parser
->mutex
);
542 wg_format_from_caps(&stream
->preferred_format
, caps
);
543 stream
->has_caps
= true;
544 pthread_mutex_unlock(&parser
->mutex
);
545 pthread_cond_signal(&parser
->init_cond
);
550 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
552 gst_event_unref(event
);
556 static GstFlowReturn
sink_chain_cb(GstPad
*pad
, GstObject
*parent
, GstBuffer
*buffer
)
558 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
559 struct wg_parser_event stream_event
;
562 GST_LOG("stream %p, buffer %p.", stream
, buffer
);
564 if (!stream
->enabled
)
566 gst_buffer_unref(buffer
);
570 stream_event
.type
= WG_PARSER_EVENT_BUFFER
;
572 /* FIXME: Should we use gst_segment_to_stream_time_full()? Under what
573 * circumstances is the stream time not equal to the buffer PTS? Note that
574 * this will need modification to wg_parser_stream_notify_qos() as well. */
576 if ((stream_event
.u
.buffer
.has_pts
= GST_BUFFER_PTS_IS_VALID(buffer
)))
577 stream_event
.u
.buffer
.pts
= GST_BUFFER_PTS(buffer
) / 100;
578 if ((stream_event
.u
.buffer
.has_duration
= GST_BUFFER_DURATION_IS_VALID(buffer
)))
579 stream_event
.u
.buffer
.duration
= GST_BUFFER_DURATION(buffer
) / 100;
580 stream_event
.u
.buffer
.discontinuity
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_DISCONT
);
581 stream_event
.u
.buffer
.preroll
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_LIVE
);
582 stream_event
.u
.buffer
.delta
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_DELTA_UNIT
);
583 stream_event
.u
.buffer
.size
= gst_buffer_get_size(buffer
);
585 /* Transfer our reference to the buffer to the stream object. */
586 if ((ret
= queue_stream_event(stream
, &stream_event
, buffer
)) != GST_FLOW_OK
)
587 gst_buffer_unref(buffer
);
591 static gboolean
sink_query_cb(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
593 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
595 GST_LOG("stream %p, type \"%s\".", stream
, gst_query_type_get_name(query
->type
));
601 GstCaps
*caps
, *filter
, *temp
;
604 gst_query_parse_caps(query
, &filter
);
607 caps
= wg_format_to_caps(&stream
->current_format
);
609 caps
= gst_caps_new_any();
613 str
= gst_caps_to_string(caps
);
614 GST_LOG("Stream caps are \"%s\".", str
);
619 temp
= gst_caps_intersect(caps
, filter
);
620 gst_caps_unref(caps
);
624 gst_query_set_caps_result(query
, caps
);
625 gst_caps_unref(caps
);
629 case GST_QUERY_ACCEPT_CAPS
:
631 struct wg_format format
;
635 if (!stream
->enabled
)
637 gst_query_set_accept_caps_result(query
, TRUE
);
641 gst_query_parse_accept_caps(query
, &caps
);
642 wg_format_from_caps(&format
, caps
);
643 ret
= wg_format_compare(&format
, &stream
->current_format
);
644 if (!ret
&& gst_debug_category_get_threshold(GST_CAT_DEFAULT
) >= GST_LEVEL_WARNING
)
646 gchar
*str
= gst_caps_to_string(caps
);
647 GST_WARNING("Rejecting caps \"%s\".", str
);
650 gst_query_set_accept_caps_result(query
, ret
);
655 return gst_pad_query_default (pad
, parent
, query
);
659 GstElement
*create_element(const char *name
, const char *plugin_set
)
663 if (!(element
= gst_element_factory_make(name
, NULL
)))
664 fprintf(stderr
, "winegstreamer: failed to create %s, are %u-bit GStreamer \"%s\" plugins installed?\n",
665 name
, 8 * (unsigned int)sizeof(void *), plugin_set
);
669 static struct wg_parser_stream
*create_stream(struct wg_parser
*parser
)
671 struct wg_parser_stream
*stream
, **new_array
;
674 if (!(new_array
= realloc(parser
->streams
, (parser
->stream_count
+ 1) * sizeof(*parser
->streams
))))
676 parser
->streams
= new_array
;
678 if (!(stream
= calloc(1, sizeof(*stream
))))
681 gst_segment_init(&stream
->segment
, GST_FORMAT_UNDEFINED
);
683 stream
->parser
= parser
;
684 pthread_cond_init(&stream
->event_cond
, NULL
);
685 pthread_cond_init(&stream
->event_empty_cond
, NULL
);
687 sprintf(pad_name
, "qz_sink_%u", parser
->stream_count
);
688 stream
->my_sink
= gst_pad_new(pad_name
, GST_PAD_SINK
);
689 gst_pad_set_element_private(stream
->my_sink
, stream
);
690 gst_pad_set_chain_function(stream
->my_sink
, sink_chain_cb
);
691 gst_pad_set_event_function(stream
->my_sink
, sink_event_cb
);
692 gst_pad_set_query_function(stream
->my_sink
, sink_query_cb
);
694 parser
->streams
[parser
->stream_count
++] = stream
;
698 static void free_stream(struct wg_parser_stream
*stream
)
700 if (stream
->their_src
)
702 if (stream
->post_sink
)
704 gst_pad_unlink(stream
->their_src
, stream
->post_sink
);
705 gst_pad_unlink(stream
->post_src
, stream
->my_sink
);
706 gst_object_unref(stream
->post_src
);
707 gst_object_unref(stream
->post_sink
);
708 stream
->post_src
= stream
->post_sink
= NULL
;
711 gst_pad_unlink(stream
->their_src
, stream
->my_sink
);
712 gst_object_unref(stream
->their_src
);
714 gst_object_unref(stream
->my_sink
);
716 pthread_cond_destroy(&stream
->event_cond
);
717 pthread_cond_destroy(&stream
->event_empty_cond
);
722 static void pad_added_cb(GstElement
*element
, GstPad
*pad
, gpointer user
)
724 struct wg_parser
*parser
= user
;
725 struct wg_parser_stream
*stream
;
730 GST_LOG("parser %p, element %p, pad %p.", parser
, element
, pad
);
732 if (gst_pad_is_linked(pad
))
735 caps
= gst_pad_query_caps(pad
, NULL
);
736 name
= gst_structure_get_name(gst_caps_get_structure(caps
, 0));
738 if (!(stream
= create_stream(parser
)))
741 if (!strcmp(name
, "video/x-raw"))
743 GstElement
*deinterlace
, *vconv
, *flip
, *vconv2
;
745 /* DirectShow can express interlaced video, but downstream filters can't
746 * necessarily consume it. In particular, the video renderer can't. */
747 if (!(deinterlace
= create_element("deinterlace", "good")))
750 /* decodebin considers many YUV formats to be "raw", but some quartz
751 * filters can't handle those. Also, videoflip can't handle all "raw"
752 * formats either. Add a videoconvert to swap color spaces. */
753 if (!(vconv
= create_element("videoconvert", "base")))
756 /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
757 if (!(flip
= create_element("videoflip", "good")))
760 /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert
761 * to do the final conversion. */
762 if (!(vconv2
= create_element("videoconvert", "base")))
765 /* The bin takes ownership of these elements. */
766 gst_bin_add(GST_BIN(parser
->container
), deinterlace
);
767 gst_element_sync_state_with_parent(deinterlace
);
768 gst_bin_add(GST_BIN(parser
->container
), vconv
);
769 gst_element_sync_state_with_parent(vconv
);
770 gst_bin_add(GST_BIN(parser
->container
), flip
);
771 gst_element_sync_state_with_parent(flip
);
772 gst_bin_add(GST_BIN(parser
->container
), vconv2
);
773 gst_element_sync_state_with_parent(vconv2
);
775 gst_element_link(deinterlace
, vconv
);
776 gst_element_link(vconv
, flip
);
777 gst_element_link(flip
, vconv2
);
779 stream
->post_sink
= gst_element_get_static_pad(deinterlace
, "sink");
780 stream
->post_src
= gst_element_get_static_pad(vconv2
, "src");
783 else if (!strcmp(name
, "audio/x-raw"))
787 /* Currently our dsound can't handle 64-bit formats or all
788 * surround-sound configurations. Native dsound can't always handle
789 * 64-bit formats either. Add an audioconvert to allow changing bit
790 * depth and channel count. */
791 if (!(convert
= create_element("audioconvert", "base")))
794 gst_bin_add(GST_BIN(parser
->container
), convert
);
795 gst_element_sync_state_with_parent(convert
);
797 stream
->post_sink
= gst_element_get_static_pad(convert
, "sink");
798 stream
->post_src
= gst_element_get_static_pad(convert
, "src");
801 if (stream
->post_sink
)
803 if ((ret
= gst_pad_link(pad
, stream
->post_sink
)) < 0)
805 GST_ERROR("Failed to link decodebin source pad to post-processing elements, error %s.",
806 gst_pad_link_get_name(ret
));
807 gst_object_unref(stream
->post_sink
);
808 stream
->post_sink
= NULL
;
812 if ((ret
= gst_pad_link(stream
->post_src
, stream
->my_sink
)) < 0)
814 GST_ERROR("Failed to link post-processing elements to our sink pad, error %s.",
815 gst_pad_link_get_name(ret
));
816 gst_object_unref(stream
->post_src
);
817 stream
->post_src
= NULL
;
818 gst_object_unref(stream
->post_sink
);
819 stream
->post_sink
= NULL
;
823 else if ((ret
= gst_pad_link(pad
, stream
->my_sink
)) < 0)
825 GST_ERROR("Failed to link decodebin source pad to our sink pad, error %s.",
826 gst_pad_link_get_name(ret
));
830 gst_pad_set_active(stream
->my_sink
, 1);
831 gst_object_ref(stream
->their_src
= pad
);
833 gst_caps_unref(caps
);
836 static void pad_removed_cb(GstElement
*element
, GstPad
*pad
, gpointer user
)
838 struct wg_parser
*parser
= user
;
842 GST_LOG("parser %p, element %p, pad %p.", parser
, element
, pad
);
844 for (i
= 0; i
< parser
->stream_count
; ++i
)
846 struct wg_parser_stream
*stream
= parser
->streams
[i
];
848 if (stream
->their_src
== pad
)
850 if (stream
->post_sink
)
851 gst_pad_unlink(stream
->their_src
, stream
->post_sink
);
853 gst_pad_unlink(stream
->their_src
, stream
->my_sink
);
854 gst_object_unref(stream
->their_src
);
855 stream
->their_src
= NULL
;
860 name
= gst_pad_get_name(pad
);
861 GST_WARNING("No pin matching pad \"%s\" found.", name
);
865 static GstFlowReturn
src_getrange_cb(GstPad
*pad
, GstObject
*parent
,
866 guint64 offset
, guint size
, GstBuffer
**buffer
)
868 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
871 GST_LOG("pad %p, offset %" G_GINT64_MODIFIER
"u, size %u, buffer %p.", pad
, offset
, size
, *buffer
);
873 if (offset
== GST_BUFFER_OFFSET_NONE
)
874 offset
= parser
->next_pull_offset
;
875 parser
->next_pull_offset
= offset
+ size
;
879 /* asfreader occasionally asks for zero bytes. gst_buffer_map() will
880 * return NULL in this case. Avoid confusing the read thread by asking
881 * it for zero bytes. */
883 *buffer
= gst_buffer_new_and_alloc(0);
884 gst_buffer_set_size(*buffer
, 0);
885 GST_LOG("Returning empty buffer.");
889 pthread_mutex_lock(&parser
->mutex
);
891 assert(!parser
->read_request
.size
);
892 parser
->read_request
.buffer
= *buffer
;
893 parser
->read_request
.offset
= offset
;
894 parser
->read_request
.size
= size
;
895 parser
->read_request
.done
= false;
896 pthread_cond_signal(&parser
->read_cond
);
898 /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect
899 * the upstream pin to flush if necessary. We should never be blocked on
900 * read_thread() not running. */
902 while (!parser
->read_request
.done
)
903 pthread_cond_wait(&parser
->read_done_cond
, &parser
->mutex
);
905 *buffer
= parser
->read_request
.buffer
;
906 ret
= parser
->read_request
.ret
;
908 pthread_mutex_unlock(&parser
->mutex
);
910 GST_LOG("Request returned %s.", gst_flow_get_name(ret
));
915 static gboolean
src_query_cb(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
917 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
920 GST_LOG("parser %p, type %s.", parser
, GST_QUERY_TYPE_NAME(query
));
922 switch (GST_QUERY_TYPE(query
))
924 case GST_QUERY_DURATION
:
925 gst_query_parse_duration(query
, &format
, NULL
);
926 if (format
== GST_FORMAT_PERCENT
)
928 gst_query_set_duration(query
, GST_FORMAT_PERCENT
, GST_FORMAT_PERCENT_MAX
);
931 else if (format
== GST_FORMAT_BYTES
)
933 gst_query_set_duration(query
, GST_FORMAT_BYTES
, parser
->file_size
);
938 case GST_QUERY_SEEKING
:
939 gst_query_parse_seeking (query
, &format
, NULL
, NULL
, NULL
);
940 if (format
!= GST_FORMAT_BYTES
)
942 GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format
));
945 gst_query_set_seeking(query
, GST_FORMAT_BYTES
, 1, 0, parser
->file_size
);
948 case GST_QUERY_SCHEDULING
:
949 gst_query_set_scheduling(query
, GST_SCHEDULING_FLAG_SEEKABLE
, 1, -1, 0);
950 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PUSH
);
951 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PULL
);
955 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query
));
960 static void *push_data(void *arg
)
962 struct wg_parser
*parser
= arg
;
966 GST_DEBUG("Starting push thread.");
968 if (!(buffer
= gst_buffer_new_allocate(NULL
, 16384, NULL
)))
970 GST_ERROR("Failed to allocate memory.");
974 max_size
= parser
->stop_offset
? parser
->stop_offset
: parser
->file_size
;
981 if (parser
->next_offset
>= max_size
)
983 size
= min(16384, max_size
- parser
->next_offset
);
985 if ((ret
= src_getrange_cb(parser
->my_src
, NULL
, parser
->next_offset
, size
, &buffer
)) < 0)
987 GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret
));
991 parser
->next_offset
+= size
;
993 buffer
->duration
= buffer
->pts
= -1;
994 if ((ret
= gst_pad_push(parser
->my_src
, buffer
)) < 0)
996 GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret
));
1001 gst_buffer_unref(buffer
);
1003 gst_pad_push_event(parser
->my_src
, gst_event_new_eos());
1005 GST_DEBUG("Stopping push thread.");
1010 static gboolean
activate_push(GstPad
*pad
, gboolean activate
)
1012 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1016 if (parser
->push_thread
)
1018 pthread_join(parser
->push_thread
, NULL
);
1019 parser
->push_thread
= 0;
1022 else if (!parser
->push_thread
)
1026 if ((ret
= pthread_create(&parser
->push_thread
, NULL
, push_data
, parser
)))
1028 GST_ERROR("Failed to create push thread: %s", strerror(errno
));
1029 parser
->push_thread
= 0;
1036 static gboolean
src_activate_mode_cb(GstPad
*pad
, GstObject
*parent
, GstPadMode mode
, gboolean activate
)
1038 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1040 GST_DEBUG("%s source pad for parser %p in %s mode.",
1041 activate
? "Activating" : "Deactivating", parser
, gst_pad_mode_get_name(mode
));
1045 case GST_PAD_MODE_PULL
:
1047 case GST_PAD_MODE_PUSH
:
1048 return activate_push(pad
, activate
);
1049 case GST_PAD_MODE_NONE
:
1055 static GstBusSyncReply
bus_handler_cb(GstBus
*bus
, GstMessage
*msg
, gpointer user
)
1057 struct wg_parser
*parser
= user
;
1058 gchar
*dbg_info
= NULL
;
1061 GST_DEBUG("parser %p, message type %s.", parser
, GST_MESSAGE_TYPE_NAME(msg
));
1065 case GST_MESSAGE_ERROR
:
1066 gst_message_parse_error(msg
, &err
, &dbg_info
);
1067 fprintf(stderr
, "winegstreamer error: %s: %s\n", GST_OBJECT_NAME(msg
->src
), err
->message
);
1068 fprintf(stderr
, "winegstreamer error: %s: %s\n", GST_OBJECT_NAME(msg
->src
), dbg_info
);
1071 pthread_mutex_lock(&parser
->mutex
);
1072 parser
->error
= true;
1073 pthread_mutex_unlock(&parser
->mutex
);
1074 pthread_cond_signal(&parser
->init_cond
);
1077 case GST_MESSAGE_WARNING
:
1078 gst_message_parse_warning(msg
, &err
, &dbg_info
);
1079 fprintf(stderr
, "winegstreamer warning: %s: %s\n", GST_OBJECT_NAME(msg
->src
), err
->message
);
1080 fprintf(stderr
, "winegstreamer warning: %s: %s\n", GST_OBJECT_NAME(msg
->src
), dbg_info
);
1085 case GST_MESSAGE_DURATION_CHANGED
:
1086 pthread_mutex_lock(&parser
->mutex
);
1087 parser
->has_duration
= true;
1088 pthread_mutex_unlock(&parser
->mutex
);
1089 pthread_cond_signal(&parser
->init_cond
);
1095 gst_message_unref(msg
);
1096 return GST_BUS_DROP
;
1099 static gboolean
src_perform_seek(struct wg_parser
*parser
, GstEvent
*event
)
1101 BOOL thread
= !!parser
->push_thread
;
1102 GstSeekType cur_type
, stop_type
;
1103 GstFormat seek_format
;
1104 GstEvent
*flush_event
;
1110 gst_event_parse_seek(event
, &rate
, &seek_format
, &flags
,
1111 &cur_type
, &cur
, &stop_type
, &stop
);
1113 if (seek_format
!= GST_FORMAT_BYTES
)
1115 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format
));
1119 seqnum
= gst_event_get_seqnum(event
);
1121 /* send flush start */
1122 if (flags
& GST_SEEK_FLAG_FLUSH
)
1124 flush_event
= gst_event_new_flush_start();
1125 gst_event_set_seqnum(flush_event
, seqnum
);
1126 gst_pad_push_event(parser
->my_src
, flush_event
);
1128 gst_pad_set_active(parser
->my_src
, 1);
1131 parser
->next_offset
= parser
->start_offset
= cur
;
1133 /* and prepare to continue streaming */
1134 if (flags
& GST_SEEK_FLAG_FLUSH
)
1136 flush_event
= gst_event_new_flush_stop(TRUE
);
1137 gst_event_set_seqnum(flush_event
, seqnum
);
1138 gst_pad_push_event(parser
->my_src
, flush_event
);
1140 gst_pad_set_active(parser
->my_src
, 1);
1146 static gboolean
src_event_cb(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
1148 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1149 gboolean ret
= TRUE
;
1151 GST_LOG("parser %p, type \"%s\".", parser
, GST_EVENT_TYPE_NAME(event
));
1153 switch (event
->type
)
1155 case GST_EVENT_SEEK
:
1156 ret
= src_perform_seek(parser
, event
);
1159 case GST_EVENT_FLUSH_START
:
1160 case GST_EVENT_FLUSH_STOP
:
1162 case GST_EVENT_RECONFIGURE
:
1166 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
1170 gst_event_unref(event
);
1174 static NTSTATUS
wg_parser_connect(void *args
)
1176 GstStaticPadTemplate src_template
= GST_STATIC_PAD_TEMPLATE("quartz_src",
1177 GST_PAD_SRC
, GST_PAD_ALWAYS
, GST_STATIC_CAPS_ANY
);
1178 const struct wg_parser_connect_params
*params
= args
;
1179 struct wg_parser
*parser
= params
->parser
;
1183 parser
->file_size
= params
->file_size
;
1184 parser
->sink_connected
= true;
1188 parser
->bus
= gst_bus_new();
1189 gst_bus_set_sync_handler(parser
->bus
, bus_handler_cb
, parser
, NULL
);
1192 parser
->container
= gst_bin_new(NULL
);
1193 gst_element_set_bus(parser
->container
, parser
->bus
);
1195 parser
->my_src
= gst_pad_new_from_static_template(&src_template
, "quartz-src");
1196 gst_pad_set_getrange_function(parser
->my_src
, src_getrange_cb
);
1197 gst_pad_set_query_function(parser
->my_src
, src_query_cb
);
1198 gst_pad_set_activatemode_function(parser
->my_src
, src_activate_mode_cb
);
1199 gst_pad_set_event_function(parser
->my_src
, src_event_cb
);
1200 gst_pad_set_element_private(parser
->my_src
, parser
);
1202 parser
->start_offset
= parser
->next_offset
= parser
->stop_offset
= 0;
1203 parser
->next_pull_offset
= 0;
1204 parser
->error
= false;
1206 if (!parser
->init_gst(parser
))
1209 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
1210 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
1211 if (ret
== GST_STATE_CHANGE_FAILURE
)
1213 GST_ERROR("Failed to play stream.\n");
1217 pthread_mutex_lock(&parser
->mutex
);
1219 while (!parser
->no_more_pads
&& !parser
->error
)
1220 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1223 pthread_mutex_unlock(&parser
->mutex
);
1227 for (i
= 0; i
< parser
->stream_count
; ++i
)
1229 struct wg_parser_stream
*stream
= parser
->streams
[i
];
1232 while (!stream
->has_caps
&& !parser
->error
)
1233 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1235 /* GStreamer doesn't actually provide any guarantees about when duration
1236 * is available, even for seekable streams. It's basically built for
1237 * applications that don't care, e.g. movie players that can display
1238 * a duration once it's available, and update it visually if a better
1239 * estimate is found. This doesn't really match well with DirectShow or
1240 * Media Foundation, which both expect duration to be available
1241 * immediately on connecting, so we have to use some complex heuristics
1242 * to try to actually get a usable duration.
1244 * Some elements (avidemux, wavparse, qtdemux) record duration almost
1245 * immediately, before fixing caps. Such elements don't send
1246 * duration-changed messages. Therefore always try querying duration
1247 * after caps have been found.
1249 * Some elements (mpegaudioparse) send duration-changed. In the case of
1250 * a mp3 stream without seek tables it will not be sent immediately, but
1251 * only after enough frames have been parsed to form an estimate. They
1252 * may send it multiple times with increasingly accurate estimates, but
1253 * unfortunately we have no way of knowing whether another estimate will
1254 * be sent, so we always take the first one. We assume that if the
1255 * duration is not immediately available then the element will always
1256 * send duration-changed.
1263 pthread_mutex_unlock(&parser
->mutex
);
1266 if (gst_pad_query_duration(stream
->their_src
, GST_FORMAT_TIME
, &duration
))
1268 stream
->duration
= duration
/ 100;
1274 stream
->duration
= 0;
1275 GST_WARNING("Failed to query duration.\n");
1279 /* Elements based on GstBaseParse send duration-changed before
1280 * actually updating the duration in GStreamer versions prior
1281 * to 1.17.1. See <gstreamer.git:d28e0b4147fe7073b2>. So after
1282 * receiving duration-changed we have to continue polling until
1283 * the query succeeds. */
1284 if (parser
->has_duration
)
1286 pthread_mutex_unlock(&parser
->mutex
);
1288 pthread_mutex_lock(&parser
->mutex
);
1292 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1297 pthread_mutex_unlock(&parser
->mutex
);
1299 parser
->next_offset
= 0;
1303 if (parser
->container
)
1304 gst_element_set_state(parser
->container
, GST_STATE_NULL
);
1305 if (parser
->their_sink
)
1307 gst_pad_unlink(parser
->my_src
, parser
->their_sink
);
1308 gst_object_unref(parser
->their_sink
);
1309 parser
->my_src
= parser
->their_sink
= NULL
;
1312 for (i
= 0; i
< parser
->stream_count
; ++i
)
1313 free_stream(parser
->streams
[i
]);
1314 parser
->stream_count
= 0;
1315 free(parser
->streams
);
1316 parser
->streams
= NULL
;
1318 if (parser
->container
)
1320 gst_element_set_bus(parser
->container
, NULL
);
1321 gst_object_unref(parser
->container
);
1322 parser
->container
= NULL
;
1325 pthread_mutex_lock(&parser
->mutex
);
1326 parser
->sink_connected
= false;
1327 pthread_mutex_unlock(&parser
->mutex
);
1328 pthread_cond_signal(&parser
->read_cond
);
1333 static NTSTATUS
wg_parser_disconnect(void *args
)
1335 struct wg_parser
*parser
= args
;
1338 /* Unblock all of our streams. */
1339 pthread_mutex_lock(&parser
->mutex
);
1340 for (i
= 0; i
< parser
->stream_count
; ++i
)
1342 parser
->streams
[i
]->flushing
= true;
1343 pthread_cond_signal(&parser
->streams
[i
]->event_empty_cond
);
1345 pthread_mutex_unlock(&parser
->mutex
);
1347 gst_element_set_state(parser
->container
, GST_STATE_NULL
);
1348 gst_pad_unlink(parser
->my_src
, parser
->their_sink
);
1349 gst_object_unref(parser
->my_src
);
1350 gst_object_unref(parser
->their_sink
);
1351 parser
->my_src
= parser
->their_sink
= NULL
;
1353 pthread_mutex_lock(&parser
->mutex
);
1354 parser
->sink_connected
= false;
1355 pthread_mutex_unlock(&parser
->mutex
);
1356 pthread_cond_signal(&parser
->read_cond
);
1358 for (i
= 0; i
< parser
->stream_count
; ++i
)
1359 free_stream(parser
->streams
[i
]);
1361 parser
->stream_count
= 0;
1362 free(parser
->streams
);
1363 parser
->streams
= NULL
;
1365 gst_element_set_bus(parser
->container
, NULL
);
1366 gst_object_unref(parser
->container
);
1367 parser
->container
= NULL
;
1372 static BOOL
decodebin_parser_init_gst(struct wg_parser
*parser
)
1374 GstElement
*element
;
1377 if (!(element
= create_element("decodebin", "base")))
1380 gst_bin_add(GST_BIN(parser
->container
), element
);
1381 parser
->decodebin
= element
;
1383 if (parser
->unlimited_buffering
)
1385 g_object_set(parser
->decodebin
, "max-size-buffers", G_MAXUINT
, NULL
);
1386 g_object_set(parser
->decodebin
, "max-size-time", G_MAXUINT64
, NULL
);
1387 g_object_set(parser
->decodebin
, "max-size-bytes", G_MAXUINT
, NULL
);
1390 g_signal_connect(element
, "pad-added", G_CALLBACK(pad_added_cb
), parser
);
1391 g_signal_connect(element
, "pad-removed", G_CALLBACK(pad_removed_cb
), parser
);
1392 g_signal_connect(element
, "autoplug-select", G_CALLBACK(autoplug_select_cb
), parser
);
1393 g_signal_connect(element
, "no-more-pads", G_CALLBACK(no_more_pads_cb
), parser
);
1395 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1397 pthread_mutex_lock(&parser
->mutex
);
1398 parser
->no_more_pads
= false;
1399 pthread_mutex_unlock(&parser
->mutex
);
1401 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1403 GST_ERROR("Failed to link pads, error %d.", ret
);
1410 static BOOL
avi_parser_init_gst(struct wg_parser
*parser
)
1412 GstElement
*element
;
1415 if (!(element
= create_element("avidemux", "good")))
1418 gst_bin_add(GST_BIN(parser
->container
), element
);
1420 g_signal_connect(element
, "pad-added", G_CALLBACK(pad_added_cb
), parser
);
1421 g_signal_connect(element
, "pad-removed", G_CALLBACK(pad_removed_cb
), parser
);
1422 g_signal_connect(element
, "no-more-pads", G_CALLBACK(no_more_pads_cb
), parser
);
1424 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1426 pthread_mutex_lock(&parser
->mutex
);
1427 parser
->no_more_pads
= false;
1428 pthread_mutex_unlock(&parser
->mutex
);
1430 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1432 GST_ERROR("Failed to link pads, error %d.", ret
);
1439 static BOOL
mpeg_audio_parser_init_gst(struct wg_parser
*parser
)
1441 struct wg_parser_stream
*stream
;
1442 GstElement
*element
;
1445 if (!(element
= create_element("mpegaudioparse", "good")))
1448 gst_bin_add(GST_BIN(parser
->container
), element
);
1450 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1451 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1453 GST_ERROR("Failed to link sink pads, error %d.", ret
);
1457 if (!(stream
= create_stream(parser
)))
1460 gst_object_ref(stream
->their_src
= gst_element_get_static_pad(element
, "src"));
1461 if ((ret
= gst_pad_link(stream
->their_src
, stream
->my_sink
)) < 0)
1463 GST_ERROR("Failed to link source pads, error %d.", ret
);
1466 gst_pad_set_active(stream
->my_sink
, 1);
1468 parser
->no_more_pads
= true;
1473 static BOOL
wave_parser_init_gst(struct wg_parser
*parser
)
1475 struct wg_parser_stream
*stream
;
1476 GstElement
*element
;
1479 if (!(element
= create_element("wavparse", "good")))
1482 gst_bin_add(GST_BIN(parser
->container
), element
);
1484 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1485 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1487 GST_ERROR("Failed to link sink pads, error %d.", ret
);
1491 if (!(stream
= create_stream(parser
)))
1494 stream
->their_src
= gst_element_get_static_pad(element
, "src");
1495 gst_object_ref(stream
->their_src
);
1496 if ((ret
= gst_pad_link(stream
->their_src
, stream
->my_sink
)) < 0)
1498 GST_ERROR("Failed to link source pads, error %d.", ret
);
1501 gst_pad_set_active(stream
->my_sink
, 1);
1503 parser
->no_more_pads
= true;
1508 static void init_gstreamer_once(void)
1510 char arg0
[] = "wine";
1511 char arg1
[] = "--gst-disable-registry-fork";
1512 char *args
[] = {arg0
, arg1
, NULL
};
1513 int argc
= ARRAY_SIZE(args
) - 1;
1517 if (!gst_init_check(&argc
, &argv
, &err
))
1519 fprintf(stderr
, "winegstreamer: failed to initialize GStreamer: %s\n", err
->message
);
1524 GST_DEBUG_CATEGORY_INIT(wine
, "WINE", GST_DEBUG_FG_RED
, "Wine GStreamer support");
1526 GST_INFO("GStreamer library version %s; wine built with %d.%d.%d.",
1527 gst_version_string(), GST_VERSION_MAJOR
, GST_VERSION_MINOR
, GST_VERSION_MICRO
);
1530 bool init_gstreamer(void)
1532 static pthread_once_t init_once
= PTHREAD_ONCE_INIT
;
1534 return !pthread_once(&init_once
, init_gstreamer_once
);
1537 static NTSTATUS
wg_parser_create(void *args
)
1539 static const init_gst_cb init_funcs
[] =
1541 [WG_PARSER_DECODEBIN
] = decodebin_parser_init_gst
,
1542 [WG_PARSER_AVIDEMUX
] = avi_parser_init_gst
,
1543 [WG_PARSER_MPEGAUDIOPARSE
] = mpeg_audio_parser_init_gst
,
1544 [WG_PARSER_WAVPARSE
] = wave_parser_init_gst
,
1547 struct wg_parser_create_params
*params
= args
;
1548 struct wg_parser
*parser
;
1550 if (!init_gstreamer())
1553 if (!(parser
= calloc(1, sizeof(*parser
))))
1554 return E_OUTOFMEMORY
;
1556 pthread_mutex_init(&parser
->mutex
, NULL
);
1557 pthread_cond_init(&parser
->init_cond
, NULL
);
1558 pthread_cond_init(&parser
->read_cond
, NULL
);
1559 pthread_cond_init(&parser
->read_done_cond
, NULL
);
1560 parser
->init_gst
= init_funcs
[params
->type
];
1561 parser
->unlimited_buffering
= params
->unlimited_buffering
;
1563 GST_DEBUG("Created winegstreamer parser %p.", parser
);
1564 params
->parser
= parser
;
1568 static NTSTATUS
wg_parser_destroy(void *args
)
1570 struct wg_parser
*parser
= args
;
1574 gst_bus_set_sync_handler(parser
->bus
, NULL
, NULL
, NULL
);
1575 gst_object_unref(parser
->bus
);
1578 pthread_mutex_destroy(&parser
->mutex
);
1579 pthread_cond_destroy(&parser
->init_cond
);
1580 pthread_cond_destroy(&parser
->read_cond
);
1581 pthread_cond_destroy(&parser
->read_done_cond
);
1587 const unixlib_entry_t __wine_unix_call_funcs
[] =
1589 #define X(name) [unix_ ## name] = name
1590 X(wg_parser_create
),
1591 X(wg_parser_destroy
),
1593 X(wg_parser_connect
),
1594 X(wg_parser_disconnect
),
1596 X(wg_parser_get_next_read_offset
),
1597 X(wg_parser_push_data
),
1599 X(wg_parser_get_stream_count
),
1600 X(wg_parser_get_stream
),
1602 X(wg_parser_stream_get_preferred_format
),
1603 X(wg_parser_stream_enable
),
1604 X(wg_parser_stream_disable
),
1606 X(wg_parser_stream_get_event
),
1607 X(wg_parser_stream_copy_buffer
),
1608 X(wg_parser_stream_release_buffer
),
1609 X(wg_parser_stream_notify_qos
),
1611 X(wg_parser_stream_get_duration
),
1612 X(wg_parser_stream_seek
),
1614 X(wg_transform_create
),
1615 X(wg_transform_destroy
),