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
29 #define WIN32_NO_STATUS
30 #include "gst_private.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
)
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
;
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
)
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
;
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.");
119 if (!gst_structure_get_int(structure
, "channels", &channels
))
121 GST_WARNING("Missing \"channels\" value.");
124 if (!gst_structure_get_int(structure
, "rate", &rate
))
126 GST_WARNING("Missing \"rate\" value.");
130 format
->major_type
= WG_MAJOR_TYPE_AUDIO
;
133 format
->u
.audio
.format
= WG_AUDIO_FORMAT_MPEG1_LAYER1
;
135 format
->u
.audio
.format
= WG_AUDIO_FORMAT_MPEG1_LAYER2
;
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.");
153 if (!gst_structure_get_int(structure
, "height", &height
))
155 GST_WARNING("Missing \"height\" value.");
158 if (!gst_structure_get_fraction(structure
, "framerate", &fps_n
, &fps_d
))
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"))
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"))
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
);
203 gchar
*str
= gst_caps_to_string(caps
);
205 GST_FIXME("Unhandled caps %s.", str
);
210 static GstAudioFormat
wg_audio_format_to_gst(enum wg_audio_format 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
;
229 if ((audio_format
= wg_audio_format_to_gst(format
->u
.audio
.format
)) == GST_AUDIO_FORMAT_UNKNOWN
)
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
)
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
;
263 if ((video_format
= wg_video_format_to_gst(format
->u
.video
.format
)) == GST_VIDEO_FORMAT_UNKNOWN
)
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
);
279 static GstCaps
*wg_format_to_caps(const struct wg_format
*format
)
281 switch (format
->major_type
)
283 case WG_MAJOR_TYPE_UNKNOWN
:
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
);
294 static bool wg_format_compare(const struct wg_format
*a
, const struct wg_format
*b
)
296 if (a
->major_type
!= b
->major_type
)
299 switch (a
->major_type
)
301 case WG_MAJOR_TYPE_UNKNOWN
:
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
;
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
)
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");
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");
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");
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
);
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
);
433 pthread_mutex_unlock(&parser
->mutex
);
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
);
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
)
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
;
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.");
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
));
574 case GST_EVENT_SEGMENT
:
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
));
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
);
599 struct wg_parser_event stream_event
;
601 stream_event
.type
= WG_PARSER_EVENT_EOS
;
602 queue_stream_event(stream
, &stream_event
, NULL
);
606 pthread_mutex_lock(&parser
->mutex
);
608 pthread_mutex_unlock(&parser
->mutex
);
609 pthread_cond_signal(&parser
->init_cond
);
613 case GST_EVENT_FLUSH_START
:
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
);
633 case GST_EVENT_FLUSH_STOP
:
636 pthread_mutex_lock(&parser
->mutex
);
637 stream
->flushing
= false;
638 pthread_mutex_unlock(&parser
->mutex
);
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
);
656 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
658 gst_event_unref(event
);
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
;
668 GST_LOG("stream %p, buffer %p.", stream
, buffer
);
670 if (!stream
->enabled
)
672 gst_buffer_unref(buffer
);
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
);
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
));
703 GstCaps
*caps
, *filter
, *temp
;
705 gst_query_parse_caps(query
, &filter
);
708 caps
= wg_format_to_caps(&stream
->current_format
);
710 caps
= gst_caps_new_any();
716 temp
= gst_caps_intersect(caps
, filter
);
717 gst_caps_unref(caps
);
721 gst_query_set_caps_result(query
, caps
);
722 gst_caps_unref(caps
);
726 case GST_QUERY_ACCEPT_CAPS
:
728 struct wg_format format
;
732 if (!stream
->enabled
)
734 gst_query_set_accept_caps_result(query
, 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
);
747 gst_query_set_accept_caps_result(query
, ret
);
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
;
761 if (!(new_array
= realloc(parser
->streams
, (parser
->stream_count
+ 1) * sizeof(*parser
->streams
))))
763 parser
->streams
= new_array
;
765 if (!(stream
= calloc(1, sizeof(*stream
))))
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
;
783 static void init_new_decoded_pad(GstElement
*element
, GstPad
*pad
, struct wg_parser
*parser
)
785 struct wg_parser_stream
*stream
;
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
)))
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 *));
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 *));
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 *));
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 *));
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");
854 else if (!strcmp(name
, "audio/x-raw"))
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 *));
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
;
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
;
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
));
905 gst_pad_set_active(stream
->my_sink
, 1);
906 gst_object_ref(stream
->their_src
= pad
);
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
))
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
;
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
);
940 gst_pad_unlink(stream
->their_src
, stream
->my_sink
);
941 gst_object_unref(stream
->their_src
);
942 stream
->their_src
= NULL
;
947 name
= gst_pad_get_name(pad
);
948 GST_WARNING("No pin matching pad \"%s\" found.", 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
;
958 GST_LOG("pad %p, offset %" G_GINT64_MODIFIER
"u, length %u, buffer %p.", pad
, offset
, size
, *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
);
991 static gboolean
query_function(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
993 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
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
);
1007 else if (format
== GST_FORMAT_BYTES
)
1009 gst_query_set_duration(query
, GST_FORMAT_BYTES
, parser
->file_size
);
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
));
1021 gst_query_set_seeking(query
, GST_FORMAT_BYTES
, 1, 0, parser
->file_size
);
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
);
1031 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query
));
1036 static void *push_data(void *arg
)
1038 struct wg_parser
*parser
= arg
;
1042 GST_DEBUG("Starting push thread.");
1044 if (!(buffer
= gst_buffer_new_allocate(NULL
, 16384, NULL
)))
1046 GST_ERROR("Failed to allocate memory.");
1050 max_size
= parser
->stop_offset
? parser
->stop_offset
: parser
->file_size
;
1057 if (parser
->next_offset
>= max_size
)
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
));
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
));
1077 gst_buffer_unref(buffer
);
1079 gst_pad_push_event(parser
->my_src
, gst_event_new_eos());
1081 GST_DEBUG("Stopping push thread.");
1086 static gboolean
activate_push(GstPad
*pad
, gboolean activate
)
1088 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1092 if (parser
->push_thread
)
1094 pthread_join(parser
->push_thread
, NULL
);
1095 parser
->push_thread
= 0;
1098 else if (!parser
->push_thread
)
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;
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
));
1121 case GST_PAD_MODE_PULL
:
1123 case GST_PAD_MODE_PUSH
:
1124 return activate_push(pad
, activate
);
1125 case GST_PAD_MODE_NONE
:
1131 static GstBusSyncReply
watch_bus(GstBus
*bus
, GstMessage
*msg
, gpointer user
)
1133 struct wg_parser
*parser
= user
;
1134 gchar
*dbg_info
= NULL
;
1137 GST_DEBUG("parser %p, message type %s.", parser
, GST_MESSAGE_TYPE_NAME(msg
));
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
);
1147 pthread_mutex_lock(&parser
->mutex
);
1148 parser
->error
= true;
1149 pthread_mutex_unlock(&parser
->mutex
);
1150 pthread_cond_signal(&parser
->init_cond
);
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
);
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
);
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
;
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
));
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
);
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
);
1216 gst_pad_set_active(parser
->my_src
, 1);
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
);
1235 case GST_EVENT_FLUSH_START
:
1236 case GST_EVENT_FLUSH_STOP
:
1238 case GST_EVENT_RECONFIGURE
:
1242 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
1246 gst_event_unref(event
);
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");
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
);
1276 parser
->file_size
= file_size
;
1277 parser
->sink_connected
= true;
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
))
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
);
1311 pthread_mutex_unlock(&parser
->mutex
);
1316 pthread_mutex_unlock(&parser
->mutex
);
1318 parser
->next_offset
= 0;
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
;
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
);
1346 static void CDECL
wg_parser_disconnect(struct wg_parser
*parser
)
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
);
1389 ERR("Failed to create decodebin; are %u-bit GStreamer \"base\" plugins installed?\n",
1390 8 * (int)sizeof(void*));
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
);
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");
1421 pthread_mutex_lock(&parser
->mutex
);
1422 while (!parser
->no_more_pads
&& !parser
->error
)
1423 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1426 pthread_mutex_unlock(&parser
->mutex
);
1429 pthread_mutex_unlock(&parser
->mutex
);
1434 static BOOL
avi_parser_init_gst(struct wg_parser
*parser
)
1436 GstElement
*element
= gst_element_factory_make("avidemux", NULL
);
1441 ERR("Failed to create avidemux; are %u-bit GStreamer \"good\" plugins installed?\n",
1442 8 * (int)sizeof(void*));
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
);
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");
1472 pthread_mutex_lock(&parser
->mutex
);
1473 while (!parser
->no_more_pads
&& !parser
->error
)
1474 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1477 pthread_mutex_unlock(&parser
->mutex
);
1480 pthread_mutex_unlock(&parser
->mutex
);
1485 static BOOL
mpeg_audio_parser_init_gst(struct wg_parser
*parser
)
1487 struct wg_parser_stream
*stream
;
1488 GstElement
*element
;
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*));
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
);
1507 if (!(stream
= create_stream(parser
)))
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
);
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");
1526 pthread_mutex_lock(&parser
->mutex
);
1527 while (!parser
->has_duration
&& !parser
->error
&& !stream
->eos
)
1528 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1531 pthread_mutex_unlock(&parser
->mutex
);
1534 pthread_mutex_unlock(&parser
->mutex
);
1538 static BOOL
wave_parser_init_gst(struct wg_parser
*parser
)
1540 struct wg_parser_stream
*stream
;
1541 GstElement
*element
;
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*));
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
);
1560 if (!(stream
= create_stream(parser
)))
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
);
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");
1583 static struct wg_parser
*wg_parser_create(void)
1585 struct wg_parser
*parser
;
1587 if (!(parser
= calloc(1, sizeof(*parser
))))
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
);
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
;
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
;
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
;
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
;
1636 static void CDECL
wg_parser_destroy(struct wg_parser
*parser
)
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
);
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
,
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;
1692 if (!gst_init_check(&argc
, &argv
, &err
))
1694 ERR("Failed to initialize GStreamer: %s\n", debugstr_a(err
->message
));
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
;