d3dx9: Unify calling parse_mesh helper functions.
[wine.git] / dlls / winegstreamer / wg_parser.c
blob84bb65dbccd7258e99e9f26c8e7a980ed5ddc854
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>
36 #include <gst/tag/tag.h>
38 #include "ntstatus.h"
39 #define WIN32_NO_STATUS
40 #include "winternl.h"
41 #include "dshow.h"
43 #include "unix_private.h"
45 typedef enum
47 GST_AUTOPLUG_SELECT_TRY,
48 GST_AUTOPLUG_SELECT_EXPOSE,
49 GST_AUTOPLUG_SELECT_SKIP,
50 } GstAutoplugSelectResult;
52 struct wg_parser;
54 typedef BOOL (*init_gst_cb)(struct wg_parser *parser);
56 struct input_cache_chunk
58 guint64 position;
59 uint8_t *data;
62 struct wg_parser
64 init_gst_cb init_gst;
66 struct wg_parser_stream **streams;
67 unsigned int stream_count;
69 GstElement *container, *decodebin;
70 GstBus *bus;
71 GstPad *my_src;
73 guint64 file_size, start_offset, next_offset, stop_offset;
74 guint64 next_pull_offset;
76 pthread_t push_thread;
78 pthread_mutex_t mutex;
80 pthread_cond_t init_cond;
81 bool output_compressed;
82 bool no_more_pads, has_duration, error;
83 bool err_on, warn_on;
85 pthread_cond_t read_cond, read_done_cond;
86 struct
88 GstBuffer *buffer;
89 uint64_t offset;
90 uint32_t size;
91 bool done;
92 GstFlowReturn ret;
93 } read_request;
95 bool sink_connected;
97 gchar *sink_caps;
99 struct input_cache_chunk input_cache_chunks[4];
101 static const unsigned int input_cache_chunk_size = 512 << 10;
103 struct wg_parser_stream
105 struct wg_parser *parser;
106 uint32_t number;
108 GstPad *my_sink;
109 GstElement *flip, *decodebin;
110 GstSegment segment;
111 struct wg_format preferred_format, current_format, codec_format;
113 pthread_cond_t event_cond, event_empty_cond;
114 GstBuffer *buffer;
115 GstMapInfo map_info;
117 bool flushing, eos, enabled, has_caps, has_tags, has_buffer, no_more_pads;
119 uint64_t duration;
120 gchar *tags[WG_PARSER_TAG_COUNT];
123 static struct wg_parser *get_parser(wg_parser_t parser)
125 return (struct wg_parser *)(ULONG_PTR)parser;
128 static struct wg_parser_stream *get_stream(wg_parser_stream_t stream)
130 return (struct wg_parser_stream *)(ULONG_PTR)stream;
133 static bool format_is_compressed(struct wg_format *format)
135 return format->major_type != WG_MAJOR_TYPE_UNKNOWN
136 && format->major_type != WG_MAJOR_TYPE_VIDEO
137 && format->major_type != WG_MAJOR_TYPE_AUDIO;
140 static NTSTATUS wg_parser_get_stream_count(void *args)
142 struct wg_parser_get_stream_count_params *params = args;
144 params->count = get_parser(params->parser)->stream_count;
145 return S_OK;
148 static NTSTATUS wg_parser_get_stream(void *args)
150 struct wg_parser_get_stream_params *params = args;
152 params->stream = (wg_parser_stream_t)(ULONG_PTR)get_parser(params->parser)->streams[params->index];
153 return S_OK;
156 static NTSTATUS wg_parser_get_next_read_offset(void *args)
158 struct wg_parser_get_next_read_offset_params *params = args;
159 struct wg_parser *parser = get_parser(params->parser);
161 pthread_mutex_lock(&parser->mutex);
163 while (parser->sink_connected && !parser->read_request.size)
164 pthread_cond_wait(&parser->read_cond, &parser->mutex);
166 if (!parser->sink_connected)
168 pthread_mutex_unlock(&parser->mutex);
169 return VFW_E_WRONG_STATE;
172 params->offset = parser->read_request.offset;
173 params->size = parser->read_request.size;
175 pthread_mutex_unlock(&parser->mutex);
176 return S_OK;
179 static NTSTATUS wg_parser_push_data(void *args)
181 const struct wg_parser_push_data_params *params = args;
182 struct wg_parser *parser = get_parser(params->parser);
183 const void *data = params->data;
184 uint32_t size = params->size;
186 pthread_mutex_lock(&parser->mutex);
188 if (data)
190 if (size)
192 GstMapInfo map_info;
194 /* Note that we don't allocate the buffer until we have a size.
195 * midiparse passes a NULL buffer and a size of UINT_MAX, in an
196 * apparent attempt to read the whole input stream at once. */
197 if (!parser->read_request.buffer)
198 parser->read_request.buffer = gst_buffer_new_and_alloc(size);
199 gst_buffer_map(parser->read_request.buffer, &map_info, GST_MAP_WRITE);
200 memcpy(map_info.data, data, size);
201 gst_buffer_unmap(parser->read_request.buffer, &map_info);
202 parser->read_request.ret = GST_FLOW_OK;
204 else
206 parser->read_request.ret = GST_FLOW_EOS;
209 else
211 parser->read_request.ret = GST_FLOW_ERROR;
213 parser->read_request.done = true;
214 parser->read_request.size = 0;
216 pthread_mutex_unlock(&parser->mutex);
217 pthread_cond_signal(&parser->read_done_cond);
219 return S_OK;
222 static NTSTATUS wg_parser_stream_get_preferred_format(void *args)
224 const struct wg_parser_stream_get_preferred_format_params *params = args;
226 *params->format = get_stream(params->stream)->preferred_format;
227 return S_OK;
230 static NTSTATUS wg_parser_stream_get_codec_format(void *args)
232 struct wg_parser_stream_get_codec_format_params *params = args;
233 struct wg_parser_stream *stream = get_stream(params->stream);
235 *params->format = format_is_compressed(&stream->codec_format) ?
236 stream->codec_format :
237 stream->preferred_format;
238 return S_OK;
241 static NTSTATUS wg_parser_stream_enable(void *args)
243 const struct wg_parser_stream_enable_params *params = args;
244 struct wg_parser_stream *stream = get_stream(params->stream);
245 const struct wg_format *format = params->format;
246 struct wg_parser *parser = stream->parser;
248 pthread_mutex_lock(&parser->mutex);
250 stream->current_format = *format;
251 stream->enabled = true;
253 pthread_mutex_unlock(&parser->mutex);
255 if (format->major_type == WG_MAJOR_TYPE_VIDEO)
257 bool flip = (format->u.video.height < 0);
259 gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none");
262 push_event(stream->my_sink, gst_event_new_reconfigure());
263 return S_OK;
266 static NTSTATUS wg_parser_stream_disable(void *args)
268 struct wg_parser_stream *stream = get_stream(*(wg_parser_stream_t *)args);
269 struct wg_parser *parser = stream->parser;
271 pthread_mutex_lock(&parser->mutex);
272 stream->enabled = false;
273 stream->current_format.major_type = WG_MAJOR_TYPE_UNKNOWN;
274 pthread_mutex_unlock(&parser->mutex);
275 pthread_cond_signal(&stream->event_empty_cond);
276 return S_OK;
279 static GstBuffer *wait_parser_stream_buffer(struct wg_parser *parser, struct wg_parser_stream *stream)
281 GstBuffer *buffer = NULL;
283 /* Note that we can both have a buffer and stream->eos, in which case we
284 * must return the buffer. */
286 while (stream->enabled && !(buffer = stream->buffer) && !stream->eos)
287 pthread_cond_wait(&stream->event_cond, &parser->mutex);
289 return buffer;
292 static NTSTATUS wg_parser_stream_get_buffer(void *args)
294 const struct wg_parser_stream_get_buffer_params *params = args;
295 struct wg_parser_buffer *wg_buffer = params->buffer;
296 struct wg_parser_stream *stream = get_stream(params->stream);
297 struct wg_parser *parser = get_parser(params->parser);
298 GstBuffer *buffer;
299 unsigned int i;
301 pthread_mutex_lock(&parser->mutex);
303 if (stream)
304 buffer = wait_parser_stream_buffer(parser, stream);
305 else
307 /* Find the earliest buffer by PTS.
309 * Native seems to behave similarly to this with the wm async reader, although our
310 * unit tests show that it's not entirely consistent—some frames are received
311 * slightly out of order. It's possible that one stream is being manually offset
312 * to account for decoding latency.
314 * The behaviour with the wm sync reader, when stream 0 is requested, seems
315 * consistent with this hypothesis, but with a much larger offset—the video
316 * stream seems to be "behind" by about 150 ms.
318 * The main reason for doing this is that the video and audio stream probably
319 * don't have quite the same "frame rate", and we don't want to force one stream
320 * to decode faster just to keep up with the other. Delivering samples in PTS
321 * order should avoid that problem. */
322 GstBuffer *earliest = NULL;
324 for (i = 0; i < parser->stream_count; ++i)
326 if (!(buffer = wait_parser_stream_buffer(parser, parser->streams[i])))
327 continue;
328 /* invalid PTS is GST_CLOCK_TIME_NONE == (guint64)-1, so this will prefer valid timestamps. */
329 if (!earliest || GST_BUFFER_PTS(buffer) < GST_BUFFER_PTS(earliest))
331 stream = parser->streams[i];
332 earliest = buffer;
336 buffer = earliest;
339 if (!buffer)
341 pthread_mutex_unlock(&parser->mutex);
342 return S_FALSE;
345 /* FIXME: Should we use gst_segment_to_stream_time_full()? Under what
346 * circumstances is the stream time not equal to the buffer PTS? Note
347 * that this will need modification to wg_parser_stream_notify_qos() as
348 * well. */
350 if ((wg_buffer->has_pts = GST_BUFFER_PTS_IS_VALID(buffer)))
351 wg_buffer->pts = GST_BUFFER_PTS(buffer) / 100;
352 if ((wg_buffer->has_duration = GST_BUFFER_DURATION_IS_VALID(buffer)))
353 wg_buffer->duration = GST_BUFFER_DURATION(buffer) / 100;
354 wg_buffer->discontinuity = GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT);
355 wg_buffer->preroll = GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_LIVE);
356 wg_buffer->delta = GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
357 wg_buffer->size = gst_buffer_get_size(buffer);
358 wg_buffer->stream = stream->number;
360 pthread_mutex_unlock(&parser->mutex);
361 return S_OK;
364 static NTSTATUS wg_parser_stream_copy_buffer(void *args)
366 const struct wg_parser_stream_copy_buffer_params *params = args;
367 struct wg_parser_stream *stream = get_stream(params->stream);
368 struct wg_parser *parser = stream->parser;
369 uint32_t offset = params->offset;
370 uint32_t size = params->size;
372 pthread_mutex_lock(&parser->mutex);
374 if (!stream->buffer)
376 pthread_mutex_unlock(&parser->mutex);
377 return VFW_E_WRONG_STATE;
380 assert(offset < stream->map_info.size);
381 assert(offset + size <= stream->map_info.size);
382 memcpy(params->data, stream->map_info.data + offset, size);
384 pthread_mutex_unlock(&parser->mutex);
385 return S_OK;
388 static NTSTATUS wg_parser_stream_release_buffer(void *args)
390 struct wg_parser_stream *stream = get_stream(*(wg_parser_stream_t *)args);
391 struct wg_parser *parser = stream->parser;
393 pthread_mutex_lock(&parser->mutex);
395 assert(stream->buffer);
397 gst_buffer_unmap(stream->buffer, &stream->map_info);
398 gst_buffer_unref(stream->buffer);
399 stream->buffer = NULL;
401 pthread_mutex_unlock(&parser->mutex);
402 pthread_cond_signal(&stream->event_empty_cond);
404 return S_OK;
407 static NTSTATUS wg_parser_stream_get_duration(void *args)
409 struct wg_parser_stream_get_duration_params *params = args;
411 params->duration = get_stream(params->stream)->duration;
412 return S_OK;
415 static NTSTATUS wg_parser_stream_get_tag(void *args)
417 struct wg_parser_stream_get_tag_params *params = args;
418 struct wg_parser_stream *stream = get_stream(params->stream);
419 uint32_t len;
421 if (params->tag >= WG_PARSER_TAG_COUNT)
422 return STATUS_INVALID_PARAMETER;
423 if (!stream->tags[params->tag])
424 return STATUS_NOT_FOUND;
425 if ((len = strlen(stream->tags[params->tag]) + 1) > *params->size)
427 *params->size = len;
428 return STATUS_BUFFER_TOO_SMALL;
430 memcpy(params->buffer, stream->tags[params->tag], len);
431 return STATUS_SUCCESS;
434 static NTSTATUS wg_parser_stream_seek(void *args)
436 GstSeekType start_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET;
437 const struct wg_parser_stream_seek_params *params = args;
438 DWORD start_flags = params->start_flags;
439 DWORD stop_flags = params->stop_flags;
440 const struct wg_parser_stream *stream;
441 GstSeekFlags flags = 0;
443 stream = get_stream(params->stream);
445 if (start_flags & AM_SEEKING_SeekToKeyFrame)
446 flags |= GST_SEEK_FLAG_KEY_UNIT;
447 if (start_flags & AM_SEEKING_Segment)
448 flags |= GST_SEEK_FLAG_SEGMENT;
449 if (!(start_flags & AM_SEEKING_NoFlush))
450 flags |= GST_SEEK_FLAG_FLUSH;
452 if ((start_flags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
453 start_type = GST_SEEK_TYPE_NONE;
454 if ((stop_flags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
455 stop_type = GST_SEEK_TYPE_NONE;
457 if (!push_event(stream->my_sink, gst_event_new_seek(params->rate, GST_FORMAT_TIME,
458 flags, start_type, params->start_pos * 100, stop_type,
459 params->stop_pos == stream->duration ? -1 : params->stop_pos * 100)))
460 GST_ERROR("Failed to seek.");
462 return S_OK;
465 static NTSTATUS wg_parser_stream_notify_qos(void *args)
467 const struct wg_parser_stream_notify_qos_params *params = args;
468 struct wg_parser_stream *stream = get_stream(params->stream);
469 GstClockTimeDiff diff = params->diff * 100;
470 GstClockTime stream_time;
471 GstEvent *event;
473 /* We return timestamps in stream time, i.e. relative to the start of the
474 * file (or other medium), but gst_event_new_qos() expects the timestamp in
475 * running time. */
476 stream_time = gst_segment_to_running_time(&stream->segment, GST_FORMAT_TIME, params->timestamp * 100);
477 if (diff < (GstClockTimeDiff)-stream_time)
478 diff = -stream_time;
479 if (stream_time == -1)
481 /* This can happen legitimately if the sample falls outside of the
482 * segment bounds. GStreamer elements shouldn't present the sample in
483 * that case, but DirectShow doesn't care. */
484 GST_LOG("Ignoring QoS event.");
485 return S_OK;
487 if (!(event = gst_event_new_qos(params->underflow ? GST_QOS_TYPE_UNDERFLOW : GST_QOS_TYPE_OVERFLOW,
488 params->proportion, diff, stream_time)))
489 GST_ERROR("Failed to create QOS event.");
490 push_event(stream->my_sink, event);
492 return S_OK;
495 static bool parser_no_more_pads(struct wg_parser *parser)
497 unsigned int i;
499 for (i = 0; i < parser->stream_count; ++i)
501 if (!parser->streams[i]->no_more_pads)
502 return false;
505 return parser->no_more_pads;
508 static gboolean autoplug_continue_cb(GstElement * decodebin, GstPad *pad, GstCaps * caps, gpointer user)
510 struct wg_format format;
512 wg_format_from_caps(&format, caps);
514 return !format_is_compressed(&format);
517 static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad,
518 GstCaps *caps, GstElementFactory *fact, gpointer user)
520 struct wg_parser *parser = user;
521 const char *name = gst_element_factory_get_longname(fact);
522 const char *klass = gst_element_factory_get_klass(fact);
524 GST_INFO("Using \"%s\".", name);
526 if (strstr(name, "Player protection"))
528 GST_WARNING("Blacklisted a/52 decoder because it only works in Totem.");
529 return GST_AUTOPLUG_SELECT_SKIP;
531 if (!strcmp(name, "Fluendo Hardware Accelerated Video Decoder"))
533 GST_WARNING("Disabled video acceleration since it breaks in wine.");
534 return GST_AUTOPLUG_SELECT_SKIP;
537 if (!parser->sink_caps && strstr(klass, GST_ELEMENT_FACTORY_KLASS_DEMUXER))
538 parser->sink_caps = g_strdup(gst_structure_get_name(gst_caps_get_structure(caps, 0)));
540 return GST_AUTOPLUG_SELECT_TRY;
543 static void no_more_pads_cb(GstElement *element, gpointer user)
545 struct wg_parser *parser = user;
547 GST_DEBUG("parser %p.", parser);
549 pthread_mutex_lock(&parser->mutex);
550 parser->no_more_pads = true;
551 pthread_mutex_unlock(&parser->mutex);
552 pthread_cond_signal(&parser->init_cond);
555 static gboolean sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event)
557 struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
558 struct wg_parser *parser = stream->parser;
560 GST_LOG("stream %p, type \"%s\".", stream, GST_EVENT_TYPE_NAME(event));
562 switch (event->type)
564 case GST_EVENT_SEGMENT:
565 pthread_mutex_lock(&parser->mutex);
566 if (stream->enabled)
568 const GstSegment *segment;
570 gst_event_parse_segment(event, &segment);
572 if (segment->format != GST_FORMAT_TIME)
574 pthread_mutex_unlock(&parser->mutex);
575 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(segment->format));
576 break;
579 gst_segment_copy_into(segment, &stream->segment);
581 pthread_mutex_unlock(&parser->mutex);
582 break;
584 case GST_EVENT_EOS:
585 pthread_mutex_lock(&parser->mutex);
586 stream->eos = true;
587 if (stream->enabled)
588 pthread_cond_signal(&stream->event_cond);
589 else
590 pthread_cond_signal(&parser->init_cond);
591 pthread_mutex_unlock(&parser->mutex);
592 break;
594 case GST_EVENT_FLUSH_START:
595 pthread_mutex_lock(&parser->mutex);
597 if (stream->enabled)
599 stream->flushing = true;
600 pthread_cond_signal(&stream->event_empty_cond);
602 if (stream->buffer)
604 gst_buffer_unmap(stream->buffer, &stream->map_info);
605 gst_buffer_unref(stream->buffer);
606 stream->buffer = NULL;
610 pthread_mutex_unlock(&parser->mutex);
611 break;
613 case GST_EVENT_FLUSH_STOP:
615 gboolean reset_time;
617 gst_event_parse_flush_stop(event, &reset_time);
619 if (reset_time)
620 gst_segment_init(&stream->segment, GST_FORMAT_UNDEFINED);
622 pthread_mutex_lock(&parser->mutex);
624 stream->eos = false;
625 if (stream->enabled)
626 stream->flushing = false;
628 pthread_mutex_unlock(&parser->mutex);
629 break;
632 case GST_EVENT_CAPS:
634 GstCaps *caps;
636 gst_event_parse_caps(event, &caps);
637 pthread_mutex_lock(&parser->mutex);
638 wg_format_from_caps(&stream->preferred_format, caps);
639 stream->has_caps = true;
640 pthread_mutex_unlock(&parser->mutex);
641 pthread_cond_signal(&parser->init_cond);
642 break;
645 case GST_EVENT_TAG:
646 pthread_mutex_lock(&parser->mutex);
647 stream->has_tags = true;
648 pthread_cond_signal(&parser->init_cond);
649 pthread_mutex_unlock(&parser->mutex);
650 break;
652 default:
653 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
655 gst_event_unref(event);
656 return TRUE;
659 static GstFlowReturn sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer)
661 struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
662 struct wg_parser *parser = stream->parser;
664 GST_LOG("stream %p, buffer %p.", stream, buffer);
666 pthread_mutex_lock(&parser->mutex);
668 if (!stream->has_buffer)
670 stream->has_buffer = true;
671 pthread_cond_signal(&parser->init_cond);
674 /* Allow this buffer to be flushed by GStreamer. We are effectively
675 * implementing a queue object here. */
677 while (stream->enabled && !stream->flushing && stream->buffer)
678 pthread_cond_wait(&stream->event_empty_cond, &parser->mutex);
680 if (!stream->enabled)
682 GST_LOG("Stream is disabled; discarding buffer.");
683 pthread_mutex_unlock(&parser->mutex);
684 gst_buffer_unref(buffer);
685 return GST_FLOW_OK;
688 if (stream->flushing)
690 pthread_mutex_unlock(&parser->mutex);
691 GST_DEBUG("Stream is flushing; discarding buffer.");
692 gst_buffer_unref(buffer);
693 return GST_FLOW_FLUSHING;
696 if (!gst_buffer_map(buffer, &stream->map_info, GST_MAP_READ))
698 pthread_mutex_unlock(&parser->mutex);
699 GST_ERROR("Failed to map buffer.");
700 gst_buffer_unref(buffer);
701 return GST_FLOW_ERROR;
704 stream->buffer = buffer;
706 pthread_mutex_unlock(&parser->mutex);
707 pthread_cond_signal(&stream->event_cond);
709 /* The chain callback is given a reference to the buffer. Transfer that
710 * reference to the stream object, which will release it in
711 * wg_parser_stream_release_buffer(). */
713 GST_LOG("Buffer queued.");
714 return GST_FLOW_OK;
717 static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query)
719 struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
720 struct wg_parser *parser = stream->parser;
722 GST_LOG("stream %p, type \"%s\".", stream, gst_query_type_get_name(query->type));
724 switch (query->type)
726 case GST_QUERY_CAPS:
728 GstCaps *caps, *filter, *temp;
729 gsize i;
731 gst_query_parse_caps(query, &filter);
733 pthread_mutex_lock(&parser->mutex);
734 caps = wg_format_to_caps(&stream->current_format);
735 pthread_mutex_unlock(&parser->mutex);
737 if (!caps)
738 return FALSE;
740 /* Clear some fields that shouldn't prevent us from connecting. */
741 for (i = 0; i < gst_caps_get_size(caps); ++i)
742 gst_structure_remove_fields(gst_caps_get_structure(caps, i),
743 "framerate", "pixel-aspect-ratio", NULL);
745 GST_LOG("Stream caps are \"%" GST_PTR_FORMAT "\".", caps);
747 if (filter)
749 temp = gst_caps_intersect(caps, filter);
750 gst_caps_unref(caps);
751 caps = temp;
754 gst_query_set_caps_result(query, caps);
755 gst_caps_unref(caps);
756 return TRUE;
759 case GST_QUERY_ACCEPT_CAPS:
761 struct wg_format format;
762 gboolean ret = TRUE;
763 GstCaps *caps;
765 pthread_mutex_lock(&parser->mutex);
767 if (stream->current_format.major_type == WG_MAJOR_TYPE_UNKNOWN)
769 pthread_mutex_unlock(&parser->mutex);
770 gst_query_set_accept_caps_result(query, TRUE);
771 return TRUE;
774 gst_query_parse_accept_caps(query, &caps);
775 wg_format_from_caps(&format, caps);
776 ret = wg_format_compare(&format, &stream->current_format);
778 pthread_mutex_unlock(&parser->mutex);
780 if (!ret)
781 GST_WARNING("Rejecting caps \"%" GST_PTR_FORMAT "\".", caps);
782 gst_query_set_accept_caps_result(query, ret);
783 return TRUE;
786 default:
787 return gst_pad_query_default (pad, parent, query);
791 static struct wg_parser_stream *create_stream(struct wg_parser *parser)
793 struct wg_parser_stream *stream, **new_array;
794 char pad_name[19];
796 if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams))))
797 return NULL;
798 parser->streams = new_array;
800 if (!(stream = calloc(1, sizeof(*stream))))
801 return NULL;
803 gst_segment_init(&stream->segment, GST_FORMAT_UNDEFINED);
805 stream->parser = parser;
806 stream->number = parser->stream_count;
807 stream->no_more_pads = true;
808 stream->current_format.major_type = WG_MAJOR_TYPE_UNKNOWN;
809 pthread_cond_init(&stream->event_cond, NULL);
810 pthread_cond_init(&stream->event_empty_cond, NULL);
812 sprintf(pad_name, "qz_sink_%u", parser->stream_count);
813 stream->my_sink = gst_pad_new(pad_name, GST_PAD_SINK);
814 gst_pad_set_element_private(stream->my_sink, stream);
815 gst_pad_set_chain_function(stream->my_sink, sink_chain_cb);
816 gst_pad_set_event_function(stream->my_sink, sink_event_cb);
817 gst_pad_set_query_function(stream->my_sink, sink_query_cb);
819 parser->streams[parser->stream_count++] = stream;
820 return stream;
823 static void free_stream(struct wg_parser_stream *stream)
825 unsigned int i;
827 gst_object_unref(stream->my_sink);
829 if (stream->buffer)
831 gst_buffer_unmap(stream->buffer, &stream->map_info);
832 gst_buffer_unref(stream->buffer);
833 stream->buffer = NULL;
836 pthread_cond_destroy(&stream->event_cond);
837 pthread_cond_destroy(&stream->event_empty_cond);
839 for (i = 0; i < ARRAY_SIZE(stream->tags); ++i)
841 if (stream->tags[i])
842 g_free(stream->tags[i]);
844 free(stream);
847 static bool stream_create_post_processing_elements(GstPad *pad, struct wg_parser_stream *stream)
849 GstElement *element = NULL, *first = NULL, *last = NULL;
850 struct wg_parser *parser = stream->parser;
851 const char *name;
852 GstCaps *caps;
854 caps = gst_pad_query_caps(pad, NULL);
855 name = gst_structure_get_name(gst_caps_get_structure(caps, 0));
856 gst_caps_unref(caps);
858 if (!strcmp(name, "video/x-raw"))
860 /* DirectShow can express interlaced video, but downstream filters can't
861 * necessarily consume it. In particular, the video renderer can't. */
862 if (!(element = create_element("deinterlace", "good"))
863 || !append_element(parser->container, element, &first, &last))
864 return false;
866 /* decodebin considers many YUV formats to be "raw", but some quartz
867 * filters can't handle those. Also, videoflip can't handle all "raw"
868 * formats either. Add a videoconvert to swap color spaces. */
869 if (!(element = create_element("videoconvert", "base"))
870 || !append_element(parser->container, element, &first, &last))
871 return false;
873 /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
874 if (!(element = create_element("videoflip", "good"))
875 || !append_element(parser->container, element, &first, &last))
876 return false;
877 stream->flip = element;
879 /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert
880 * to do the final conversion. */
881 if (!(element = create_element("videoconvert", "base"))
882 || !append_element(parser->container, element, &first, &last))
883 return false;
885 if (!link_src_to_element(pad, first) || !link_element_to_sink(last, stream->my_sink))
886 return false;
888 else if (!strcmp(name, "audio/x-raw"))
890 /* Currently our dsound can't handle 64-bit formats or all
891 * surround-sound configurations. Native dsound can't always handle
892 * 64-bit formats either. Add an audioconvert to allow changing bit
893 * depth and channel count. */
894 if (!(element = create_element("audioconvert", "base"))
895 || !append_element(parser->container, element, &first, &last))
896 return false;
898 if (!link_src_to_element(pad, first) || !link_element_to_sink(last, stream->my_sink))
899 return false;
901 else
903 return link_src_to_sink(pad, stream->my_sink);
906 return true;
909 static void stream_decodebin_no_more_pads_cb(GstElement *element, gpointer user)
911 struct wg_parser_stream *stream = user;
912 struct wg_parser *parser = stream->parser;
914 GST_DEBUG("stream %p, parser %p, element %p.", stream, parser, element);
916 pthread_mutex_lock(&parser->mutex);
917 stream->no_more_pads = true;
918 pthread_mutex_unlock(&parser->mutex);
919 pthread_cond_signal(&parser->init_cond);
922 static void stream_decodebin_pad_added_cb(GstElement *element, GstPad *pad, gpointer user)
924 struct wg_parser_stream *stream = user;
925 struct wg_parser *parser = stream->parser;
927 GST_LOG("stream %p, parser %p, element %p, pad %p.", stream, parser, element, pad);
929 if (gst_pad_is_linked(pad))
930 return;
932 if (!stream_create_post_processing_elements(pad, stream))
933 return;
934 gst_pad_set_active(stream->my_sink, 1);
937 static bool stream_decodebin_create(struct wg_parser_stream *stream)
939 struct wg_parser *parser = stream->parser;
941 GST_LOG("stream %p, parser %p.", stream, parser);
943 if (!(stream->decodebin = create_element("decodebin", "base")))
944 return false;
945 gst_bin_add(GST_BIN(parser->container), stream->decodebin);
947 g_signal_connect(stream->decodebin, "pad-added", G_CALLBACK(stream_decodebin_pad_added_cb), stream);
948 g_signal_connect(stream->decodebin, "autoplug-select", G_CALLBACK(autoplug_select_cb), stream);
949 g_signal_connect(stream->decodebin, "no-more-pads", G_CALLBACK(stream_decodebin_no_more_pads_cb), stream);
951 pthread_mutex_lock(&parser->mutex);
952 stream->no_more_pads = false;
953 pthread_mutex_unlock(&parser->mutex);
954 gst_element_sync_state_with_parent(stream->decodebin);
956 GST_LOG("Created stream decodebin %p for %u.", stream->decodebin, stream->number);
958 return true;
961 static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user)
963 struct wg_parser_stream *stream;
964 struct wg_parser *parser = user;
965 GstCaps *caps;
967 GST_LOG("parser %p, element %p, pad %p.", parser, element, pad);
969 if (gst_pad_is_linked(pad))
970 return;
972 if (!(stream = create_stream(parser)))
973 return;
975 caps = gst_pad_query_caps(pad, NULL);
976 wg_format_from_caps(&stream->codec_format, caps);
977 gst_caps_unref(caps);
979 /* For compressed stream, create an extra decodebin to decode it. */
980 if (!parser->output_compressed && format_is_compressed(&stream->codec_format))
982 if (!stream_decodebin_create(stream))
984 GST_ERROR("Failed to create decodebin for stream %u.", stream->number);
985 return;
988 if (!link_src_to_element(pad, stream->decodebin))
989 GST_ERROR("Failed to link pad %p to stream decodebin %p for stream %u.",
990 pad, stream->decodebin, stream->number);
992 return;
995 if (!stream_create_post_processing_elements(pad, stream))
996 return;
997 gst_pad_set_active(stream->my_sink, 1);
1000 static void pad_removed_cb(GstElement *element, GstPad *pad, gpointer user)
1002 struct wg_parser *parser = user;
1003 bool done = false;
1004 unsigned int i;
1005 char *name;
1007 GST_LOG("parser %p, element %p, pad %p.", parser, element, pad);
1009 for (i = 0; i < parser->stream_count; ++i)
1011 struct wg_parser_stream *stream = parser->streams[i];
1012 GstPad *stream_decodebin_sink_peer = NULL;
1013 GstPad *stream_decodebin_sink = NULL;
1015 if (stream->decodebin)
1017 stream_decodebin_sink = gst_element_get_static_pad(stream->decodebin, "sink");
1018 stream_decodebin_sink_peer = gst_pad_get_peer(stream_decodebin_sink);
1021 if (stream_decodebin_sink_peer == pad)
1023 gst_pad_unlink(pad, stream_decodebin_sink);
1024 done = true;
1027 if (stream_decodebin_sink_peer)
1028 gst_object_unref(stream_decodebin_sink_peer);
1029 if (stream_decodebin_sink)
1030 gst_object_unref(stream_decodebin_sink);
1032 if (done)
1033 return;
1036 name = gst_pad_get_name(pad);
1037 GST_WARNING("No pin matching pad \"%s\" found.", name);
1038 g_free(name);
1041 static GstFlowReturn issue_read_request(struct wg_parser *parser, guint64 offset, guint size, GstBuffer **buffer)
1043 GstFlowReturn ret;
1045 pthread_mutex_lock(&parser->mutex);
1047 assert(!parser->read_request.size);
1048 parser->read_request.buffer = *buffer;
1049 parser->read_request.offset = offset;
1050 parser->read_request.size = size;
1051 parser->read_request.done = false;
1052 pthread_cond_signal(&parser->read_cond);
1054 /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect
1055 * the upstream pin to flush if necessary. We should never be blocked on
1056 * read_thread() not running. */
1058 while (!parser->read_request.done)
1059 pthread_cond_wait(&parser->read_done_cond, &parser->mutex);
1061 *buffer = parser->read_request.buffer;
1062 ret = parser->read_request.ret;
1064 pthread_mutex_unlock(&parser->mutex);
1066 GST_LOG("Request returned %s.", gst_flow_get_name(ret));
1068 return ret;
1071 static struct input_cache_chunk * get_cache_entry(struct wg_parser *parser, guint64 position)
1073 struct input_cache_chunk chunk;
1074 unsigned int i;
1076 for (i = 0; i < ARRAY_SIZE(parser->input_cache_chunks); i++)
1078 chunk = parser->input_cache_chunks[i];
1080 if (chunk.data && position == chunk.position)
1082 if (i != 0)
1084 memmove(&parser->input_cache_chunks[1], &parser->input_cache_chunks[0], i * sizeof(chunk));
1085 parser->input_cache_chunks[0] = chunk;
1088 return &parser->input_cache_chunks[0];
1092 return NULL;
1095 static GstFlowReturn read_cached_chunk(struct wg_parser *parser, guint64 chunk_position, unsigned int chunk_offset, GstBuffer *buffer, guint64 buffer_offset)
1097 struct input_cache_chunk *chunk;
1098 GstBuffer *chunk_buffer;
1099 void *chunk_data;
1100 GstFlowReturn ret;
1102 if ((chunk = get_cache_entry(parser, chunk_position)))
1104 if (!!gst_buffer_fill(buffer, buffer_offset, chunk->data + chunk_offset, input_cache_chunk_size - chunk_offset))
1105 return GST_FLOW_OK;
1106 else
1107 return GST_FLOW_ERROR;
1110 chunk = &parser->input_cache_chunks[ ARRAY_SIZE(parser->input_cache_chunks) - 1 ];
1112 if (!(chunk_data = chunk->data))
1113 chunk_data = malloc(input_cache_chunk_size);
1115 chunk_buffer = gst_buffer_new_wrapped_full(0, chunk_data, input_cache_chunk_size, 0, input_cache_chunk_size, NULL, NULL);
1116 ret = issue_read_request(parser, chunk_position, input_cache_chunk_size, &chunk_buffer);
1117 gst_buffer_unref(chunk_buffer);
1119 if (ret != GST_FLOW_OK)
1121 if (!chunk->data)
1122 free(chunk_data);
1123 return ret;
1126 memmove(&parser->input_cache_chunks[1], &parser->input_cache_chunks[0], (ARRAY_SIZE(parser->input_cache_chunks) - 1) * sizeof(*chunk));
1127 parser->input_cache_chunks[0].data = chunk_data;
1128 parser->input_cache_chunks[0].position = chunk_position;
1130 chunk = &parser->input_cache_chunks[0];
1131 if (!!gst_buffer_fill(buffer, buffer_offset, chunk->data + chunk_offset, input_cache_chunk_size - chunk_offset))
1132 return GST_FLOW_OK;
1133 else
1134 return GST_FLOW_ERROR;
1137 static GstFlowReturn read_input_cache(struct wg_parser *parser, guint64 offset, guint size, GstBuffer **buffer)
1139 unsigned int i, chunk_count, chunk_offset, buffer_offset = 0;
1140 GstBuffer *working_buffer;
1141 guint64 chunk_position;
1142 GstFlowReturn ret;
1144 working_buffer = *buffer;
1145 if (!working_buffer)
1146 working_buffer = gst_buffer_new_and_alloc(size);
1148 chunk_position = offset - (offset % input_cache_chunk_size);
1149 chunk_count = (offset + size + input_cache_chunk_size - chunk_position - 1) / input_cache_chunk_size;
1150 chunk_offset = offset - chunk_position;
1152 for (i = 0; i < chunk_count; i++)
1154 if ((ret = read_cached_chunk(parser, chunk_position, chunk_offset, working_buffer, buffer_offset)) != GST_FLOW_OK)
1156 if (!*buffer)
1157 gst_buffer_unref(working_buffer);
1158 return ret;
1161 chunk_position += input_cache_chunk_size;
1162 buffer_offset += input_cache_chunk_size - chunk_offset;
1163 chunk_offset = 0;
1166 *buffer = working_buffer;
1167 return GST_FLOW_OK;
1170 static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent,
1171 guint64 offset, guint size, GstBuffer **buffer)
1173 struct wg_parser *parser = gst_pad_get_element_private(pad);
1175 GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, size %u, buffer %p.", pad, offset, size, *buffer);
1177 if (offset == GST_BUFFER_OFFSET_NONE)
1178 offset = parser->next_pull_offset;
1179 parser->next_pull_offset = offset + size;
1181 if (!size)
1183 /* asfreader occasionally asks for zero bytes. gst_buffer_map() will
1184 * return NULL in this case. Avoid confusing the read thread by asking
1185 * it for zero bytes. */
1186 if (!*buffer)
1187 *buffer = gst_buffer_new_and_alloc(0);
1188 gst_buffer_set_size(*buffer, 0);
1189 GST_LOG("Returning empty buffer.");
1190 return GST_FLOW_OK;
1193 if (size >= input_cache_chunk_size || sizeof(void*) == 4)
1194 return issue_read_request(parser, offset, size, buffer);
1196 if (offset >= parser->file_size)
1197 return GST_FLOW_EOS;
1199 if ((offset + size) >= parser->file_size)
1200 size = parser->file_size - offset;
1202 return read_input_cache(parser, offset, size, buffer);
1205 static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query)
1207 struct wg_parser *parser = gst_pad_get_element_private(pad);
1208 GstFormat format;
1210 GST_LOG("parser %p, type %s.", parser, GST_QUERY_TYPE_NAME(query));
1212 switch (GST_QUERY_TYPE(query))
1214 case GST_QUERY_DURATION:
1215 gst_query_parse_duration(query, &format, NULL);
1216 if (format == GST_FORMAT_PERCENT)
1218 gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX);
1219 return TRUE;
1221 else if (format == GST_FORMAT_BYTES)
1223 gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size);
1224 return TRUE;
1226 return FALSE;
1228 case GST_QUERY_SEEKING:
1229 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
1230 if (format != GST_FORMAT_BYTES)
1232 GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format));
1233 return FALSE;
1235 gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size);
1236 return TRUE;
1238 case GST_QUERY_SCHEDULING:
1239 gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
1240 gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH);
1241 gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL);
1242 return TRUE;
1244 default:
1245 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query));
1246 return FALSE;
1250 static void *push_data(void *arg)
1252 struct wg_parser *parser = arg;
1253 GstBuffer *buffer;
1254 guint max_size;
1256 GST_DEBUG("Starting push thread.");
1258 if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL)))
1260 GST_ERROR("Failed to allocate memory.");
1261 return NULL;
1264 max_size = parser->stop_offset ? parser->stop_offset : parser->file_size;
1266 for (;;)
1268 ULONG size;
1269 int ret;
1271 if (parser->next_offset >= max_size)
1272 break;
1273 size = min(16384, max_size - parser->next_offset);
1275 if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0)
1277 GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret));
1278 break;
1281 parser->next_offset += size;
1283 buffer->duration = buffer->pts = -1;
1284 if ((ret = gst_pad_push(parser->my_src, buffer)) < 0)
1286 GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret));
1287 break;
1291 gst_buffer_unref(buffer);
1293 push_event(parser->my_src, gst_event_new_eos());
1295 GST_DEBUG("Stopping push thread.");
1297 return NULL;
1300 static gboolean activate_push(GstPad *pad, gboolean activate)
1302 struct wg_parser *parser = gst_pad_get_element_private(pad);
1304 if (!activate)
1306 if (parser->push_thread)
1308 pthread_join(parser->push_thread, NULL);
1309 parser->push_thread = 0;
1312 else if (!parser->push_thread)
1314 int ret;
1316 if ((ret = pthread_create(&parser->push_thread, NULL, push_data, parser)))
1318 GST_ERROR("Failed to create push thread: %s", strerror(errno));
1319 parser->push_thread = 0;
1320 return FALSE;
1323 return TRUE;
1326 static gboolean src_activate_mode_cb(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
1328 struct wg_parser *parser = gst_pad_get_element_private(pad);
1330 GST_DEBUG("%s source pad for parser %p in %s mode.",
1331 activate ? "Activating" : "Deactivating", parser, gst_pad_mode_get_name(mode));
1333 switch (mode)
1335 case GST_PAD_MODE_PULL:
1336 return TRUE;
1337 case GST_PAD_MODE_PUSH:
1338 return activate_push(pad, activate);
1339 case GST_PAD_MODE_NONE:
1340 break;
1342 return FALSE;
1345 static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer user)
1347 struct wg_parser *parser = user;
1348 gchar *dbg_info = NULL;
1349 GError *err = NULL;
1351 GST_DEBUG("parser %p, message type %s.", parser, GST_MESSAGE_TYPE_NAME(msg));
1353 switch (msg->type)
1355 case GST_MESSAGE_ERROR:
1356 gst_message_parse_error(msg, &err, &dbg_info);
1357 if (parser->err_on)
1359 fprintf(stderr, "winegstreamer error: %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
1360 fprintf(stderr, "winegstreamer error: %s: %s\n", GST_OBJECT_NAME(msg->src), dbg_info);
1362 g_error_free(err);
1363 g_free(dbg_info);
1364 pthread_mutex_lock(&parser->mutex);
1365 parser->error = true;
1366 pthread_mutex_unlock(&parser->mutex);
1367 pthread_cond_signal(&parser->init_cond);
1368 break;
1370 case GST_MESSAGE_WARNING:
1371 gst_message_parse_warning(msg, &err, &dbg_info);
1372 if (parser->warn_on)
1374 fprintf(stderr, "winegstreamer warning: %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
1375 fprintf(stderr, "winegstreamer warning: %s: %s\n", GST_OBJECT_NAME(msg->src), dbg_info);
1377 g_error_free(err);
1378 g_free(dbg_info);
1379 break;
1381 case GST_MESSAGE_DURATION_CHANGED:
1382 pthread_mutex_lock(&parser->mutex);
1383 parser->has_duration = true;
1384 pthread_mutex_unlock(&parser->mutex);
1385 pthread_cond_signal(&parser->init_cond);
1386 break;
1388 default:
1389 break;
1391 gst_message_unref(msg);
1392 return GST_BUS_DROP;
1395 static gboolean src_perform_seek(struct wg_parser *parser, GstEvent *event)
1397 BOOL thread = !!parser->push_thread;
1398 GstSeekType cur_type, stop_type;
1399 GstFormat seek_format;
1400 GstEvent *flush_event;
1401 GstSeekFlags flags;
1402 gint64 cur, stop;
1403 guint32 seqnum;
1404 gdouble rate;
1406 gst_event_parse_seek(event, &rate, &seek_format, &flags,
1407 &cur_type, &cur, &stop_type, &stop);
1409 if (seek_format != GST_FORMAT_BYTES)
1411 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format));
1412 return FALSE;
1415 seqnum = gst_event_get_seqnum(event);
1417 /* send flush start */
1418 if (flags & GST_SEEK_FLAG_FLUSH)
1420 flush_event = gst_event_new_flush_start();
1421 gst_event_set_seqnum(flush_event, seqnum);
1422 push_event(parser->my_src, flush_event);
1423 if (thread)
1424 gst_pad_set_active(parser->my_src, 1);
1427 parser->next_offset = parser->start_offset = cur;
1429 /* and prepare to continue streaming */
1430 if (flags & GST_SEEK_FLAG_FLUSH)
1432 flush_event = gst_event_new_flush_stop(TRUE);
1433 gst_event_set_seqnum(flush_event, seqnum);
1434 push_event(parser->my_src, flush_event);
1435 if (thread)
1436 gst_pad_set_active(parser->my_src, 1);
1439 return TRUE;
1442 static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event)
1444 struct wg_parser *parser = gst_pad_get_element_private(pad);
1445 gboolean ret = TRUE;
1447 GST_LOG("parser %p, type \"%s\".", parser, GST_EVENT_TYPE_NAME(event));
1449 switch (event->type)
1451 case GST_EVENT_SEEK:
1452 ret = src_perform_seek(parser, event);
1453 break;
1455 case GST_EVENT_FLUSH_START:
1456 case GST_EVENT_FLUSH_STOP:
1457 case GST_EVENT_QOS:
1458 case GST_EVENT_RECONFIGURE:
1459 break;
1461 default:
1462 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
1463 ret = FALSE;
1464 break;
1466 gst_event_unref(event);
1467 return ret;
1470 static void query_tags(struct wg_parser_stream *stream)
1472 GstPad *peer = gst_pad_get_peer(stream->my_sink);
1473 const gchar *struct_name;
1474 GstEvent *tag_event;
1475 guint i, j;
1477 stream->tags[WG_PARSER_TAG_NAME] = NULL;
1478 stream->tags[WG_PARSER_TAG_LANGUAGE] = NULL;
1480 i = 0;
1481 while ((tag_event = gst_pad_get_sticky_event(peer, GST_EVENT_TAG, i++)))
1483 GstTagList *tag_list;
1485 gst_event_parse_tag(tag_event, &tag_list);
1487 if (!stream->tags[WG_PARSER_TAG_NAME])
1489 /* Extract stream name from Quick Time demuxer private tag where it puts unrecognized chunks. */
1490 const GValue *val;
1491 GstSample *sample;
1492 GstBuffer *buf;
1493 gsize size;
1494 guint tag_count = gst_tag_list_get_tag_size(tag_list, "private-qt-tag");
1496 for (j = 0; j < tag_count; ++j)
1498 if (!(val = gst_tag_list_get_value_index(tag_list, "private-qt-tag", j)))
1499 continue;
1500 if (!GST_VALUE_HOLDS_SAMPLE(val) || !(sample = gst_value_get_sample(val)))
1501 continue;
1502 struct_name = gst_structure_get_name(gst_sample_get_info(sample));
1503 if (!struct_name || strcmp(struct_name, "application/x-gst-qt-name-tag"))
1504 continue;
1505 if (!(buf = gst_sample_get_buffer(sample)))
1506 continue;
1507 if ((size = gst_buffer_get_size(buf)) < 8)
1508 continue;
1509 size -= 8;
1510 if (!(stream->tags[WG_PARSER_TAG_NAME] = g_malloc(size + 1)))
1511 continue;
1512 if (gst_buffer_extract(buf, 8, stream->tags[WG_PARSER_TAG_NAME], size) != size)
1514 g_free(stream->tags[WG_PARSER_TAG_NAME]);
1515 stream->tags[WG_PARSER_TAG_NAME] = NULL;
1516 continue;
1518 stream->tags[WG_PARSER_TAG_NAME][size] = 0;
1522 if (!stream->tags[WG_PARSER_TAG_LANGUAGE])
1524 gchar *lang_code = NULL;
1526 gst_tag_list_get_string(tag_list, GST_TAG_LANGUAGE_CODE, &lang_code);
1527 if (stream->parser->sink_caps && !strcmp(stream->parser->sink_caps, "video/quicktime"))
1529 /* For QuickTime media, we convert the language tags to ISO 639-1. */
1530 const gchar *lang_code_iso_639_1 = lang_code ? gst_tag_get_language_code_iso_639_1(lang_code) : NULL;
1531 stream->tags[WG_PARSER_TAG_LANGUAGE] = lang_code_iso_639_1 ? g_strdup(lang_code_iso_639_1) : NULL;
1532 g_free(lang_code);
1534 else
1535 stream->tags[WG_PARSER_TAG_LANGUAGE] = lang_code;
1538 gst_event_unref(tag_event);
1540 gst_object_unref(peer);
1543 static NTSTATUS wg_parser_connect(void *args)
1545 GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src",
1546 GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
1547 const struct wg_parser_connect_params *params = args;
1548 struct wg_parser *parser = get_parser(params->parser);
1549 unsigned int i;
1550 int ret;
1552 parser->file_size = params->file_size;
1553 parser->sink_connected = true;
1555 if (!parser->bus)
1557 parser->bus = gst_bus_new();
1558 gst_bus_set_sync_handler(parser->bus, bus_handler_cb, parser, NULL);
1561 parser->container = gst_bin_new(NULL);
1562 gst_element_set_bus(parser->container, parser->bus);
1564 parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src");
1565 gst_pad_set_getrange_function(parser->my_src, src_getrange_cb);
1566 gst_pad_set_query_function(parser->my_src, src_query_cb);
1567 gst_pad_set_activatemode_function(parser->my_src, src_activate_mode_cb);
1568 gst_pad_set_event_function(parser->my_src, src_event_cb);
1569 gst_pad_set_element_private(parser->my_src, parser);
1571 parser->start_offset = parser->next_offset = parser->stop_offset = 0;
1572 parser->next_pull_offset = 0;
1573 parser->error = false;
1575 if (!parser->init_gst(parser))
1576 goto out;
1578 gst_element_set_state(parser->container, GST_STATE_PAUSED);
1579 ret = gst_element_get_state(parser->container, NULL, NULL, -1);
1580 if (ret == GST_STATE_CHANGE_FAILURE)
1582 GST_ERROR("Failed to play stream.");
1583 goto out;
1586 pthread_mutex_lock(&parser->mutex);
1588 while (!parser_no_more_pads(parser) && !parser->error)
1589 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1590 if (parser->error)
1592 pthread_mutex_unlock(&parser->mutex);
1593 goto out;
1596 for (i = 0; i < parser->stream_count; ++i)
1598 struct wg_parser_stream *stream = parser->streams[i];
1599 gint64 duration;
1601 /* If we received a buffer, waiting for tags or caps does not make sense anymore. */
1602 while ((!stream->has_caps || !stream->has_tags) && !parser->error && !stream->has_buffer)
1603 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1605 /* GStreamer doesn't actually provide any guarantees about when duration
1606 * is available, even for seekable streams. It's basically built for
1607 * applications that don't care, e.g. movie players that can display
1608 * a duration once it's available, and update it visually if a better
1609 * estimate is found. This doesn't really match well with DirectShow or
1610 * Media Foundation, which both expect duration to be available
1611 * immediately on connecting, so we have to use some complex heuristics
1612 * to try to actually get a usable duration.
1614 * Some elements (avidemux, wavparse, qtdemux) record duration almost
1615 * immediately, before fixing caps. Such elements don't send
1616 * duration-changed messages. Therefore always try querying duration
1617 * after caps have been found.
1619 * Some elements (mpegaudioparse) send duration-changed. In the case of
1620 * a mp3 stream without seek tables it will not be sent immediately, but
1621 * only after enough frames have been parsed to form an estimate. They
1622 * may send it multiple times with increasingly accurate estimates, but
1623 * unfortunately we have no way of knowing whether another estimate will
1624 * be sent, so we always take the first one. We assume that if the
1625 * duration is not immediately available then the element will always
1626 * send duration-changed.
1629 for (;;)
1631 if (parser->error)
1633 pthread_mutex_unlock(&parser->mutex);
1634 goto out;
1636 if (gst_pad_peer_query_duration(stream->my_sink, GST_FORMAT_TIME, &duration))
1638 stream->duration = duration / 100;
1639 break;
1642 if (stream->eos)
1644 stream->duration = 0;
1645 GST_WARNING("Failed to query duration.");
1646 break;
1649 /* Elements based on GstBaseParse send duration-changed before
1650 * actually updating the duration in GStreamer versions prior
1651 * to 1.17.1. See <gstreamer.git:d28e0b4147fe7073b2>. So after
1652 * receiving duration-changed we have to continue polling until
1653 * the query succeeds. */
1654 if (parser->has_duration)
1656 pthread_mutex_unlock(&parser->mutex);
1657 g_usleep(10000);
1658 pthread_mutex_lock(&parser->mutex);
1660 else
1662 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1666 query_tags(stream);
1668 /* Now that we're fully initialized, enable the stream so that further
1669 * samples get queued instead of being discarded. We don't actually need
1670 * the samples (in particular, the frontend should seek before
1671 * attempting to read anything), but we don't want to waste CPU time
1672 * trying to decode them. */
1673 stream->enabled = true;
1676 pthread_mutex_unlock(&parser->mutex);
1678 parser->next_offset = 0;
1679 return S_OK;
1681 out:
1682 if (parser->container)
1683 gst_element_set_state(parser->container, GST_STATE_NULL);
1684 if (parser->my_src)
1685 gst_object_unref(parser->my_src);
1687 for (i = 0; i < parser->stream_count; ++i)
1688 free_stream(parser->streams[i]);
1689 parser->stream_count = 0;
1690 free(parser->streams);
1691 parser->streams = NULL;
1693 if (parser->container)
1695 gst_element_set_bus(parser->container, NULL);
1696 gst_object_unref(parser->container);
1697 parser->container = NULL;
1700 g_free(parser->sink_caps);
1701 parser->sink_caps = NULL;
1703 pthread_mutex_lock(&parser->mutex);
1704 parser->sink_connected = false;
1705 pthread_mutex_unlock(&parser->mutex);
1706 pthread_cond_signal(&parser->read_cond);
1708 return E_FAIL;
1711 static NTSTATUS wg_parser_disconnect(void *args)
1713 struct wg_parser *parser = get_parser(*(wg_parser_t *)args);
1714 unsigned int i;
1716 /* Unblock all of our streams. */
1717 pthread_mutex_lock(&parser->mutex);
1718 for (i = 0; i < parser->stream_count; ++i)
1720 parser->streams[i]->flushing = true;
1721 pthread_cond_signal(&parser->streams[i]->event_empty_cond);
1723 pthread_mutex_unlock(&parser->mutex);
1725 gst_element_set_state(parser->container, GST_STATE_NULL);
1726 gst_object_unref(parser->my_src);
1727 parser->my_src = NULL;
1729 pthread_mutex_lock(&parser->mutex);
1730 parser->sink_connected = false;
1731 pthread_mutex_unlock(&parser->mutex);
1732 pthread_cond_signal(&parser->read_cond);
1734 for (i = 0; i < parser->stream_count; ++i)
1735 free_stream(parser->streams[i]);
1737 parser->stream_count = 0;
1738 free(parser->streams);
1739 parser->streams = NULL;
1741 gst_element_set_bus(parser->container, NULL);
1742 gst_object_unref(parser->container);
1743 parser->container = NULL;
1745 g_free(parser->sink_caps);
1746 parser->sink_caps = NULL;
1748 for (i = 0; i < ARRAY_SIZE(parser->input_cache_chunks); i++)
1750 free(parser->input_cache_chunks[i].data);
1751 parser->input_cache_chunks[i].data = NULL;
1754 return S_OK;
1757 static BOOL decodebin_parser_init_gst(struct wg_parser *parser)
1759 GstElement *element;
1761 if (!(element = create_element("decodebin", "base")))
1762 return FALSE;
1764 gst_bin_add(GST_BIN(parser->container), element);
1765 parser->decodebin = element;
1767 g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser);
1768 g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser);
1769 g_signal_connect(element, "autoplug-continue", G_CALLBACK(autoplug_continue_cb), parser);
1770 g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser);
1771 g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser);
1773 pthread_mutex_lock(&parser->mutex);
1774 parser->no_more_pads = false;
1775 pthread_mutex_unlock(&parser->mutex);
1777 if (!link_src_to_element(parser->my_src, element))
1778 return FALSE;
1780 return TRUE;
1783 static BOOL avi_parser_init_gst(struct wg_parser *parser)
1785 GstElement *element;
1787 if (!(element = create_element("avidemux", "good")))
1788 return FALSE;
1790 gst_bin_add(GST_BIN(parser->container), element);
1792 g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser);
1793 g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser);
1794 g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser);
1796 pthread_mutex_lock(&parser->mutex);
1797 parser->no_more_pads = false;
1798 pthread_mutex_unlock(&parser->mutex);
1800 if (!link_src_to_element(parser->my_src, element))
1801 return FALSE;
1803 return TRUE;
1806 static BOOL wave_parser_init_gst(struct wg_parser *parser)
1808 struct wg_parser_stream *stream;
1809 GstElement *element;
1811 if (!(element = create_element("wavparse", "good")))
1812 return FALSE;
1814 gst_bin_add(GST_BIN(parser->container), element);
1816 if (!link_src_to_element(parser->my_src, element))
1817 return FALSE;
1819 if (!(stream = create_stream(parser)))
1820 return FALSE;
1822 if (!link_element_to_sink(element, stream->my_sink))
1823 return FALSE;
1824 gst_pad_set_active(stream->my_sink, 1);
1826 parser->no_more_pads = true;
1828 return TRUE;
1831 static NTSTATUS wg_parser_create(void *args)
1833 static const init_gst_cb init_funcs[] =
1835 [WG_PARSER_DECODEBIN] = decodebin_parser_init_gst,
1836 [WG_PARSER_AVIDEMUX] = avi_parser_init_gst,
1837 [WG_PARSER_WAVPARSE] = wave_parser_init_gst,
1840 struct wg_parser_create_params *params = args;
1841 struct wg_parser *parser;
1843 if (!(parser = calloc(1, sizeof(*parser))))
1844 return E_OUTOFMEMORY;
1846 pthread_mutex_init(&parser->mutex, NULL);
1847 pthread_cond_init(&parser->init_cond, NULL);
1848 pthread_cond_init(&parser->read_cond, NULL);
1849 pthread_cond_init(&parser->read_done_cond, NULL);
1850 parser->init_gst = init_funcs[params->type];
1851 parser->output_compressed = params->output_compressed;
1852 parser->err_on = params->err_on;
1853 parser->warn_on = params->warn_on;
1854 GST_DEBUG("Created winegstreamer parser %p.", parser);
1855 params->parser = (wg_parser_t)(ULONG_PTR)parser;
1856 return S_OK;
1859 static NTSTATUS wg_parser_destroy(void *args)
1861 struct wg_parser *parser = get_parser(*(wg_parser_t *)args);
1863 if (parser->bus)
1865 gst_bus_set_sync_handler(parser->bus, NULL, NULL, NULL);
1866 gst_object_unref(parser->bus);
1869 pthread_mutex_destroy(&parser->mutex);
1870 pthread_cond_destroy(&parser->init_cond);
1871 pthread_cond_destroy(&parser->read_cond);
1872 pthread_cond_destroy(&parser->read_done_cond);
1874 free(parser);
1875 return S_OK;
1878 const unixlib_entry_t __wine_unix_call_funcs[] =
1880 #define X(name) [unix_ ## name] = name
1881 X(wg_init_gstreamer),
1883 X(wg_parser_create),
1884 X(wg_parser_destroy),
1886 X(wg_parser_connect),
1887 X(wg_parser_disconnect),
1889 X(wg_parser_get_next_read_offset),
1890 X(wg_parser_push_data),
1892 X(wg_parser_get_stream_count),
1893 X(wg_parser_get_stream),
1895 X(wg_parser_stream_get_preferred_format),
1896 X(wg_parser_stream_get_codec_format),
1897 X(wg_parser_stream_enable),
1898 X(wg_parser_stream_disable),
1900 X(wg_parser_stream_get_buffer),
1901 X(wg_parser_stream_copy_buffer),
1902 X(wg_parser_stream_release_buffer),
1903 X(wg_parser_stream_notify_qos),
1905 X(wg_parser_stream_get_duration),
1906 X(wg_parser_stream_get_tag),
1907 X(wg_parser_stream_seek),
1909 X(wg_transform_create),
1910 X(wg_transform_destroy),
1911 X(wg_transform_set_output_format),
1913 X(wg_transform_push_data),
1914 X(wg_transform_read_data),
1915 X(wg_transform_get_status),
1916 X(wg_transform_drain),
1917 X(wg_transform_flush),
1919 X(wg_muxer_create),
1920 X(wg_muxer_destroy),
1921 X(wg_muxer_add_stream),
1922 X(wg_muxer_start),
1923 X(wg_muxer_push_sample),
1924 X(wg_muxer_read_data),
1927 C_ASSERT(ARRAYSIZE(__wine_unix_call_funcs) == unix_wg_funcs_count);
1929 #ifdef _WIN64
1931 typedef ULONG PTR32;
1933 static NTSTATUS wow64_wg_parser_push_data(void *args) {
1934 struct
1936 wg_parser_t parser;
1937 PTR32 data;
1938 UINT32 size;
1939 } *params32 = args;
1940 struct wg_parser_push_data_params params =
1942 .parser = params32->parser,
1943 .data = ULongToPtr(params32->data),
1944 .size = params32->size,
1947 return wg_parser_push_data(&params);
1950 static NTSTATUS wow64_wg_parser_stream_get_preferred_format(void *args)
1952 struct
1954 wg_parser_stream_t stream;
1955 PTR32 format;
1956 } *params32 = args;
1957 struct wg_parser_stream_get_preferred_format_params params =
1959 .stream = params32->stream,
1960 .format = ULongToPtr(params32->format),
1963 return wg_parser_stream_get_preferred_format(&params);
1966 static NTSTATUS wow64_wg_parser_stream_get_codec_format(void *args)
1968 struct
1970 wg_parser_stream_t stream;
1971 PTR32 format;
1972 } *params32 = args;
1973 struct wg_parser_stream_get_codec_format_params params =
1975 .stream = params32->stream,
1976 .format = ULongToPtr(params32->format),
1979 return wg_parser_stream_get_codec_format(&params);
1982 static NTSTATUS wow64_wg_parser_stream_enable(void *args)
1984 struct
1986 wg_parser_stream_t stream;
1987 PTR32 format;
1988 } *params32 = args;
1989 struct wg_parser_stream_enable_params params =
1991 .stream = params32->stream,
1992 .format = ULongToPtr(params32->format),
1995 return wg_parser_stream_enable(&params);
1998 static NTSTATUS wow64_wg_parser_stream_get_buffer(void *args)
2000 struct
2002 wg_parser_t parser;
2003 wg_parser_stream_t stream;
2004 PTR32 buffer;
2005 } *params32 = args;
2006 struct wg_parser_stream_get_buffer_params params =
2008 .parser = params32->parser,
2009 .stream = params32->stream,
2010 .buffer = ULongToPtr(params32->buffer),
2012 return wg_parser_stream_get_buffer(&params);
2015 static NTSTATUS wow64_wg_parser_stream_copy_buffer(void *args)
2017 struct
2019 wg_parser_stream_t stream;
2020 PTR32 data;
2021 UINT32 offset;
2022 UINT32 size;
2023 } *params32 = args;
2024 struct wg_parser_stream_copy_buffer_params params =
2026 .stream = params32->stream,
2027 .data = ULongToPtr(params32->data),
2028 .offset = params32->offset,
2029 .size = params32->size,
2031 return wg_parser_stream_copy_buffer(&params);
2034 static NTSTATUS wow64_wg_parser_stream_get_tag(void *args)
2036 struct
2038 wg_parser_stream_t stream;
2039 wg_parser_tag tag;
2040 PTR32 buffer;
2041 PTR32 size;
2042 } *params32 = args;
2043 struct wg_parser_stream_get_tag_params params =
2045 .stream = params32->stream,
2046 .tag = params32->tag,
2047 .buffer = ULongToPtr(params32->buffer),
2048 .size = ULongToPtr(params32->size),
2051 return wg_parser_stream_get_tag(&params);
2054 NTSTATUS wow64_wg_transform_create(void *args)
2056 struct
2058 wg_transform_t transform;
2059 PTR32 input_format;
2060 PTR32 output_format;
2061 PTR32 attrs;
2062 } *params32 = args;
2063 struct wg_transform_create_params params =
2065 .input_format = ULongToPtr(params32->input_format),
2066 .output_format = ULongToPtr(params32->output_format),
2067 .attrs = ULongToPtr(params32->attrs),
2069 NTSTATUS ret;
2071 ret = wg_transform_create(&params);
2072 params32->transform = params.transform;
2073 return ret;
2076 NTSTATUS wow64_wg_transform_set_output_format(void *args)
2078 struct
2080 wg_transform_t transform;
2081 PTR32 format;
2082 } *params32 = args;
2083 struct wg_transform_set_output_format_params params =
2085 .transform = params32->transform,
2086 .format = ULongToPtr(params32->format),
2088 return wg_transform_set_output_format(&params);
2091 NTSTATUS wow64_wg_transform_push_data(void *args)
2093 struct
2095 wg_transform_t transform;
2096 PTR32 sample;
2097 HRESULT result;
2098 } *params32 = args;
2099 struct wg_transform_push_data_params params =
2101 .transform = params32->transform,
2102 .sample = ULongToPtr(params32->sample),
2104 NTSTATUS ret;
2106 ret = wg_transform_push_data(&params);
2107 params32->result = params.result;
2108 return ret;
2111 NTSTATUS wow64_wg_transform_read_data(void *args)
2113 struct
2115 wg_transform_t transform;
2116 PTR32 sample;
2117 PTR32 format;
2118 HRESULT result;
2119 } *params32 = args;
2120 struct wg_transform_read_data_params params =
2122 .transform = params32->transform,
2123 .sample = ULongToPtr(params32->sample),
2124 .format = ULongToPtr(params32->format),
2126 NTSTATUS ret;
2128 ret = wg_transform_read_data(&params);
2129 params32->result = params.result;
2130 return ret;
2133 NTSTATUS wow64_wg_muxer_create(void *args)
2135 struct
2137 wg_muxer_t muxer;
2138 PTR32 format;
2139 } *params32 = args;
2140 struct wg_muxer_create_params params =
2142 .format = ULongToPtr(params32->format),
2144 NTSTATUS ret;
2146 ret = wg_muxer_create(&params);
2147 params32->muxer = params.muxer;
2148 return ret;
2151 NTSTATUS wow64_wg_muxer_add_stream(void *args)
2153 struct
2155 wg_muxer_t muxer;
2156 UINT32 stream_id;
2157 PTR32 format;
2158 } *params32 = args;
2159 struct wg_muxer_add_stream_params params =
2161 .muxer = params32->muxer,
2162 .stream_id = params32->stream_id,
2163 .format = ULongToPtr(params32->format),
2165 return wg_muxer_add_stream(&params);
2168 NTSTATUS wow64_wg_muxer_push_sample(void *args)
2170 struct
2172 wg_muxer_t muxer;
2173 PTR32 sample;
2174 UINT32 stream_id;
2175 } *params32 = args;
2176 struct wg_muxer_push_sample_params params =
2178 .muxer = params32->muxer,
2179 .sample = ULongToPtr(params32->sample),
2180 .stream_id = params32->stream_id,
2182 return wg_muxer_push_sample(&params);
2185 NTSTATUS wow64_wg_muxer_read_data(void *args)
2187 struct
2189 wg_muxer_t muxer;
2190 PTR32 buffer;
2191 UINT32 size;
2192 UINT64 offset;
2193 } *params32 = args;
2194 struct wg_muxer_read_data_params params =
2196 .muxer = params32->muxer,
2197 .buffer = ULongToPtr(params32->buffer),
2198 .size = params32->size,
2199 .offset = params32->offset,
2201 NTSTATUS ret;
2203 ret = wg_muxer_read_data(&params);
2204 params32->size = params.size;
2205 params32->offset = params.offset;
2206 return ret;
2209 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
2211 #define X64(name) [unix_ ## name] = wow64_ ## name
2212 X(wg_init_gstreamer),
2214 X(wg_parser_create),
2215 X(wg_parser_destroy),
2217 X(wg_parser_connect),
2218 X(wg_parser_disconnect),
2220 X(wg_parser_get_next_read_offset),
2221 X64(wg_parser_push_data),
2223 X(wg_parser_get_stream_count),
2224 X(wg_parser_get_stream),
2226 X64(wg_parser_stream_get_preferred_format),
2227 X64(wg_parser_stream_get_codec_format),
2228 X64(wg_parser_stream_enable),
2229 X(wg_parser_stream_disable),
2231 X64(wg_parser_stream_get_buffer),
2232 X64(wg_parser_stream_copy_buffer),
2233 X(wg_parser_stream_release_buffer),
2234 X(wg_parser_stream_notify_qos),
2236 X(wg_parser_stream_get_duration),
2237 X64(wg_parser_stream_get_tag),
2238 X(wg_parser_stream_seek),
2240 X64(wg_transform_create),
2241 X(wg_transform_destroy),
2242 X64(wg_transform_set_output_format),
2244 X64(wg_transform_push_data),
2245 X64(wg_transform_read_data),
2246 X(wg_transform_get_status),
2247 X(wg_transform_drain),
2248 X(wg_transform_flush),
2250 X64(wg_muxer_create),
2251 X(wg_muxer_destroy),
2252 X64(wg_muxer_add_stream),
2253 X(wg_muxer_start),
2254 X64(wg_muxer_push_sample),
2255 X64(wg_muxer_read_data),
2258 C_ASSERT(ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_wg_funcs_count);
2260 #endif /* _WIN64 */