winegstreamer: Map the output sample buffer in the Unix library.
[wine.git] / dlls / winegstreamer / wg_parser.c
blobde066f838812b5c1b91b54a0c00d84e8af97bd45
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"
28 #include "ntstatus.h"
29 #define WIN32_NO_STATUS
30 #include "gst_private.h"
31 #include "winternl.h"
32 #include <assert.h>
34 WINE_DEFAULT_DEBUG_CHANNEL(gstreamer);
36 GST_DEBUG_CATEGORY_STATIC(wine);
37 #define GST_CAT_DEFAULT wine
39 static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format)
41 switch (format)
43 case GST_AUDIO_FORMAT_U8:
44 return WG_AUDIO_FORMAT_U8;
45 case GST_AUDIO_FORMAT_S16LE:
46 return WG_AUDIO_FORMAT_S16LE;
47 case GST_AUDIO_FORMAT_S24LE:
48 return WG_AUDIO_FORMAT_S24LE;
49 case GST_AUDIO_FORMAT_S32LE:
50 return WG_AUDIO_FORMAT_S32LE;
51 case GST_AUDIO_FORMAT_F32LE:
52 return WG_AUDIO_FORMAT_F32LE;
53 case GST_AUDIO_FORMAT_F64LE:
54 return WG_AUDIO_FORMAT_F64LE;
55 default:
56 return WG_AUDIO_FORMAT_UNKNOWN;
60 static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info)
62 format->major_type = WG_MAJOR_TYPE_AUDIO;
63 format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info));
64 format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info);
65 format->u.audio.rate = GST_AUDIO_INFO_RATE(info);
68 static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format)
70 switch (format)
72 case GST_VIDEO_FORMAT_BGRA:
73 return WG_VIDEO_FORMAT_BGRA;
74 case GST_VIDEO_FORMAT_BGRx:
75 return WG_VIDEO_FORMAT_BGRx;
76 case GST_VIDEO_FORMAT_BGR:
77 return WG_VIDEO_FORMAT_BGR;
78 case GST_VIDEO_FORMAT_RGB15:
79 return WG_VIDEO_FORMAT_RGB15;
80 case GST_VIDEO_FORMAT_AYUV:
81 return WG_VIDEO_FORMAT_AYUV;
82 case GST_VIDEO_FORMAT_I420:
83 return WG_VIDEO_FORMAT_I420;
84 case GST_VIDEO_FORMAT_NV12:
85 return WG_VIDEO_FORMAT_NV12;
86 case GST_VIDEO_FORMAT_UYVY:
87 return WG_VIDEO_FORMAT_UYVY;
88 case GST_VIDEO_FORMAT_YUY2:
89 return WG_VIDEO_FORMAT_YUY2;
90 case GST_VIDEO_FORMAT_YV12:
91 return WG_VIDEO_FORMAT_YV12;
92 case GST_VIDEO_FORMAT_YVYU:
93 return WG_VIDEO_FORMAT_YVYU;
94 default:
95 return WG_VIDEO_FORMAT_UNKNOWN;
99 static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info)
101 format->major_type = WG_MAJOR_TYPE_VIDEO;
102 format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info));
103 format->u.video.width = GST_VIDEO_INFO_WIDTH(info);
104 format->u.video.height = GST_VIDEO_INFO_HEIGHT(info);
105 format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info);
106 format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info);
109 static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps)
111 const GstStructure *structure = gst_caps_get_structure(caps, 0);
112 gint layer, channels, rate;
114 if (!gst_structure_get_int(structure, "layer", &layer))
116 GST_WARNING("Missing \"layer\" value.");
117 return;
119 if (!gst_structure_get_int(structure, "channels", &channels))
121 GST_WARNING("Missing \"channels\" value.");
122 return;
124 if (!gst_structure_get_int(structure, "rate", &rate))
126 GST_WARNING("Missing \"rate\" value.");
127 return;
130 format->major_type = WG_MAJOR_TYPE_AUDIO;
132 if (layer == 1)
133 format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1;
134 else if (layer == 2)
135 format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2;
136 else if (layer == 3)
137 format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3;
139 format->u.audio.channels = channels;
140 format->u.audio.rate = rate;
143 static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps)
145 const GstStructure *structure = gst_caps_get_structure(caps, 0);
146 gint width, height, fps_n, fps_d;
148 if (!gst_structure_get_int(structure, "width", &width))
150 GST_WARNING("Missing \"width\" value.");
151 return;
153 if (!gst_structure_get_int(structure, "height", &height))
155 GST_WARNING("Missing \"height\" value.");
156 return;
158 if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d))
160 fps_n = 0;
161 fps_d = 1;
164 format->major_type = WG_MAJOR_TYPE_VIDEO;
165 format->u.video.format = WG_VIDEO_FORMAT_CINEPAK;
166 format->u.video.width = width;
167 format->u.video.height = height;
168 format->u.video.fps_n = fps_n;
169 format->u.video.fps_d = fps_d;
172 static void wg_format_from_caps(struct wg_format *format, const GstCaps *caps)
174 const GstStructure *structure = gst_caps_get_structure(caps, 0);
175 const char *name = gst_structure_get_name(structure);
177 memset(format, 0, sizeof(*format));
179 if (!strcmp(name, "audio/x-raw"))
181 GstAudioInfo info;
183 if (gst_audio_info_from_caps(&info, caps))
184 wg_format_from_audio_info(format, &info);
186 else if (!strcmp(name, "video/x-raw"))
188 GstVideoInfo info;
190 if (gst_video_info_from_caps(&info, caps))
191 wg_format_from_video_info(format, &info);
193 else if (!strcmp(name, "audio/mpeg"))
195 wg_format_from_caps_audio_mpeg(format, caps);
197 else if (!strcmp(name, "video/x-cinepak"))
199 wg_format_from_caps_video_cinepak(format, caps);
201 else
203 gchar *str = gst_caps_to_string(caps);
205 GST_FIXME("Unhandled caps %s.", str);
206 g_free(str);
210 static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format)
212 switch (format)
214 case WG_AUDIO_FORMAT_U8: return GST_AUDIO_FORMAT_U8;
215 case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE;
216 case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE;
217 case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE;
218 case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE;
219 case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE;
220 default: return GST_AUDIO_FORMAT_UNKNOWN;
224 static GstCaps *wg_format_to_caps_audio(const struct wg_format *format)
226 GstAudioFormat audio_format;
227 GstAudioInfo info;
229 if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN)
230 return NULL;
232 gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, NULL);
233 return gst_audio_info_to_caps(&info);
236 static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format)
238 switch (format)
240 case WG_VIDEO_FORMAT_BGRA: return GST_VIDEO_FORMAT_BGRA;
241 case WG_VIDEO_FORMAT_BGRx: return GST_VIDEO_FORMAT_BGRx;
242 case WG_VIDEO_FORMAT_BGR: return GST_VIDEO_FORMAT_BGR;
243 case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15;
244 case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16;
245 case WG_VIDEO_FORMAT_AYUV: return GST_VIDEO_FORMAT_AYUV;
246 case WG_VIDEO_FORMAT_I420: return GST_VIDEO_FORMAT_I420;
247 case WG_VIDEO_FORMAT_NV12: return GST_VIDEO_FORMAT_NV12;
248 case WG_VIDEO_FORMAT_UYVY: return GST_VIDEO_FORMAT_UYVY;
249 case WG_VIDEO_FORMAT_YUY2: return GST_VIDEO_FORMAT_YUY2;
250 case WG_VIDEO_FORMAT_YV12: return GST_VIDEO_FORMAT_YV12;
251 case WG_VIDEO_FORMAT_YVYU: return GST_VIDEO_FORMAT_YVYU;
252 default: return GST_VIDEO_FORMAT_UNKNOWN;
256 static GstCaps *wg_format_to_caps_video(const struct wg_format *format)
258 GstVideoFormat video_format;
259 GstVideoInfo info;
260 unsigned int i;
261 GstCaps *caps;
263 if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN)
264 return NULL;
266 gst_video_info_set_format(&info, video_format, format->u.video.width, format->u.video.height);
267 if ((caps = gst_video_info_to_caps(&info)))
269 /* Clear some fields that shouldn't prevent us from connecting. */
270 for (i = 0; i < gst_caps_get_size(caps); ++i)
272 gst_structure_remove_fields(gst_caps_get_structure(caps, i),
273 "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL);
276 return caps;
279 static GstCaps *wg_format_to_caps(const struct wg_format *format)
281 switch (format->major_type)
283 case WG_MAJOR_TYPE_UNKNOWN:
284 return NULL;
285 case WG_MAJOR_TYPE_AUDIO:
286 return wg_format_to_caps_audio(format);
287 case WG_MAJOR_TYPE_VIDEO:
288 return wg_format_to_caps_video(format);
290 assert(0);
291 return NULL;
294 static bool wg_format_compare(const struct wg_format *a, const struct wg_format *b)
296 if (a->major_type != b->major_type)
297 return false;
299 switch (a->major_type)
301 case WG_MAJOR_TYPE_UNKNOWN:
302 return false;
304 case WG_MAJOR_TYPE_AUDIO:
305 return a->u.audio.format == b->u.audio.format
306 && a->u.audio.channels == b->u.audio.channels
307 && a->u.audio.rate == b->u.audio.rate;
309 case WG_MAJOR_TYPE_VIDEO:
310 /* Do not compare FPS. */
311 return a->u.video.format == b->u.video.format
312 && a->u.video.width == b->u.video.width
313 && a->u.video.height == b->u.video.height;
316 assert(0);
317 return false;
320 static uint32_t CDECL wg_parser_get_stream_count(struct wg_parser *parser)
322 return parser->stream_count;
325 static struct wg_parser_stream * CDECL wg_parser_get_stream(struct wg_parser *parser, uint32_t index)
327 return parser->streams[index];
330 static void CDECL wg_parser_begin_flush(struct wg_parser *parser)
332 unsigned int i;
334 pthread_mutex_lock(&parser->mutex);
335 parser->flushing = true;
336 pthread_mutex_unlock(&parser->mutex);
338 for (i = 0; i < parser->stream_count; ++i)
340 if (parser->streams[i]->enabled)
341 pthread_cond_signal(&parser->streams[i]->event_cond);
345 static void CDECL wg_parser_end_flush(struct wg_parser *parser)
347 pthread_mutex_lock(&parser->mutex);
348 parser->flushing = false;
349 pthread_mutex_unlock(&parser->mutex);
352 static void CDECL wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format)
354 *format = stream->preferred_format;
357 static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format)
359 stream->current_format = *format;
360 stream->enabled = true;
362 if (format->major_type == WG_MAJOR_TYPE_VIDEO)
364 switch (format->u.video.format)
366 case WG_VIDEO_FORMAT_BGRA:
367 case WG_VIDEO_FORMAT_BGRx:
368 case WG_VIDEO_FORMAT_BGR:
369 case WG_VIDEO_FORMAT_RGB15:
370 case WG_VIDEO_FORMAT_RGB16:
371 gst_util_set_object_arg(G_OBJECT(stream->flip), "method", "vertical-flip");
372 break;
374 case WG_VIDEO_FORMAT_AYUV:
375 case WG_VIDEO_FORMAT_I420:
376 case WG_VIDEO_FORMAT_NV12:
377 case WG_VIDEO_FORMAT_UYVY:
378 case WG_VIDEO_FORMAT_YUY2:
379 case WG_VIDEO_FORMAT_YV12:
380 case WG_VIDEO_FORMAT_YVYU:
381 case WG_VIDEO_FORMAT_UNKNOWN:
382 case WG_VIDEO_FORMAT_CINEPAK:
383 gst_util_set_object_arg(G_OBJECT(stream->flip), "method", "none");
384 break;
388 gst_pad_push_event(stream->my_sink, gst_event_new_reconfigure());
391 static void CDECL wg_parser_stream_disable(struct wg_parser_stream *stream)
393 stream->enabled = false;
396 static bool CDECL wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event)
398 struct wg_parser *parser = stream->parser;
400 pthread_mutex_lock(&parser->mutex);
402 while (!parser->flushing && stream->event.type == WG_PARSER_EVENT_NONE)
403 pthread_cond_wait(&stream->event_cond, &parser->mutex);
405 if (parser->flushing)
407 pthread_mutex_unlock(&parser->mutex);
408 TRACE("Filter is flushing.\n");
409 return false;
412 *event = stream->event;
414 if (stream->event.type != WG_PARSER_EVENT_BUFFER)
416 stream->event.type = WG_PARSER_EVENT_NONE;
417 pthread_cond_signal(&stream->event_empty_cond);
419 pthread_mutex_unlock(&parser->mutex);
421 return true;
424 static bool CDECL wg_parser_stream_copy_buffer(struct wg_parser_stream *stream,
425 void *data, uint32_t offset, uint32_t size)
427 struct wg_parser *parser = stream->parser;
429 pthread_mutex_lock(&parser->mutex);
431 if (!stream->buffer)
433 pthread_mutex_unlock(&parser->mutex);
434 return false;
437 assert(stream->event.type == WG_PARSER_EVENT_BUFFER);
438 assert(offset < stream->map_info.size);
439 assert(offset + size <= stream->map_info.size);
440 memcpy(data, stream->map_info.data + offset, size);
442 pthread_mutex_unlock(&parser->mutex);
443 return true;
446 static void CDECL wg_parser_stream_release_buffer(struct wg_parser_stream *stream)
448 struct wg_parser *parser = stream->parser;
450 pthread_mutex_lock(&parser->mutex);
452 assert(stream->event.type == WG_PARSER_EVENT_BUFFER);
454 gst_buffer_unmap(stream->buffer, &stream->map_info);
455 gst_buffer_unref(stream->buffer);
456 stream->buffer = NULL;
457 stream->event.type = WG_PARSER_EVENT_NONE;
459 pthread_mutex_unlock(&parser->mutex);
460 pthread_cond_signal(&stream->event_empty_cond);
463 static bool CDECL wg_parser_stream_seek(struct wg_parser_stream *stream, double rate,
464 uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags)
466 GstSeekType start_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET;
467 GstSeekFlags flags = 0;
469 if (start_flags & AM_SEEKING_SeekToKeyFrame)
470 flags |= GST_SEEK_FLAG_KEY_UNIT;
471 if (start_flags & AM_SEEKING_Segment)
472 flags |= GST_SEEK_FLAG_SEGMENT;
473 if (!(start_flags & AM_SEEKING_NoFlush))
474 flags |= GST_SEEK_FLAG_FLUSH;
476 if ((start_flags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
477 start_type = GST_SEEK_TYPE_NONE;
478 if ((stop_flags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
479 stop_type = GST_SEEK_TYPE_NONE;
481 return gst_pad_push_event(stream->my_sink, gst_event_new_seek(rate,
482 GST_FORMAT_TIME, flags, start_type, start_pos * 100, stop_type, stop_pos * 100));
485 static void CDECL wg_parser_stream_notify_qos(struct wg_parser_stream *stream,
486 bool underflow, double proportion, int64_t diff, uint64_t timestamp)
488 GstEvent *event;
490 if (!(event = gst_event_new_qos(underflow ? GST_QOS_TYPE_UNDERFLOW : GST_QOS_TYPE_OVERFLOW,
491 1000.0 / proportion, diff * 100, timestamp * 100)))
492 ERR("Failed to create QOS event.\n");
493 gst_pad_push_event(stream->my_sink, event);
496 static GstAutoplugSelectResult autoplug_blacklist(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *fact, gpointer user)
498 const char *name = gst_element_factory_get_longname(fact);
500 GST_TRACE("Using \"%s\".", name);
502 if (strstr(name, "Player protection"))
504 GST_WARNING("Blacklisted a/52 decoder because it only works in Totem.");
505 return GST_AUTOPLUG_SELECT_SKIP;
507 if (!strcmp(name, "Fluendo Hardware Accelerated Video Decoder"))
509 GST_WARNING("Disabled video acceleration since it breaks in wine.");
510 return GST_AUTOPLUG_SELECT_SKIP;
512 return GST_AUTOPLUG_SELECT_TRY;
515 static void no_more_pads(GstElement *element, gpointer user)
517 struct wg_parser *parser = user;
519 GST_DEBUG("parser %p.", parser);
521 pthread_mutex_lock(&parser->mutex);
522 parser->no_more_pads = true;
523 pthread_mutex_unlock(&parser->mutex);
524 pthread_cond_signal(&parser->init_cond);
527 static GstFlowReturn queue_stream_event(struct wg_parser_stream *stream,
528 const struct wg_parser_event *event, GstBuffer *buffer)
530 struct wg_parser *parser = stream->parser;
532 /* Unlike request_buffer_src() [q.v.], we need to watch for GStreamer
533 * flushes here. The difference is that we can be blocked by the streaming
534 * thread not running (or itself flushing on the DirectShow side).
535 * request_buffer_src() can only be blocked by the upstream source, and that
536 * is solved by flushing the upstream source. */
538 pthread_mutex_lock(&parser->mutex);
539 while (!stream->flushing && stream->event.type != WG_PARSER_EVENT_NONE)
540 pthread_cond_wait(&stream->event_empty_cond, &parser->mutex);
541 if (stream->flushing)
543 pthread_mutex_unlock(&parser->mutex);
544 GST_DEBUG("Filter is flushing; discarding event.");
545 return GST_FLOW_FLUSHING;
547 if (buffer)
549 assert(GST_IS_BUFFER(buffer));
550 if (!gst_buffer_map(buffer, &stream->map_info, GST_MAP_READ))
552 pthread_mutex_unlock(&parser->mutex);
553 GST_ERROR("Failed to map buffer.\n");
554 return GST_FLOW_ERROR;
557 stream->event = *event;
558 stream->buffer = buffer;
559 pthread_mutex_unlock(&parser->mutex);
560 pthread_cond_signal(&stream->event_cond);
561 GST_LOG("Event queued.");
562 return GST_FLOW_OK;
565 static gboolean event_sink(GstPad *pad, GstObject *parent, GstEvent *event)
567 struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
568 struct wg_parser *parser = stream->parser;
570 GST_LOG("stream %p, type \"%s\".", stream, GST_EVENT_TYPE_NAME(event));
572 switch (event->type)
574 case GST_EVENT_SEGMENT:
575 if (stream->enabled)
577 struct wg_parser_event stream_event;
578 const GstSegment *segment;
580 gst_event_parse_segment(event, &segment);
582 if (segment->format != GST_FORMAT_TIME)
584 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(segment->format));
585 break;
588 stream_event.type = WG_PARSER_EVENT_SEGMENT;
589 stream_event.u.segment.position = segment->position / 100;
590 stream_event.u.segment.stop = segment->stop / 100;
591 stream_event.u.segment.rate = segment->rate * segment->applied_rate;
592 queue_stream_event(stream, &stream_event, NULL);
594 break;
596 case GST_EVENT_EOS:
597 if (stream->enabled)
599 struct wg_parser_event stream_event;
601 stream_event.type = WG_PARSER_EVENT_EOS;
602 queue_stream_event(stream, &stream_event, NULL);
604 else
606 pthread_mutex_lock(&parser->mutex);
607 stream->eos = true;
608 pthread_mutex_unlock(&parser->mutex);
609 pthread_cond_signal(&parser->init_cond);
611 break;
613 case GST_EVENT_FLUSH_START:
614 if (stream->enabled)
616 pthread_mutex_lock(&parser->mutex);
618 stream->flushing = true;
619 pthread_cond_signal(&stream->event_empty_cond);
621 if (stream->event.type == WG_PARSER_EVENT_BUFFER)
623 gst_buffer_unmap(stream->buffer, &stream->map_info);
624 gst_buffer_unref(stream->buffer);
625 stream->buffer = NULL;
627 stream->event.type = WG_PARSER_EVENT_NONE;
629 pthread_mutex_unlock(&parser->mutex);
631 break;
633 case GST_EVENT_FLUSH_STOP:
634 if (stream->enabled)
636 pthread_mutex_lock(&parser->mutex);
637 stream->flushing = false;
638 pthread_mutex_unlock(&parser->mutex);
640 break;
642 case GST_EVENT_CAPS:
644 GstCaps *caps;
646 gst_event_parse_caps(event, &caps);
647 pthread_mutex_lock(&parser->mutex);
648 wg_format_from_caps(&stream->preferred_format, caps);
649 stream->has_caps = true;
650 pthread_mutex_unlock(&parser->mutex);
651 pthread_cond_signal(&parser->init_cond);
652 break;
655 default:
656 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
658 gst_event_unref(event);
659 return TRUE;
662 static GstFlowReturn got_data_sink(GstPad *pad, GstObject *parent, GstBuffer *buffer)
664 struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
665 struct wg_parser_event stream_event;
666 GstFlowReturn ret;
668 GST_LOG("stream %p, buffer %p.", stream, buffer);
670 if (!stream->enabled)
672 gst_buffer_unref(buffer);
673 return GST_FLOW_OK;
676 stream_event.type = WG_PARSER_EVENT_BUFFER;
678 if ((stream_event.u.buffer.has_pts = GST_BUFFER_PTS_IS_VALID(buffer)))
679 stream_event.u.buffer.pts = GST_BUFFER_PTS(buffer) / 100;
680 if ((stream_event.u.buffer.has_duration = GST_BUFFER_DURATION_IS_VALID(buffer)))
681 stream_event.u.buffer.duration = GST_BUFFER_DURATION(buffer) / 100;
682 stream_event.u.buffer.discontinuity = GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DISCONT);
683 stream_event.u.buffer.preroll = GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_LIVE);
684 stream_event.u.buffer.delta = GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT);
685 stream_event.u.buffer.size = gst_buffer_get_size(buffer);
687 /* Transfer our reference to the buffer to the stream object. */
688 if ((ret = queue_stream_event(stream, &stream_event, buffer)) != GST_FLOW_OK)
689 gst_buffer_unref(buffer);
690 return ret;
693 static gboolean query_sink(GstPad *pad, GstObject *parent, GstQuery *query)
695 struct wg_parser_stream *stream = gst_pad_get_element_private(pad);
697 GST_LOG("stream %p, type \"%s\".", stream, gst_query_type_get_name(query->type));
699 switch (query->type)
701 case GST_QUERY_CAPS:
703 GstCaps *caps, *filter, *temp;
705 gst_query_parse_caps(query, &filter);
707 if (stream->enabled)
708 caps = wg_format_to_caps(&stream->current_format);
709 else
710 caps = gst_caps_new_any();
711 if (!caps)
712 return FALSE;
714 if (filter)
716 temp = gst_caps_intersect(caps, filter);
717 gst_caps_unref(caps);
718 caps = temp;
721 gst_query_set_caps_result(query, caps);
722 gst_caps_unref(caps);
723 return TRUE;
726 case GST_QUERY_ACCEPT_CAPS:
728 struct wg_format format;
729 gboolean ret = TRUE;
730 GstCaps *caps;
732 if (!stream->enabled)
734 gst_query_set_accept_caps_result(query, TRUE);
735 return TRUE;
738 gst_query_parse_accept_caps(query, &caps);
739 wg_format_from_caps(&format, caps);
740 ret = wg_format_compare(&format, &stream->current_format);
741 if (!ret && WARN_ON(gstreamer))
743 gchar *str = gst_caps_to_string(caps);
744 GST_WARNING("Rejecting caps \"%s\".", str);
745 g_free(str);
747 gst_query_set_accept_caps_result(query, ret);
748 return TRUE;
751 default:
752 return gst_pad_query_default (pad, parent, query);
756 static struct wg_parser_stream *create_stream(struct wg_parser *parser)
758 struct wg_parser_stream *stream, **new_array;
759 char pad_name[19];
761 if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams))))
762 return NULL;
763 parser->streams = new_array;
765 if (!(stream = calloc(1, sizeof(*stream))))
766 return NULL;
768 stream->parser = parser;
769 pthread_cond_init(&stream->event_cond, NULL);
770 pthread_cond_init(&stream->event_empty_cond, NULL);
772 sprintf(pad_name, "qz_sink_%u", parser->stream_count);
773 stream->my_sink = gst_pad_new(pad_name, GST_PAD_SINK);
774 gst_pad_set_element_private(stream->my_sink, stream);
775 gst_pad_set_chain_function(stream->my_sink, got_data_sink);
776 gst_pad_set_event_function(stream->my_sink, event_sink);
777 gst_pad_set_query_function(stream->my_sink, query_sink);
779 parser->streams[parser->stream_count++] = stream;
780 return stream;
783 static void init_new_decoded_pad(GstElement *element, GstPad *pad, struct wg_parser *parser)
785 struct wg_parser_stream *stream;
786 const char *name;
787 GstCaps *caps;
788 int ret;
790 caps = gst_caps_make_writable(gst_pad_query_caps(pad, NULL));
791 name = gst_structure_get_name(gst_caps_get_structure(caps, 0));
793 if (!(stream = create_stream(parser)))
794 goto out;
796 if (!strcmp(name, "video/x-raw"))
798 GstElement *deinterlace, *vconv, *flip, *vconv2;
800 /* DirectShow can express interlaced video, but downstream filters can't
801 * necessarily consume it. In particular, the video renderer can't. */
802 if (!(deinterlace = gst_element_factory_make("deinterlace", NULL)))
804 fprintf(stderr, "winegstreamer: failed to create deinterlace, are %u-bit GStreamer \"good\" plugins installed?\n",
805 8 * (int)sizeof(void *));
806 goto out;
809 /* decodebin considers many YUV formats to be "raw", but some quartz
810 * filters can't handle those. Also, videoflip can't handle all "raw"
811 * formats either. Add a videoconvert to swap color spaces. */
812 if (!(vconv = gst_element_factory_make("videoconvert", NULL)))
814 fprintf(stderr, "winegstreamer: failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
815 8 * (int)sizeof(void *));
816 goto out;
819 /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
820 if (!(flip = gst_element_factory_make("videoflip", NULL)))
822 fprintf(stderr, "winegstreamer: failed to create videoflip, are %u-bit GStreamer \"good\" plugins installed?\n",
823 8 * (int)sizeof(void *));
824 goto out;
827 /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert
828 * to do the final conversion. */
829 if (!(vconv2 = gst_element_factory_make("videoconvert", NULL)))
831 fprintf(stderr, "winegstreamer: failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
832 8 * (int)sizeof(void *));
833 goto out;
836 /* The bin takes ownership of these elements. */
837 gst_bin_add(GST_BIN(parser->container), deinterlace);
838 gst_element_sync_state_with_parent(deinterlace);
839 gst_bin_add(GST_BIN(parser->container), vconv);
840 gst_element_sync_state_with_parent(vconv);
841 gst_bin_add(GST_BIN(parser->container), flip);
842 gst_element_sync_state_with_parent(flip);
843 gst_bin_add(GST_BIN(parser->container), vconv2);
844 gst_element_sync_state_with_parent(vconv2);
846 gst_element_link(deinterlace, vconv);
847 gst_element_link(vconv, flip);
848 gst_element_link(flip, vconv2);
850 stream->post_sink = gst_element_get_static_pad(deinterlace, "sink");
851 stream->post_src = gst_element_get_static_pad(vconv2, "src");
852 stream->flip = flip;
854 else if (!strcmp(name, "audio/x-raw"))
856 GstElement *convert;
858 /* Currently our dsound can't handle 64-bit formats or all
859 * surround-sound configurations. Native dsound can't always handle
860 * 64-bit formats either. Add an audioconvert to allow changing bit
861 * depth and channel count. */
862 if (!(convert = gst_element_factory_make("audioconvert", NULL)))
864 fprintf(stderr, "winegstreamer: failed to create audioconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
865 8 * (int)sizeof(void *));
866 goto out;
869 gst_bin_add(GST_BIN(parser->container), convert);
870 gst_element_sync_state_with_parent(convert);
872 stream->post_sink = gst_element_get_static_pad(convert, "sink");
873 stream->post_src = gst_element_get_static_pad(convert, "src");
876 if (stream->post_sink)
878 if ((ret = gst_pad_link(pad, stream->post_sink)) < 0)
880 GST_ERROR("Failed to link decodebin source pad to post-processing elements, error %s.",
881 gst_pad_link_get_name(ret));
882 gst_object_unref(stream->post_sink);
883 stream->post_sink = NULL;
884 goto out;
887 if ((ret = gst_pad_link(stream->post_src, stream->my_sink)) < 0)
889 GST_ERROR("Failed to link post-processing elements to our sink pad, error %s.",
890 gst_pad_link_get_name(ret));
891 gst_object_unref(stream->post_src);
892 stream->post_src = NULL;
893 gst_object_unref(stream->post_sink);
894 stream->post_sink = NULL;
895 goto out;
898 else if ((ret = gst_pad_link(pad, stream->my_sink)) < 0)
900 GST_ERROR("Failed to link decodebin source pad to our sink pad, error %s.",
901 gst_pad_link_get_name(ret));
902 goto out;
905 gst_pad_set_active(stream->my_sink, 1);
906 gst_object_ref(stream->their_src = pad);
907 out:
908 gst_caps_unref(caps);
911 static void existing_new_pad(GstElement *element, GstPad *pad, gpointer user)
913 struct wg_parser *parser = user;
915 GST_LOG("parser %p, element %p, pad %p.", parser, element, pad);
917 if (gst_pad_is_linked(pad))
918 return;
920 init_new_decoded_pad(element, pad, parser);
923 static void removed_decoded_pad(GstElement *element, GstPad *pad, gpointer user)
925 struct wg_parser *parser = user;
926 unsigned int i;
927 char *name;
929 GST_LOG("parser %p, element %p, pad %p.", parser, element, pad);
931 for (i = 0; i < parser->stream_count; ++i)
933 struct wg_parser_stream *stream = parser->streams[i];
935 if (stream->their_src == pad)
937 if (stream->post_sink)
938 gst_pad_unlink(stream->their_src, stream->post_sink);
939 else
940 gst_pad_unlink(stream->their_src, stream->my_sink);
941 gst_object_unref(stream->their_src);
942 stream->their_src = NULL;
943 return;
947 name = gst_pad_get_name(pad);
948 GST_WARNING("No pin matching pad \"%s\" found.", name);
949 g_free(name);
952 static GstFlowReturn request_buffer_src(GstPad *pad, GstObject *parent, guint64 offset, guint size, GstBuffer **buffer)
954 struct wg_parser *parser = gst_pad_get_element_private(pad);
955 GstBuffer *new_buffer = NULL;
956 GstFlowReturn ret;
958 GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, length %u, buffer %p.", pad, offset, size, *buffer);
960 if (!*buffer)
961 *buffer = new_buffer = gst_buffer_new_and_alloc(size);
963 pthread_mutex_lock(&parser->mutex);
965 assert(!parser->read_request.buffer);
966 parser->read_request.buffer = *buffer;
967 parser->read_request.offset = offset;
968 parser->read_request.size = size;
969 parser->read_request.done = false;
970 pthread_cond_signal(&parser->read_cond);
972 /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect
973 * the upstream pin to flush if necessary. We should never be blocked on
974 * read_thread() not running. */
976 while (!parser->read_request.done)
977 pthread_cond_wait(&parser->read_done_cond, &parser->mutex);
979 ret = parser->read_request.ret;
981 pthread_mutex_unlock(&parser->mutex);
983 GST_LOG("Request returned %s.", gst_flow_get_name(ret));
985 if (ret != GST_FLOW_OK && new_buffer)
986 gst_buffer_unref(new_buffer);
988 return ret;
991 static gboolean query_function(GstPad *pad, GstObject *parent, GstQuery *query)
993 struct wg_parser *parser = gst_pad_get_element_private(pad);
994 GstFormat format;
996 GST_LOG("parser %p, type %s.", parser, GST_QUERY_TYPE_NAME(query));
998 switch (GST_QUERY_TYPE(query))
1000 case GST_QUERY_DURATION:
1001 gst_query_parse_duration(query, &format, NULL);
1002 if (format == GST_FORMAT_PERCENT)
1004 gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX);
1005 return TRUE;
1007 else if (format == GST_FORMAT_BYTES)
1009 gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size);
1010 return TRUE;
1012 return FALSE;
1014 case GST_QUERY_SEEKING:
1015 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
1016 if (format != GST_FORMAT_BYTES)
1018 GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format));
1019 return FALSE;
1021 gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size);
1022 return TRUE;
1024 case GST_QUERY_SCHEDULING:
1025 gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
1026 gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH);
1027 gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL);
1028 return TRUE;
1030 default:
1031 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query));
1032 return FALSE;
1036 static void *push_data(void *arg)
1038 struct wg_parser *parser = arg;
1039 GstBuffer *buffer;
1040 guint max_size;
1042 GST_DEBUG("Starting push thread.");
1044 if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL)))
1046 GST_ERROR("Failed to allocate memory.");
1047 return NULL;
1050 max_size = parser->stop_offset ? parser->stop_offset : parser->file_size;
1052 for (;;)
1054 ULONG size;
1055 int ret;
1057 if (parser->next_offset >= max_size)
1058 break;
1059 size = min(16384, max_size - parser->next_offset);
1061 if ((ret = request_buffer_src(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0)
1063 GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret));
1064 break;
1067 parser->next_offset += size;
1069 buffer->duration = buffer->pts = -1;
1070 if ((ret = gst_pad_push(parser->my_src, buffer)) < 0)
1072 GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret));
1073 break;
1077 gst_buffer_unref(buffer);
1079 gst_pad_push_event(parser->my_src, gst_event_new_eos());
1081 GST_DEBUG("Stopping push thread.");
1083 return NULL;
1086 static gboolean activate_push(GstPad *pad, gboolean activate)
1088 struct wg_parser *parser = gst_pad_get_element_private(pad);
1090 if (!activate)
1092 if (parser->push_thread)
1094 pthread_join(parser->push_thread, NULL);
1095 parser->push_thread = 0;
1098 else if (!parser->push_thread)
1100 int ret;
1102 if ((ret = pthread_create(&parser->push_thread, NULL, push_data, parser)))
1104 GST_ERROR("Failed to create push thread: %s", strerror(errno));
1105 parser->push_thread = 0;
1106 return FALSE;
1109 return TRUE;
1112 static gboolean activate_mode(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
1114 struct wg_parser *parser = gst_pad_get_element_private(pad);
1116 GST_DEBUG("%s source pad for parser %p in %s mode.",
1117 activate ? "Activating" : "Deactivating", parser, gst_pad_mode_get_name(mode));
1119 switch (mode)
1121 case GST_PAD_MODE_PULL:
1122 return TRUE;
1123 case GST_PAD_MODE_PUSH:
1124 return activate_push(pad, activate);
1125 case GST_PAD_MODE_NONE:
1126 break;
1128 return FALSE;
1131 static GstBusSyncReply watch_bus(GstBus *bus, GstMessage *msg, gpointer user)
1133 struct wg_parser *parser = user;
1134 gchar *dbg_info = NULL;
1135 GError *err = NULL;
1137 GST_DEBUG("parser %p, message type %s.", parser, GST_MESSAGE_TYPE_NAME(msg));
1139 switch (msg->type)
1141 case GST_MESSAGE_ERROR:
1142 gst_message_parse_error(msg, &err, &dbg_info);
1143 fprintf(stderr, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
1144 fprintf(stderr, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg->src), dbg_info);
1145 g_error_free(err);
1146 g_free(dbg_info);
1147 pthread_mutex_lock(&parser->mutex);
1148 parser->error = true;
1149 pthread_mutex_unlock(&parser->mutex);
1150 pthread_cond_signal(&parser->init_cond);
1151 break;
1153 case GST_MESSAGE_WARNING:
1154 gst_message_parse_warning(msg, &err, &dbg_info);
1155 fprintf(stderr, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
1156 fprintf(stderr, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg->src), dbg_info);
1157 g_error_free(err);
1158 g_free(dbg_info);
1159 break;
1161 case GST_MESSAGE_DURATION_CHANGED:
1162 pthread_mutex_lock(&parser->mutex);
1163 parser->has_duration = true;
1164 pthread_mutex_unlock(&parser->mutex);
1165 pthread_cond_signal(&parser->init_cond);
1166 break;
1168 default:
1169 break;
1171 gst_message_unref(msg);
1172 return GST_BUS_DROP;
1175 static gboolean gst_base_src_perform_seek(struct wg_parser *parser, GstEvent *event)
1177 BOOL thread = !!parser->push_thread;
1178 GstSeekType cur_type, stop_type;
1179 GstFormat seek_format;
1180 GstEvent *flush_event;
1181 GstSeekFlags flags;
1182 gint64 cur, stop;
1183 guint32 seqnum;
1184 gdouble rate;
1186 gst_event_parse_seek(event, &rate, &seek_format, &flags,
1187 &cur_type, &cur, &stop_type, &stop);
1189 if (seek_format != GST_FORMAT_BYTES)
1191 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format));
1192 return FALSE;
1195 seqnum = gst_event_get_seqnum(event);
1197 /* send flush start */
1198 if (flags & GST_SEEK_FLAG_FLUSH)
1200 flush_event = gst_event_new_flush_start();
1201 gst_event_set_seqnum(flush_event, seqnum);
1202 gst_pad_push_event(parser->my_src, flush_event);
1203 if (thread)
1204 gst_pad_set_active(parser->my_src, 1);
1207 parser->next_offset = parser->start_offset = cur;
1209 /* and prepare to continue streaming */
1210 if (flags & GST_SEEK_FLAG_FLUSH)
1212 flush_event = gst_event_new_flush_stop(TRUE);
1213 gst_event_set_seqnum(flush_event, seqnum);
1214 gst_pad_push_event(parser->my_src, flush_event);
1215 if (thread)
1216 gst_pad_set_active(parser->my_src, 1);
1219 return TRUE;
1222 static gboolean event_src(GstPad *pad, GstObject *parent, GstEvent *event)
1224 struct wg_parser *parser = gst_pad_get_element_private(pad);
1225 gboolean ret = TRUE;
1227 GST_LOG("parser %p, type \"%s\".", parser, GST_EVENT_TYPE_NAME(event));
1229 switch (event->type)
1231 case GST_EVENT_SEEK:
1232 ret = gst_base_src_perform_seek(parser, event);
1233 break;
1235 case GST_EVENT_FLUSH_START:
1236 case GST_EVENT_FLUSH_STOP:
1237 case GST_EVENT_QOS:
1238 case GST_EVENT_RECONFIGURE:
1239 break;
1241 default:
1242 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
1243 ret = FALSE;
1244 break;
1246 gst_event_unref(event);
1247 return ret;
1250 static LONGLONG query_duration(GstPad *pad)
1252 gint64 duration, byte_length;
1254 if (gst_pad_query_duration(pad, GST_FORMAT_TIME, &duration))
1255 return duration / 100;
1257 WARN("Failed to query time duration; trying to convert from byte length.\n");
1259 /* To accurately get a duration for the stream, we want to only consider the
1260 * length of that stream. Hence, query for the pad duration, instead of
1261 * using the file duration. */
1262 if (gst_pad_query_duration(pad, GST_FORMAT_BYTES, &byte_length)
1263 && gst_pad_query_convert(pad, GST_FORMAT_BYTES, byte_length, GST_FORMAT_TIME, &duration))
1264 return duration / 100;
1266 ERR("Failed to query duration.\n");
1267 return 0;
1270 static HRESULT CDECL wg_parser_connect(struct wg_parser *parser, uint64_t file_size)
1272 GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src",
1273 GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY);
1274 unsigned int i;
1276 parser->file_size = file_size;
1277 parser->sink_connected = true;
1279 if (!parser->bus)
1281 parser->bus = gst_bus_new();
1282 gst_bus_set_sync_handler(parser->bus, watch_bus, parser, NULL);
1285 parser->container = gst_bin_new(NULL);
1286 gst_element_set_bus(parser->container, parser->bus);
1288 parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src");
1289 gst_pad_set_getrange_function(parser->my_src, request_buffer_src);
1290 gst_pad_set_query_function(parser->my_src, query_function);
1291 gst_pad_set_activatemode_function(parser->my_src, activate_mode);
1292 gst_pad_set_event_function(parser->my_src, event_src);
1293 gst_pad_set_element_private(parser->my_src, parser);
1295 parser->start_offset = parser->next_offset = parser->stop_offset = 0;
1297 if (!parser->init_gst(parser))
1298 return E_FAIL;
1300 pthread_mutex_lock(&parser->mutex);
1302 for (i = 0; i < parser->stream_count; ++i)
1304 struct wg_parser_stream *stream = parser->streams[i];
1306 stream->duration = query_duration(stream->their_src);
1307 while (!stream->has_caps && !parser->error)
1308 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1309 if (parser->error)
1311 pthread_mutex_unlock(&parser->mutex);
1312 return E_FAIL;
1316 pthread_mutex_unlock(&parser->mutex);
1318 parser->next_offset = 0;
1319 return S_OK;
1322 static void free_stream(struct wg_parser_stream *stream)
1324 if (stream->their_src)
1326 if (stream->post_sink)
1328 gst_pad_unlink(stream->their_src, stream->post_sink);
1329 gst_pad_unlink(stream->post_src, stream->my_sink);
1330 gst_object_unref(stream->post_src);
1331 gst_object_unref(stream->post_sink);
1332 stream->post_src = stream->post_sink = NULL;
1334 else
1335 gst_pad_unlink(stream->their_src, stream->my_sink);
1336 gst_object_unref(stream->their_src);
1338 gst_object_unref(stream->my_sink);
1340 pthread_cond_destroy(&stream->event_cond);
1341 pthread_cond_destroy(&stream->event_empty_cond);
1343 free(stream);
1346 static void CDECL wg_parser_disconnect(struct wg_parser *parser)
1348 unsigned int i;
1350 /* Unblock all of our streams. */
1351 pthread_mutex_lock(&parser->mutex);
1352 for (i = 0; i < parser->stream_count; ++i)
1354 parser->streams[i]->flushing = true;
1355 pthread_cond_signal(&parser->streams[i]->event_empty_cond);
1357 pthread_mutex_unlock(&parser->mutex);
1359 gst_element_set_state(parser->container, GST_STATE_NULL);
1360 gst_pad_unlink(parser->my_src, parser->their_sink);
1361 gst_object_unref(parser->my_src);
1362 gst_object_unref(parser->their_sink);
1363 parser->my_src = parser->their_sink = NULL;
1365 pthread_mutex_lock(&parser->mutex);
1366 parser->sink_connected = false;
1367 pthread_mutex_unlock(&parser->mutex);
1368 pthread_cond_signal(&parser->read_cond);
1370 for (i = 0; i < parser->stream_count; ++i)
1371 free_stream(parser->streams[i]);
1373 parser->stream_count = 0;
1374 free(parser->streams);
1375 parser->streams = NULL;
1377 gst_element_set_bus(parser->container, NULL);
1378 gst_object_unref(parser->container);
1379 parser->container = NULL;
1382 static BOOL decodebin_parser_init_gst(struct wg_parser *parser)
1384 GstElement *element = gst_element_factory_make("decodebin", NULL);
1385 int ret;
1387 if (!element)
1389 ERR("Failed to create decodebin; are %u-bit GStreamer \"base\" plugins installed?\n",
1390 8 * (int)sizeof(void*));
1391 return FALSE;
1394 gst_bin_add(GST_BIN(parser->container), element);
1396 g_signal_connect(element, "pad-added", G_CALLBACK(existing_new_pad), parser);
1397 g_signal_connect(element, "pad-removed", G_CALLBACK(removed_decoded_pad), parser);
1398 g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_blacklist), parser);
1399 g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads), parser);
1401 parser->their_sink = gst_element_get_static_pad(element, "sink");
1403 pthread_mutex_lock(&parser->mutex);
1404 parser->no_more_pads = parser->error = false;
1405 pthread_mutex_unlock(&parser->mutex);
1407 if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
1409 ERR("Failed to link pads, error %d.\n", ret);
1410 return FALSE;
1413 gst_element_set_state(parser->container, GST_STATE_PAUSED);
1414 ret = gst_element_get_state(parser->container, NULL, NULL, -1);
1415 if (ret == GST_STATE_CHANGE_FAILURE)
1417 ERR("Failed to play stream.\n");
1418 return FALSE;
1421 pthread_mutex_lock(&parser->mutex);
1422 while (!parser->no_more_pads && !parser->error)
1423 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1424 if (parser->error)
1426 pthread_mutex_unlock(&parser->mutex);
1427 return FALSE;
1429 pthread_mutex_unlock(&parser->mutex);
1431 return TRUE;
1434 static BOOL avi_parser_init_gst(struct wg_parser *parser)
1436 GstElement *element = gst_element_factory_make("avidemux", NULL);
1437 int ret;
1439 if (!element)
1441 ERR("Failed to create avidemux; are %u-bit GStreamer \"good\" plugins installed?\n",
1442 8 * (int)sizeof(void*));
1443 return FALSE;
1446 gst_bin_add(GST_BIN(parser->container), element);
1448 g_signal_connect(element, "pad-added", G_CALLBACK(existing_new_pad), parser);
1449 g_signal_connect(element, "pad-removed", G_CALLBACK(removed_decoded_pad), parser);
1450 g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads), parser);
1452 parser->their_sink = gst_element_get_static_pad(element, "sink");
1454 pthread_mutex_lock(&parser->mutex);
1455 parser->no_more_pads = parser->error = false;
1456 pthread_mutex_unlock(&parser->mutex);
1458 if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
1460 ERR("Failed to link pads, error %d.\n", ret);
1461 return FALSE;
1464 gst_element_set_state(parser->container, GST_STATE_PAUSED);
1465 ret = gst_element_get_state(parser->container, NULL, NULL, -1);
1466 if (ret == GST_STATE_CHANGE_FAILURE)
1468 ERR("Failed to play stream.\n");
1469 return FALSE;
1472 pthread_mutex_lock(&parser->mutex);
1473 while (!parser->no_more_pads && !parser->error)
1474 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1475 if (parser->error)
1477 pthread_mutex_unlock(&parser->mutex);
1478 return FALSE;
1480 pthread_mutex_unlock(&parser->mutex);
1482 return TRUE;
1485 static BOOL mpeg_audio_parser_init_gst(struct wg_parser *parser)
1487 struct wg_parser_stream *stream;
1488 GstElement *element;
1489 int ret;
1491 if (!(element = gst_element_factory_make("mpegaudioparse", NULL)))
1493 ERR("Failed to create mpegaudioparse; are %u-bit GStreamer \"good\" plugins installed?\n",
1494 8 * (int)sizeof(void*));
1495 return FALSE;
1498 gst_bin_add(GST_BIN(parser->container), element);
1500 parser->their_sink = gst_element_get_static_pad(element, "sink");
1501 if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
1503 ERR("Failed to link sink pads, error %d.\n", ret);
1504 return FALSE;
1507 if (!(stream = create_stream(parser)))
1508 return FALSE;
1510 gst_object_ref(stream->their_src = gst_element_get_static_pad(element, "src"));
1511 if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0)
1513 ERR("Failed to link source pads, error %d.\n", ret);
1514 return FALSE;
1517 gst_pad_set_active(stream->my_sink, 1);
1518 gst_element_set_state(parser->container, GST_STATE_PAUSED);
1519 ret = gst_element_get_state(parser->container, NULL, NULL, -1);
1520 if (ret == GST_STATE_CHANGE_FAILURE)
1522 ERR("Failed to play stream.\n");
1523 return FALSE;
1526 pthread_mutex_lock(&parser->mutex);
1527 while (!parser->has_duration && !parser->error && !stream->eos)
1528 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1529 if (parser->error)
1531 pthread_mutex_unlock(&parser->mutex);
1532 return FALSE;
1534 pthread_mutex_unlock(&parser->mutex);
1535 return TRUE;
1538 static BOOL wave_parser_init_gst(struct wg_parser *parser)
1540 struct wg_parser_stream *stream;
1541 GstElement *element;
1542 int ret;
1544 if (!(element = gst_element_factory_make("wavparse", NULL)))
1546 ERR("Failed to create wavparse; are %u-bit GStreamer \"good\" plugins installed?\n",
1547 8 * (int)sizeof(void*));
1548 return FALSE;
1551 gst_bin_add(GST_BIN(parser->container), element);
1553 parser->their_sink = gst_element_get_static_pad(element, "sink");
1554 if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
1556 ERR("Failed to link sink pads, error %d.\n", ret);
1557 return FALSE;
1560 if (!(stream = create_stream(parser)))
1561 return FALSE;
1563 stream->their_src = gst_element_get_static_pad(element, "src");
1564 gst_object_ref(stream->their_src);
1565 if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0)
1567 ERR("Failed to link source pads, error %d.\n", ret);
1568 return FALSE;
1571 gst_pad_set_active(stream->my_sink, 1);
1572 gst_element_set_state(parser->container, GST_STATE_PAUSED);
1573 ret = gst_element_get_state(parser->container, NULL, NULL, -1);
1574 if (ret == GST_STATE_CHANGE_FAILURE)
1576 ERR("Failed to play stream.\n");
1577 return FALSE;
1580 return TRUE;
1583 static struct wg_parser *wg_parser_create(void)
1585 struct wg_parser *parser;
1587 if (!(parser = calloc(1, sizeof(*parser))))
1588 return NULL;
1590 pthread_mutex_init(&parser->mutex, NULL);
1591 pthread_cond_init(&parser->init_cond, NULL);
1592 pthread_cond_init(&parser->read_cond, NULL);
1593 pthread_cond_init(&parser->read_done_cond, NULL);
1594 parser->flushing = true;
1596 TRACE("Created winegstreamer parser %p.\n", parser);
1597 return parser;
1600 static struct wg_parser * CDECL wg_decodebin_parser_create(void)
1602 struct wg_parser *parser;
1604 if ((parser = wg_parser_create()))
1605 parser->init_gst = decodebin_parser_init_gst;
1606 return parser;
1609 static struct wg_parser * CDECL wg_avi_parser_create(void)
1611 struct wg_parser *parser;
1613 if ((parser = wg_parser_create()))
1614 parser->init_gst = avi_parser_init_gst;
1615 return parser;
1618 static struct wg_parser * CDECL wg_mpeg_audio_parser_create(void)
1620 struct wg_parser *parser;
1622 if ((parser = wg_parser_create()))
1623 parser->init_gst = mpeg_audio_parser_init_gst;
1624 return parser;
1627 static struct wg_parser * CDECL wg_wave_parser_create(void)
1629 struct wg_parser *parser;
1631 if ((parser = wg_parser_create()))
1632 parser->init_gst = wave_parser_init_gst;
1633 return parser;
1636 static void CDECL wg_parser_destroy(struct wg_parser *parser)
1638 if (parser->bus)
1640 gst_bus_set_sync_handler(parser->bus, NULL, NULL, NULL);
1641 gst_object_unref(parser->bus);
1644 pthread_mutex_destroy(&parser->mutex);
1645 pthread_cond_destroy(&parser->init_cond);
1646 pthread_cond_destroy(&parser->read_cond);
1647 pthread_cond_destroy(&parser->read_done_cond);
1649 free(parser);
1652 static const struct unix_funcs funcs =
1654 wg_decodebin_parser_create,
1655 wg_avi_parser_create,
1656 wg_mpeg_audio_parser_create,
1657 wg_wave_parser_create,
1658 wg_parser_destroy,
1660 wg_parser_connect,
1661 wg_parser_disconnect,
1663 wg_parser_begin_flush,
1664 wg_parser_end_flush,
1666 wg_parser_get_stream_count,
1667 wg_parser_get_stream,
1669 wg_parser_stream_get_preferred_format,
1670 wg_parser_stream_enable,
1671 wg_parser_stream_disable,
1673 wg_parser_stream_get_event,
1674 wg_parser_stream_copy_buffer,
1675 wg_parser_stream_release_buffer,
1676 wg_parser_stream_notify_qos,
1678 wg_parser_stream_seek,
1681 NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out)
1683 if (reason == DLL_PROCESS_ATTACH)
1685 char arg0[] = "wine";
1686 char arg1[] = "--gst-disable-registry-fork";
1687 char *args[] = {arg0, arg1, NULL};
1688 int argc = ARRAY_SIZE(args) - 1;
1689 char **argv = args;
1690 GError *err;
1692 if (!gst_init_check(&argc, &argv, &err))
1694 ERR("Failed to initialize GStreamer: %s\n", debugstr_a(err->message));
1695 g_error_free(err);
1696 return STATUS_UNSUCCESSFUL;
1698 TRACE("GStreamer library version %s; wine built with %d.%d.%d.\n",
1699 gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO);
1701 GST_DEBUG_CATEGORY_INIT(wine, "WINE", GST_DEBUG_FG_RED, "Wine GStreamer support");
1703 *(const struct unix_funcs **)ptr_out = &funcs;
1705 return STATUS_SUCCESS;