kernelbase: Reimplement LocaleNameToLCID() using the locale.nls data.
[wine.git] / dlls / winegstreamer / wg_parser.c
blobdf563e9336e591c4621814ea57f9269a6e6de812
1 /*
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
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include "config.h"
29 #include <assert.h>
30 #include <stdarg.h>
31 #include <stdio.h>
33 #include <gst/gst.h>
34 #include <gst/video/video.h>
35 #include <gst/audio/audio.h>
37 #include "winternl.h"
38 #include "dshow.h"
40 #include "unix_private.h"
42 typedef enum
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);
59 struct wg_parser
61 init_gst_cb init_gst;
63 struct wg_parser_stream **streams;
64 unsigned int stream_count;
66 GstElement *container, *decodebin;
67 GstBus *bus;
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;
81 struct
83 GstBuffer *buffer;
84 uint64_t offset;
85 uint32_t size;
86 bool done;
87 GstFlowReturn ret;
88 } read_request;
90 bool sink_connected;
92 bool unlimited_buffering;
95 struct wg_parser_stream
97 struct wg_parser *parser;
99 GstPad *their_src, *post_sink, *post_src, *my_sink;
100 GstElement *flip;
101 GstSegment segment;
102 struct wg_format preferred_format, current_format;
104 pthread_cond_t event_cond, event_empty_cond;
105 GstBuffer *buffer;
106 GstMapInfo map_info;
108 bool flushing, eos, enabled, has_caps;
110 uint64_t duration;
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;
118 return S_OK;
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];
126 return S_OK;
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);
149 return S_OK;
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);
161 if (data)
163 if (size)
165 GstMapInfo map_info;
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;
177 else
179 parser->read_request.ret = GST_FLOW_EOS;
182 else
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);
192 return S_OK;
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;
200 return S_OK;
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:
223 flip = !flip;
224 break;
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:
235 break;
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());
242 return S_OK;
245 static NTSTATUS wg_parser_stream_disable(void *args)
247 struct wg_parser_stream *stream = args;
249 stream->enabled = false;
250 return S_OK;
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;
259 GstBuffer *buffer;
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
273 * well. */
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);
285 return S_OK;
288 pthread_mutex_unlock(&parser->mutex);
289 return S_FALSE;
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);
302 if (!stream->buffer)
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);
313 return S_OK;
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);
332 return S_OK;
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;
340 return S_OK;
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");
367 return S_OK;
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;
375 GstEvent *event;
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
379 * running time. */
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");
387 return S_OK;
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);
395 return S_OK;
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));
437 switch (event->type)
439 case GST_EVENT_SEGMENT:
440 if (stream->enabled)
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));
449 break;
452 gst_segment_copy_into(segment, &stream->segment);
454 break;
456 case GST_EVENT_EOS:
457 pthread_mutex_lock(&parser->mutex);
458 stream->eos = true;
459 pthread_mutex_unlock(&parser->mutex);
460 if (stream->enabled)
461 pthread_cond_signal(&stream->event_cond);
462 else
463 pthread_cond_signal(&parser->init_cond);
464 break;
466 case GST_EVENT_FLUSH_START:
467 if (stream->enabled)
469 pthread_mutex_lock(&parser->mutex);
471 stream->flushing = true;
472 pthread_cond_signal(&stream->event_empty_cond);
474 if (stream->buffer)
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);
483 break;
485 case GST_EVENT_FLUSH_STOP:
487 gboolean reset_time;
489 gst_event_parse_flush_stop(event, &reset_time);
491 if (reset_time)
492 gst_segment_init(&stream->segment, GST_FORMAT_UNDEFINED);
494 pthread_mutex_lock(&parser->mutex);
496 stream->eos = false;
497 if (stream->enabled)
498 stream->flushing = false;
500 pthread_mutex_unlock(&parser->mutex);
501 break;
504 case GST_EVENT_CAPS:
506 GstCaps *caps;
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);
514 break;
517 default:
518 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
520 gst_event_unref(event);
521 return TRUE;
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);
534 return GST_FLOW_OK;
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.");
570 return GST_FLOW_OK;
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));
579 switch (query->type)
581 case GST_QUERY_CAPS:
583 GstCaps *caps, *filter, *temp;
584 gchar *str;
586 gst_query_parse_caps(query, &filter);
588 if (stream->enabled)
589 caps = wg_format_to_caps(&stream->current_format);
590 else
591 caps = gst_caps_new_any();
592 if (!caps)
593 return FALSE;
595 str = gst_caps_to_string(caps);
596 GST_LOG("Stream caps are \"%s\".", str);
597 g_free(str);
599 if (filter)
601 temp = gst_caps_intersect(caps, filter);
602 gst_caps_unref(caps);
603 caps = temp;
606 gst_query_set_caps_result(query, caps);
607 gst_caps_unref(caps);
608 return TRUE;
611 case GST_QUERY_ACCEPT_CAPS:
613 struct wg_format format;
614 gboolean ret = TRUE;
615 GstCaps *caps;
617 if (!stream->enabled)
619 gst_query_set_accept_caps_result(query, TRUE);
620 return 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);
630 g_free(str);
632 gst_query_set_accept_caps_result(query, ret);
633 return TRUE;
636 default:
637 return gst_pad_query_default (pad, parent, query);
641 GstElement *create_element(const char *name, const char *plugin_set)
643 GstElement *element;
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);
648 return element;
651 static struct wg_parser_stream *create_stream(struct wg_parser *parser)
653 struct wg_parser_stream *stream, **new_array;
654 char pad_name[19];
656 if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams))))
657 return NULL;
658 parser->streams = new_array;
660 if (!(stream = calloc(1, sizeof(*stream))))
661 return NULL;
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;
677 return 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);
697 free(stream);
700 static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user)
702 struct wg_parser *parser = user;
703 struct wg_parser_stream *stream;
704 const char *name;
705 GstCaps *caps;
706 int ret;
708 GST_LOG("parser %p, element %p, pad %p.", parser, element, pad);
710 if (gst_pad_is_linked(pad))
711 return;
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)))
717 goto out;
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")))
726 goto out;
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")))
732 goto out;
734 /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
735 if (!(flip = create_element("videoflip", "good")))
736 goto out;
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")))
741 goto out;
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");
759 stream->flip = flip;
761 else if (!strcmp(name, "audio/x-raw"))
763 GstElement *convert;
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")))
770 goto out;
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;
787 goto out;
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;
798 goto out;
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));
805 goto out;
808 gst_pad_set_active(stream->my_sink, 1);
809 gst_object_ref(stream->their_src = pad);
810 out:
811 gst_caps_unref(caps);
814 static void pad_removed_cb(GstElement *element, GstPad *pad, gpointer user)
816 struct wg_parser *parser = user;
817 unsigned int i;
818 char *name;
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);
830 else
831 gst_pad_unlink(stream->their_src, stream->my_sink);
832 gst_object_unref(stream->their_src);
833 stream->their_src = NULL;
834 return;
838 name = gst_pad_get_name(pad);
839 GST_WARNING("No pin matching pad \"%s\" found.", name);
840 g_free(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);
847 GstFlowReturn ret;
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;
855 if (!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. */
860 if (!*buffer)
861 *buffer = gst_buffer_new_and_alloc(0);
862 gst_buffer_set_size(*buffer, 0);
863 GST_LOG("Returning empty buffer.");
864 return GST_FLOW_OK;
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));
890 return ret;
893 static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query)
895 struct wg_parser *parser = gst_pad_get_element_private(pad);
896 GstFormat format;
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);
907 return TRUE;
909 else if (format == GST_FORMAT_BYTES)
911 gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size);
912 return TRUE;
914 return FALSE;
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));
921 return FALSE;
923 gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size);
924 return TRUE;
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);
930 return TRUE;
932 default:
933 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query));
934 return FALSE;
938 static void *push_data(void *arg)
940 struct wg_parser *parser = arg;
941 GstBuffer *buffer;
942 guint max_size;
944 GST_DEBUG("Starting push thread.");
946 if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL)))
948 GST_ERROR("Failed to allocate memory.");
949 return NULL;
952 max_size = parser->stop_offset ? parser->stop_offset : parser->file_size;
954 for (;;)
956 ULONG size;
957 int ret;
959 if (parser->next_offset >= max_size)
960 break;
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));
966 break;
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));
975 break;
979 gst_buffer_unref(buffer);
981 gst_pad_push_event(parser->my_src, gst_event_new_eos());
983 GST_DEBUG("Stopping push thread.");
985 return NULL;
988 static gboolean activate_push(GstPad *pad, gboolean activate)
990 struct wg_parser *parser = gst_pad_get_element_private(pad);
992 if (!activate)
994 if (parser->push_thread)
996 pthread_join(parser->push_thread, NULL);
997 parser->push_thread = 0;
1000 else if (!parser->push_thread)
1002 int ret;
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;
1008 return FALSE;
1011 return TRUE;
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));
1021 switch (mode)
1023 case GST_PAD_MODE_PULL:
1024 return TRUE;
1025 case GST_PAD_MODE_PUSH:
1026 return activate_push(pad, activate);
1027 case GST_PAD_MODE_NONE:
1028 break;
1030 return FALSE;
1033 static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer user)
1035 struct wg_parser *parser = user;
1036 gchar *dbg_info = NULL;
1037 GError *err = NULL;
1039 GST_DEBUG("parser %p, message type %s.", parser, GST_MESSAGE_TYPE_NAME(msg));
1041 switch (msg->type)
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);
1047 g_error_free(err);
1048 g_free(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);
1053 break;
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);
1059 g_error_free(err);
1060 g_free(dbg_info);
1061 break;
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);
1068 break;
1070 default:
1071 break;
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;
1083 GstSeekFlags flags;
1084 gint64 cur, stop;
1085 guint32 seqnum;
1086 gdouble rate;
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));
1094 return FALSE;
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);
1105 if (thread)
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);
1117 if (thread)
1118 gst_pad_set_active(parser->my_src, 1);
1121 return TRUE;
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);
1135 break;
1137 case GST_EVENT_FLUSH_START:
1138 case GST_EVENT_FLUSH_STOP:
1139 case GST_EVENT_QOS:
1140 case GST_EVENT_RECONFIGURE:
1141 break;
1143 default:
1144 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
1145 ret = FALSE;
1146 break;
1148 gst_event_unref(event);
1149 return ret;
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;
1158 unsigned int i;
1159 int ret;
1161 parser->file_size = params->file_size;
1162 parser->sink_connected = true;
1164 if (!parser->bus)
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))
1185 goto out;
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");
1192 goto out;
1195 pthread_mutex_lock(&parser->mutex);
1197 while (!parser->no_more_pads && !parser->error)
1198 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1199 if (parser->error)
1201 pthread_mutex_unlock(&parser->mutex);
1202 goto out;
1205 for (i = 0; i < parser->stream_count; ++i)
1207 struct wg_parser_stream *stream = parser->streams[i];
1208 gint64 duration;
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.
1237 for (;;)
1239 if (parser->error)
1241 pthread_mutex_unlock(&parser->mutex);
1242 goto out;
1244 if (gst_pad_query_duration(stream->their_src, GST_FORMAT_TIME, &duration))
1246 stream->duration = duration / 100;
1247 break;
1250 if (stream->eos)
1252 stream->duration = 0;
1253 GST_WARNING("Failed to query duration.\n");
1254 break;
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);
1265 g_usleep(10000);
1266 pthread_mutex_lock(&parser->mutex);
1268 else
1270 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1275 pthread_mutex_unlock(&parser->mutex);
1277 parser->next_offset = 0;
1278 return S_OK;
1280 out:
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);
1307 return E_FAIL;
1310 static NTSTATUS wg_parser_disconnect(void *args)
1312 struct wg_parser *parser = args;
1313 unsigned int i;
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;
1345 return S_OK;
1348 static BOOL decodebin_parser_init_gst(struct wg_parser *parser)
1350 GstElement *element;
1351 int ret;
1353 if (!(element = create_element("decodebin", "base")))
1354 return FALSE;
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);
1380 return FALSE;
1383 return TRUE;
1386 static BOOL avi_parser_init_gst(struct wg_parser *parser)
1388 GstElement *element;
1389 int ret;
1391 if (!(element = create_element("avidemux", "good")))
1392 return FALSE;
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);
1409 return FALSE;
1412 return TRUE;
1415 static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser)
1417 struct wg_parser_stream *stream;
1418 GstElement *element;
1419 int ret;
1421 if (!(element = create_element("mpegaudioparse", "good")))
1422 return FALSE;
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);
1430 return FALSE;
1433 if (!(stream = create_stream(parser)))
1434 return FALSE;
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);
1440 return FALSE;
1442 gst_pad_set_active(stream->my_sink, 1);
1444 parser->no_more_pads = true;
1446 return TRUE;
1449 static BOOL wave_parser_init_gst(struct wg_parser *parser)
1451 struct wg_parser_stream *stream;
1452 GstElement *element;
1453 int ret;
1455 if (!(element = create_element("wavparse", "good")))
1456 return FALSE;
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);
1464 return FALSE;
1467 if (!(stream = create_stream(parser)))
1468 return FALSE;
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);
1475 return FALSE;
1477 gst_pad_set_active(stream->my_sink, 1);
1479 parser->no_more_pads = true;
1481 return 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;
1490 char **argv = args;
1491 GError *err;
1493 if (!gst_init_check(&argc, &argv, &err))
1495 fprintf(stderr, "winegstreamer: failed to initialize GStreamer: %s\n", err->message);
1496 g_error_free(err);
1497 return;
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())
1527 return E_FAIL;
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;
1541 return S_OK;
1544 static NTSTATUS wg_parser_destroy(void *args)
1546 struct wg_parser *parser = args;
1548 if (parser->bus)
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);
1559 free(parser);
1560 return S_OK;
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),