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 #include <gst/video/video.h>
35 #include <gst/audio/audio.h>
37 WINE_DEFAULT_DEBUG_CHANNEL(gstreamer
);
39 GST_DEBUG_CATEGORY_STATIC(wine
);
40 #define GST_CAT_DEFAULT wine
44 BOOL (*init_gst
)(struct wg_parser
*parser
);
46 struct wg_parser_stream
**streams
;
47 unsigned int stream_count
;
49 GstElement
*container
, *decodebin
;
51 GstPad
*my_src
, *their_sink
;
53 guint64 file_size
, start_offset
, next_offset
, stop_offset
;
54 guint64 next_pull_offset
;
56 pthread_t push_thread
;
58 pthread_mutex_t mutex
;
60 pthread_cond_t init_cond
;
61 bool no_more_pads
, has_duration
, error
;
63 pthread_cond_t read_cond
, read_done_cond
;
73 bool flushing
, sink_connected
;
76 struct wg_parser_stream
78 struct wg_parser
*parser
;
80 GstPad
*their_src
, *post_sink
, *post_src
, *my_sink
;
83 struct wg_format preferred_format
, current_format
;
85 pthread_cond_t event_cond
, event_empty_cond
;
86 struct wg_parser_event event
;
90 bool flushing
, eos
, enabled
, has_caps
;
95 static enum wg_audio_format
wg_audio_format_from_gst(GstAudioFormat format
)
99 case GST_AUDIO_FORMAT_U8
:
100 return WG_AUDIO_FORMAT_U8
;
101 case GST_AUDIO_FORMAT_S16LE
:
102 return WG_AUDIO_FORMAT_S16LE
;
103 case GST_AUDIO_FORMAT_S24LE
:
104 return WG_AUDIO_FORMAT_S24LE
;
105 case GST_AUDIO_FORMAT_S32LE
:
106 return WG_AUDIO_FORMAT_S32LE
;
107 case GST_AUDIO_FORMAT_F32LE
:
108 return WG_AUDIO_FORMAT_F32LE
;
109 case GST_AUDIO_FORMAT_F64LE
:
110 return WG_AUDIO_FORMAT_F64LE
;
112 return WG_AUDIO_FORMAT_UNKNOWN
;
116 static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position
)
118 static const uint32_t position_map
[] =
122 SPEAKER_FRONT_CENTER
,
123 SPEAKER_LOW_FREQUENCY
,
126 SPEAKER_FRONT_LEFT_OF_CENTER
,
127 SPEAKER_FRONT_RIGHT_OF_CENTER
,
132 SPEAKER_TOP_FRONT_LEFT
,
133 SPEAKER_TOP_FRONT_RIGHT
,
134 SPEAKER_TOP_FRONT_CENTER
,
136 SPEAKER_TOP_BACK_LEFT
,
137 SPEAKER_TOP_BACK_RIGHT
,
140 SPEAKER_TOP_BACK_CENTER
,
143 if (position
< ARRAY_SIZE(position_map
))
144 return position_map
[position
];
148 static uint32_t wg_channel_mask_from_gst(const GstAudioInfo
*info
)
150 uint32_t mask
= 0, position
;
153 for (i
= 0; i
< GST_AUDIO_INFO_CHANNELS(info
); ++i
)
155 if (!(position
= wg_channel_position_from_gst(GST_AUDIO_INFO_POSITION(info
, i
))))
157 GST_WARNING("Unsupported channel %#x.", GST_AUDIO_INFO_POSITION(info
, i
));
160 /* Make sure it's also in WinMM order. WinMM mandates that channels be
161 * ordered, as it were, from least to most significant SPEAKER_* bit.
162 * Hence we fail if the current channel was already specified, or if any
163 * higher bit was already specified. */
164 if (mask
& ~(position
- 1))
166 GST_WARNING("Unsupported channel order.");
174 static void wg_format_from_audio_info(struct wg_format
*format
, const GstAudioInfo
*info
)
176 format
->major_type
= WG_MAJOR_TYPE_AUDIO
;
177 format
->u
.audio
.format
= wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info
));
178 format
->u
.audio
.channels
= GST_AUDIO_INFO_CHANNELS(info
);
179 format
->u
.audio
.channel_mask
= wg_channel_mask_from_gst(info
);
180 format
->u
.audio
.rate
= GST_AUDIO_INFO_RATE(info
);
183 static enum wg_video_format
wg_video_format_from_gst(GstVideoFormat format
)
187 case GST_VIDEO_FORMAT_BGRA
:
188 return WG_VIDEO_FORMAT_BGRA
;
189 case GST_VIDEO_FORMAT_BGRx
:
190 return WG_VIDEO_FORMAT_BGRx
;
191 case GST_VIDEO_FORMAT_BGR
:
192 return WG_VIDEO_FORMAT_BGR
;
193 case GST_VIDEO_FORMAT_RGB15
:
194 return WG_VIDEO_FORMAT_RGB15
;
195 case GST_VIDEO_FORMAT_AYUV
:
196 return WG_VIDEO_FORMAT_AYUV
;
197 case GST_VIDEO_FORMAT_I420
:
198 return WG_VIDEO_FORMAT_I420
;
199 case GST_VIDEO_FORMAT_NV12
:
200 return WG_VIDEO_FORMAT_NV12
;
201 case GST_VIDEO_FORMAT_UYVY
:
202 return WG_VIDEO_FORMAT_UYVY
;
203 case GST_VIDEO_FORMAT_YUY2
:
204 return WG_VIDEO_FORMAT_YUY2
;
205 case GST_VIDEO_FORMAT_YV12
:
206 return WG_VIDEO_FORMAT_YV12
;
207 case GST_VIDEO_FORMAT_YVYU
:
208 return WG_VIDEO_FORMAT_YVYU
;
210 return WG_VIDEO_FORMAT_UNKNOWN
;
214 static void wg_format_from_video_info(struct wg_format
*format
, const GstVideoInfo
*info
)
216 format
->major_type
= WG_MAJOR_TYPE_VIDEO
;
217 format
->u
.video
.format
= wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info
));
218 format
->u
.video
.width
= GST_VIDEO_INFO_WIDTH(info
);
219 format
->u
.video
.height
= GST_VIDEO_INFO_HEIGHT(info
);
220 format
->u
.video
.fps_n
= GST_VIDEO_INFO_FPS_N(info
);
221 format
->u
.video
.fps_d
= GST_VIDEO_INFO_FPS_D(info
);
224 static void wg_format_from_caps_audio_mpeg(struct wg_format
*format
, const GstCaps
*caps
)
226 const GstStructure
*structure
= gst_caps_get_structure(caps
, 0);
227 gint layer
, channels
, rate
;
229 if (!gst_structure_get_int(structure
, "layer", &layer
))
231 GST_WARNING("Missing \"layer\" value.");
234 if (!gst_structure_get_int(structure
, "channels", &channels
))
236 GST_WARNING("Missing \"channels\" value.");
239 if (!gst_structure_get_int(structure
, "rate", &rate
))
241 GST_WARNING("Missing \"rate\" value.");
245 format
->major_type
= WG_MAJOR_TYPE_AUDIO
;
248 format
->u
.audio
.format
= WG_AUDIO_FORMAT_MPEG1_LAYER1
;
250 format
->u
.audio
.format
= WG_AUDIO_FORMAT_MPEG1_LAYER2
;
252 format
->u
.audio
.format
= WG_AUDIO_FORMAT_MPEG1_LAYER3
;
254 format
->u
.audio
.channels
= channels
;
255 format
->u
.audio
.rate
= rate
;
258 static void wg_format_from_caps_video_cinepak(struct wg_format
*format
, const GstCaps
*caps
)
260 const GstStructure
*structure
= gst_caps_get_structure(caps
, 0);
261 gint width
, height
, fps_n
, fps_d
;
263 if (!gst_structure_get_int(structure
, "width", &width
))
265 GST_WARNING("Missing \"width\" value.");
268 if (!gst_structure_get_int(structure
, "height", &height
))
270 GST_WARNING("Missing \"height\" value.");
273 if (!gst_structure_get_fraction(structure
, "framerate", &fps_n
, &fps_d
))
279 format
->major_type
= WG_MAJOR_TYPE_VIDEO
;
280 format
->u
.video
.format
= WG_VIDEO_FORMAT_CINEPAK
;
281 format
->u
.video
.width
= width
;
282 format
->u
.video
.height
= height
;
283 format
->u
.video
.fps_n
= fps_n
;
284 format
->u
.video
.fps_d
= fps_d
;
287 static void wg_format_from_caps(struct wg_format
*format
, const GstCaps
*caps
)
289 const GstStructure
*structure
= gst_caps_get_structure(caps
, 0);
290 const char *name
= gst_structure_get_name(structure
);
292 memset(format
, 0, sizeof(*format
));
294 if (!strcmp(name
, "audio/x-raw"))
298 if (gst_audio_info_from_caps(&info
, caps
))
299 wg_format_from_audio_info(format
, &info
);
301 else if (!strcmp(name
, "video/x-raw"))
305 if (gst_video_info_from_caps(&info
, caps
))
306 wg_format_from_video_info(format
, &info
);
308 else if (!strcmp(name
, "audio/mpeg"))
310 wg_format_from_caps_audio_mpeg(format
, caps
);
312 else if (!strcmp(name
, "video/x-cinepak"))
314 wg_format_from_caps_video_cinepak(format
, caps
);
318 gchar
*str
= gst_caps_to_string(caps
);
320 GST_FIXME("Unhandled caps %s.", str
);
325 static GstAudioFormat
wg_audio_format_to_gst(enum wg_audio_format format
)
329 case WG_AUDIO_FORMAT_U8
: return GST_AUDIO_FORMAT_U8
;
330 case WG_AUDIO_FORMAT_S16LE
: return GST_AUDIO_FORMAT_S16LE
;
331 case WG_AUDIO_FORMAT_S24LE
: return GST_AUDIO_FORMAT_S24LE
;
332 case WG_AUDIO_FORMAT_S32LE
: return GST_AUDIO_FORMAT_S32LE
;
333 case WG_AUDIO_FORMAT_F32LE
: return GST_AUDIO_FORMAT_F32LE
;
334 case WG_AUDIO_FORMAT_F64LE
: return GST_AUDIO_FORMAT_F64LE
;
335 default: return GST_AUDIO_FORMAT_UNKNOWN
;
339 static void wg_channel_mask_to_gst(GstAudioChannelPosition
*positions
, uint32_t mask
, uint32_t channel_count
)
341 const uint32_t orig_mask
= mask
;
345 static const GstAudioChannelPosition position_map
[] =
347 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT
,
348 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT
,
349 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER
,
350 GST_AUDIO_CHANNEL_POSITION_LFE1
,
351 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT
,
352 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT
,
353 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER
,
354 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER
,
355 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER
,
356 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT
,
357 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
,
358 GST_AUDIO_CHANNEL_POSITION_TOP_CENTER
,
359 GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT
,
360 GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER
,
361 GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT
,
362 GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT
,
363 GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER
,
364 GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT
,
367 for (i
= 0; i
< channel_count
; ++i
)
369 positions
[i
] = GST_AUDIO_CHANNEL_POSITION_NONE
;
370 if (BitScanForward(&bit
, mask
))
372 if (bit
< ARRAY_SIZE(position_map
))
373 positions
[i
] = position_map
[bit
];
375 GST_WARNING("Invalid channel mask %#x.\n", orig_mask
);
380 GST_WARNING("Incomplete channel mask %#x.\n", orig_mask
);
385 static GstCaps
*wg_format_to_caps_audio(const struct wg_format
*format
)
387 GstAudioChannelPosition positions
[32];
388 GstAudioFormat audio_format
;
391 if ((audio_format
= wg_audio_format_to_gst(format
->u
.audio
.format
)) == GST_AUDIO_FORMAT_UNKNOWN
)
394 wg_channel_mask_to_gst(positions
, format
->u
.audio
.channel_mask
, format
->u
.audio
.channels
);
395 gst_audio_info_set_format(&info
, audio_format
, format
->u
.audio
.rate
, format
->u
.audio
.channels
, positions
);
396 return gst_audio_info_to_caps(&info
);
399 static GstVideoFormat
wg_video_format_to_gst(enum wg_video_format format
)
403 case WG_VIDEO_FORMAT_BGRA
: return GST_VIDEO_FORMAT_BGRA
;
404 case WG_VIDEO_FORMAT_BGRx
: return GST_VIDEO_FORMAT_BGRx
;
405 case WG_VIDEO_FORMAT_BGR
: return GST_VIDEO_FORMAT_BGR
;
406 case WG_VIDEO_FORMAT_RGB15
: return GST_VIDEO_FORMAT_RGB15
;
407 case WG_VIDEO_FORMAT_RGB16
: return GST_VIDEO_FORMAT_RGB16
;
408 case WG_VIDEO_FORMAT_AYUV
: return GST_VIDEO_FORMAT_AYUV
;
409 case WG_VIDEO_FORMAT_I420
: return GST_VIDEO_FORMAT_I420
;
410 case WG_VIDEO_FORMAT_NV12
: return GST_VIDEO_FORMAT_NV12
;
411 case WG_VIDEO_FORMAT_UYVY
: return GST_VIDEO_FORMAT_UYVY
;
412 case WG_VIDEO_FORMAT_YUY2
: return GST_VIDEO_FORMAT_YUY2
;
413 case WG_VIDEO_FORMAT_YV12
: return GST_VIDEO_FORMAT_YV12
;
414 case WG_VIDEO_FORMAT_YVYU
: return GST_VIDEO_FORMAT_YVYU
;
415 default: return GST_VIDEO_FORMAT_UNKNOWN
;
419 static GstCaps
*wg_format_to_caps_video(const struct wg_format
*format
)
421 GstVideoFormat video_format
;
426 if ((video_format
= wg_video_format_to_gst(format
->u
.video
.format
)) == GST_VIDEO_FORMAT_UNKNOWN
)
429 gst_video_info_set_format(&info
, video_format
, format
->u
.video
.width
, format
->u
.video
.height
);
430 if ((caps
= gst_video_info_to_caps(&info
)))
432 /* Clear some fields that shouldn't prevent us from connecting. */
433 for (i
= 0; i
< gst_caps_get_size(caps
); ++i
)
435 gst_structure_remove_fields(gst_caps_get_structure(caps
, i
),
436 "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL
);
442 static GstCaps
*wg_format_to_caps(const struct wg_format
*format
)
444 switch (format
->major_type
)
446 case WG_MAJOR_TYPE_UNKNOWN
:
448 case WG_MAJOR_TYPE_AUDIO
:
449 return wg_format_to_caps_audio(format
);
450 case WG_MAJOR_TYPE_VIDEO
:
451 return wg_format_to_caps_video(format
);
457 static bool wg_format_compare(const struct wg_format
*a
, const struct wg_format
*b
)
459 if (a
->major_type
!= b
->major_type
)
462 switch (a
->major_type
)
464 case WG_MAJOR_TYPE_UNKNOWN
:
467 case WG_MAJOR_TYPE_AUDIO
:
468 return a
->u
.audio
.format
== b
->u
.audio
.format
469 && a
->u
.audio
.channels
== b
->u
.audio
.channels
470 && a
->u
.audio
.rate
== b
->u
.audio
.rate
;
472 case WG_MAJOR_TYPE_VIDEO
:
473 /* Do not compare FPS. */
474 return a
->u
.video
.format
== b
->u
.video
.format
475 && a
->u
.video
.width
== b
->u
.video
.width
476 && a
->u
.video
.height
== b
->u
.video
.height
;
483 static uint32_t CDECL
wg_parser_get_stream_count(struct wg_parser
*parser
)
485 return parser
->stream_count
;
488 static struct wg_parser_stream
* CDECL
wg_parser_get_stream(struct wg_parser
*parser
, uint32_t index
)
490 return parser
->streams
[index
];
493 static void CDECL
wg_parser_begin_flush(struct wg_parser
*parser
)
497 pthread_mutex_lock(&parser
->mutex
);
498 parser
->flushing
= true;
499 pthread_mutex_unlock(&parser
->mutex
);
501 for (i
= 0; i
< parser
->stream_count
; ++i
)
503 if (parser
->streams
[i
]->enabled
)
504 pthread_cond_signal(&parser
->streams
[i
]->event_cond
);
508 static void CDECL
wg_parser_end_flush(struct wg_parser
*parser
)
510 pthread_mutex_lock(&parser
->mutex
);
511 parser
->flushing
= false;
512 pthread_mutex_unlock(&parser
->mutex
);
515 static bool CDECL
wg_parser_get_read_request(struct wg_parser
*parser
,
516 void **data
, uint64_t *offset
, uint32_t *size
)
518 pthread_mutex_lock(&parser
->mutex
);
520 while (parser
->sink_connected
&& !parser
->read_request
.data
)
521 pthread_cond_wait(&parser
->read_cond
, &parser
->mutex
);
523 if (!parser
->sink_connected
)
525 pthread_mutex_unlock(&parser
->mutex
);
529 *data
= parser
->read_request
.data
;
530 *offset
= parser
->read_request
.offset
;
531 *size
= parser
->read_request
.size
;
533 pthread_mutex_unlock(&parser
->mutex
);
537 static void CDECL
wg_parser_complete_read_request(struct wg_parser
*parser
, bool ret
)
539 pthread_mutex_lock(&parser
->mutex
);
540 parser
->read_request
.done
= true;
541 parser
->read_request
.ret
= ret
;
542 parser
->read_request
.data
= NULL
;
543 pthread_mutex_unlock(&parser
->mutex
);
544 pthread_cond_signal(&parser
->read_done_cond
);
547 static void CDECL
wg_parser_set_unlimited_buffering(struct wg_parser
*parser
)
549 g_object_set(parser
->decodebin
, "max-size-buffers", G_MAXUINT
, NULL
);
550 g_object_set(parser
->decodebin
, "max-size-time", G_MAXUINT64
, NULL
);
551 g_object_set(parser
->decodebin
, "max-size-bytes", G_MAXUINT
, NULL
);
554 static void CDECL
wg_parser_stream_get_preferred_format(struct wg_parser_stream
*stream
, struct wg_format
*format
)
556 *format
= stream
->preferred_format
;
559 static void CDECL
wg_parser_stream_enable(struct wg_parser_stream
*stream
, const struct wg_format
*format
)
561 stream
->current_format
= *format
;
562 stream
->enabled
= true;
564 if (format
->major_type
== WG_MAJOR_TYPE_VIDEO
)
566 switch (format
->u
.video
.format
)
568 case WG_VIDEO_FORMAT_BGRA
:
569 case WG_VIDEO_FORMAT_BGRx
:
570 case WG_VIDEO_FORMAT_BGR
:
571 case WG_VIDEO_FORMAT_RGB15
:
572 case WG_VIDEO_FORMAT_RGB16
:
573 gst_util_set_object_arg(G_OBJECT(stream
->flip
), "method", "vertical-flip");
576 case WG_VIDEO_FORMAT_AYUV
:
577 case WG_VIDEO_FORMAT_I420
:
578 case WG_VIDEO_FORMAT_NV12
:
579 case WG_VIDEO_FORMAT_UYVY
:
580 case WG_VIDEO_FORMAT_YUY2
:
581 case WG_VIDEO_FORMAT_YV12
:
582 case WG_VIDEO_FORMAT_YVYU
:
583 case WG_VIDEO_FORMAT_UNKNOWN
:
584 case WG_VIDEO_FORMAT_CINEPAK
:
585 gst_util_set_object_arg(G_OBJECT(stream
->flip
), "method", "none");
590 gst_pad_push_event(stream
->my_sink
, gst_event_new_reconfigure());
593 static void CDECL
wg_parser_stream_disable(struct wg_parser_stream
*stream
)
595 stream
->enabled
= false;
598 static bool CDECL
wg_parser_stream_get_event(struct wg_parser_stream
*stream
, struct wg_parser_event
*event
)
600 struct wg_parser
*parser
= stream
->parser
;
602 pthread_mutex_lock(&parser
->mutex
);
604 while (!parser
->flushing
&& stream
->event
.type
== WG_PARSER_EVENT_NONE
)
605 pthread_cond_wait(&stream
->event_cond
, &parser
->mutex
);
607 if (parser
->flushing
)
609 pthread_mutex_unlock(&parser
->mutex
);
610 TRACE("Filter is flushing.\n");
614 *event
= stream
->event
;
616 if (stream
->event
.type
!= WG_PARSER_EVENT_BUFFER
)
618 stream
->event
.type
= WG_PARSER_EVENT_NONE
;
619 pthread_cond_signal(&stream
->event_empty_cond
);
621 pthread_mutex_unlock(&parser
->mutex
);
626 static bool CDECL
wg_parser_stream_copy_buffer(struct wg_parser_stream
*stream
,
627 void *data
, uint32_t offset
, uint32_t size
)
629 struct wg_parser
*parser
= stream
->parser
;
631 pthread_mutex_lock(&parser
->mutex
);
635 pthread_mutex_unlock(&parser
->mutex
);
639 assert(stream
->event
.type
== WG_PARSER_EVENT_BUFFER
);
640 assert(offset
< stream
->map_info
.size
);
641 assert(offset
+ size
<= stream
->map_info
.size
);
642 memcpy(data
, stream
->map_info
.data
+ offset
, size
);
644 pthread_mutex_unlock(&parser
->mutex
);
648 static void CDECL
wg_parser_stream_release_buffer(struct wg_parser_stream
*stream
)
650 struct wg_parser
*parser
= stream
->parser
;
652 pthread_mutex_lock(&parser
->mutex
);
654 assert(stream
->event
.type
== WG_PARSER_EVENT_BUFFER
);
656 gst_buffer_unmap(stream
->buffer
, &stream
->map_info
);
657 gst_buffer_unref(stream
->buffer
);
658 stream
->buffer
= NULL
;
659 stream
->event
.type
= WG_PARSER_EVENT_NONE
;
661 pthread_mutex_unlock(&parser
->mutex
);
662 pthread_cond_signal(&stream
->event_empty_cond
);
665 static uint64_t CDECL
wg_parser_stream_get_duration(struct wg_parser_stream
*stream
)
667 return stream
->duration
;
670 static bool CDECL
wg_parser_stream_seek(struct wg_parser_stream
*stream
, double rate
,
671 uint64_t start_pos
, uint64_t stop_pos
, DWORD start_flags
, DWORD stop_flags
)
673 GstSeekType start_type
= GST_SEEK_TYPE_SET
, stop_type
= GST_SEEK_TYPE_SET
;
674 GstSeekFlags flags
= 0;
676 if (start_flags
& AM_SEEKING_SeekToKeyFrame
)
677 flags
|= GST_SEEK_FLAG_KEY_UNIT
;
678 if (start_flags
& AM_SEEKING_Segment
)
679 flags
|= GST_SEEK_FLAG_SEGMENT
;
680 if (!(start_flags
& AM_SEEKING_NoFlush
))
681 flags
|= GST_SEEK_FLAG_FLUSH
;
683 if ((start_flags
& AM_SEEKING_PositioningBitsMask
) == AM_SEEKING_NoPositioning
)
684 start_type
= GST_SEEK_TYPE_NONE
;
685 if ((stop_flags
& AM_SEEKING_PositioningBitsMask
) == AM_SEEKING_NoPositioning
)
686 stop_type
= GST_SEEK_TYPE_NONE
;
688 return gst_pad_push_event(stream
->my_sink
, gst_event_new_seek(rate
,
689 GST_FORMAT_TIME
, flags
, start_type
, start_pos
* 100, stop_type
, stop_pos
* 100));
692 static void CDECL
wg_parser_stream_notify_qos(struct wg_parser_stream
*stream
,
693 bool underflow
, double proportion
, int64_t diff
, uint64_t timestamp
)
695 GstClockTime stream_time
;
698 /* We return timestamps in stream time, i.e. relative to the start of the
699 * file (or other medium), but gst_event_new_qos() expects the timestamp in
701 stream_time
= gst_segment_to_running_time(&stream
->segment
, GST_FORMAT_TIME
, timestamp
* 100);
702 if (stream_time
== -1)
704 /* This can happen legitimately if the sample falls outside of the
705 * segment bounds. GStreamer elements shouldn't present the sample in
706 * that case, but DirectShow doesn't care. */
707 TRACE("Ignoring QoS event.\n");
711 if (!(event
= gst_event_new_qos(underflow
? GST_QOS_TYPE_UNDERFLOW
: GST_QOS_TYPE_OVERFLOW
,
712 proportion
, diff
* 100, stream_time
)))
713 ERR("Failed to create QOS event.\n");
714 gst_pad_push_event(stream
->my_sink
, event
);
717 static GstAutoplugSelectResult
autoplug_select_cb(GstElement
*bin
, GstPad
*pad
,
718 GstCaps
*caps
, GstElementFactory
*fact
, gpointer user
)
720 const char *name
= gst_element_factory_get_longname(fact
);
722 GST_TRACE("Using \"%s\".", name
);
724 if (strstr(name
, "Player protection"))
726 GST_WARNING("Blacklisted a/52 decoder because it only works in Totem.");
727 return GST_AUTOPLUG_SELECT_SKIP
;
729 if (!strcmp(name
, "Fluendo Hardware Accelerated Video Decoder"))
731 GST_WARNING("Disabled video acceleration since it breaks in wine.");
732 return GST_AUTOPLUG_SELECT_SKIP
;
734 return GST_AUTOPLUG_SELECT_TRY
;
737 static void no_more_pads_cb(GstElement
*element
, gpointer user
)
739 struct wg_parser
*parser
= user
;
741 GST_DEBUG("parser %p.", parser
);
743 pthread_mutex_lock(&parser
->mutex
);
744 parser
->no_more_pads
= true;
745 pthread_mutex_unlock(&parser
->mutex
);
746 pthread_cond_signal(&parser
->init_cond
);
749 static GstFlowReturn
queue_stream_event(struct wg_parser_stream
*stream
,
750 const struct wg_parser_event
*event
, GstBuffer
*buffer
)
752 struct wg_parser
*parser
= stream
->parser
;
754 /* Unlike request_buffer_src() [q.v.], we need to watch for GStreamer
755 * flushes here. The difference is that we can be blocked by the streaming
756 * thread not running (or itself flushing on the DirectShow side).
757 * request_buffer_src() can only be blocked by the upstream source, and that
758 * is solved by flushing the upstream source. */
760 pthread_mutex_lock(&parser
->mutex
);
761 while (!stream
->flushing
&& stream
->event
.type
!= WG_PARSER_EVENT_NONE
)
762 pthread_cond_wait(&stream
->event_empty_cond
, &parser
->mutex
);
763 if (stream
->flushing
)
765 pthread_mutex_unlock(&parser
->mutex
);
766 GST_DEBUG("Filter is flushing; discarding event.");
767 return GST_FLOW_FLUSHING
;
771 assert(GST_IS_BUFFER(buffer
));
772 if (!gst_buffer_map(buffer
, &stream
->map_info
, GST_MAP_READ
))
774 pthread_mutex_unlock(&parser
->mutex
);
775 GST_ERROR("Failed to map buffer.\n");
776 return GST_FLOW_ERROR
;
779 stream
->event
= *event
;
780 stream
->buffer
= buffer
;
781 pthread_mutex_unlock(&parser
->mutex
);
782 pthread_cond_signal(&stream
->event_cond
);
783 GST_LOG("Event queued.");
787 static gboolean
sink_event_cb(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
789 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
790 struct wg_parser
*parser
= stream
->parser
;
792 GST_LOG("stream %p, type \"%s\".", stream
, GST_EVENT_TYPE_NAME(event
));
796 case GST_EVENT_SEGMENT
:
799 struct wg_parser_event stream_event
;
800 const GstSegment
*segment
;
802 gst_event_parse_segment(event
, &segment
);
804 if (segment
->format
!= GST_FORMAT_TIME
)
806 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(segment
->format
));
810 gst_segment_copy_into(segment
, &stream
->segment
);
812 stream_event
.type
= WG_PARSER_EVENT_SEGMENT
;
813 stream_event
.u
.segment
.position
= segment
->position
/ 100;
814 stream_event
.u
.segment
.stop
= segment
->stop
/ 100;
815 stream_event
.u
.segment
.rate
= segment
->rate
* segment
->applied_rate
;
816 queue_stream_event(stream
, &stream_event
, NULL
);
823 struct wg_parser_event stream_event
;
825 stream_event
.type
= WG_PARSER_EVENT_EOS
;
826 queue_stream_event(stream
, &stream_event
, NULL
);
830 pthread_mutex_lock(&parser
->mutex
);
832 pthread_mutex_unlock(&parser
->mutex
);
833 pthread_cond_signal(&parser
->init_cond
);
837 case GST_EVENT_FLUSH_START
:
840 pthread_mutex_lock(&parser
->mutex
);
842 stream
->flushing
= true;
843 pthread_cond_signal(&stream
->event_empty_cond
);
845 if (stream
->event
.type
== WG_PARSER_EVENT_BUFFER
)
847 gst_buffer_unmap(stream
->buffer
, &stream
->map_info
);
848 gst_buffer_unref(stream
->buffer
);
849 stream
->buffer
= NULL
;
851 stream
->event
.type
= WG_PARSER_EVENT_NONE
;
853 pthread_mutex_unlock(&parser
->mutex
);
857 case GST_EVENT_FLUSH_STOP
:
861 gst_event_parse_flush_stop(event
, &reset_time
);
864 gst_segment_init(&stream
->segment
, GST_FORMAT_UNDEFINED
);
868 pthread_mutex_lock(&parser
->mutex
);
869 stream
->flushing
= false;
870 pthread_mutex_unlock(&parser
->mutex
);
879 gst_event_parse_caps(event
, &caps
);
880 pthread_mutex_lock(&parser
->mutex
);
881 wg_format_from_caps(&stream
->preferred_format
, caps
);
882 stream
->has_caps
= true;
883 pthread_mutex_unlock(&parser
->mutex
);
884 pthread_cond_signal(&parser
->init_cond
);
889 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
891 gst_event_unref(event
);
895 static GstFlowReturn
sink_chain_cb(GstPad
*pad
, GstObject
*parent
, GstBuffer
*buffer
)
897 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
898 struct wg_parser_event stream_event
;
901 GST_LOG("stream %p, buffer %p.", stream
, buffer
);
903 if (!stream
->enabled
)
905 gst_buffer_unref(buffer
);
909 stream_event
.type
= WG_PARSER_EVENT_BUFFER
;
911 /* FIXME: Should we use gst_segment_to_stream_time_full()? Under what
912 * circumstances is the stream time not equal to the buffer PTS? Note that
913 * this will need modification to wg_parser_stream_notify_qos() as well. */
915 if ((stream_event
.u
.buffer
.has_pts
= GST_BUFFER_PTS_IS_VALID(buffer
)))
916 stream_event
.u
.buffer
.pts
= GST_BUFFER_PTS(buffer
) / 100;
917 if ((stream_event
.u
.buffer
.has_duration
= GST_BUFFER_DURATION_IS_VALID(buffer
)))
918 stream_event
.u
.buffer
.duration
= GST_BUFFER_DURATION(buffer
) / 100;
919 stream_event
.u
.buffer
.discontinuity
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_DISCONT
);
920 stream_event
.u
.buffer
.preroll
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_LIVE
);
921 stream_event
.u
.buffer
.delta
= GST_BUFFER_FLAG_IS_SET(buffer
, GST_BUFFER_FLAG_DELTA_UNIT
);
922 stream_event
.u
.buffer
.size
= gst_buffer_get_size(buffer
);
924 /* Transfer our reference to the buffer to the stream object. */
925 if ((ret
= queue_stream_event(stream
, &stream_event
, buffer
)) != GST_FLOW_OK
)
926 gst_buffer_unref(buffer
);
930 static gboolean
sink_query_cb(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
932 struct wg_parser_stream
*stream
= gst_pad_get_element_private(pad
);
934 GST_LOG("stream %p, type \"%s\".", stream
, gst_query_type_get_name(query
->type
));
940 GstCaps
*caps
, *filter
, *temp
;
942 gst_query_parse_caps(query
, &filter
);
945 caps
= wg_format_to_caps(&stream
->current_format
);
947 caps
= gst_caps_new_any();
953 temp
= gst_caps_intersect(caps
, filter
);
954 gst_caps_unref(caps
);
958 gst_query_set_caps_result(query
, caps
);
959 gst_caps_unref(caps
);
963 case GST_QUERY_ACCEPT_CAPS
:
965 struct wg_format format
;
969 if (!stream
->enabled
)
971 gst_query_set_accept_caps_result(query
, TRUE
);
975 gst_query_parse_accept_caps(query
, &caps
);
976 wg_format_from_caps(&format
, caps
);
977 ret
= wg_format_compare(&format
, &stream
->current_format
);
978 if (!ret
&& WARN_ON(gstreamer
))
980 gchar
*str
= gst_caps_to_string(caps
);
981 GST_WARNING("Rejecting caps \"%s\".", str
);
984 gst_query_set_accept_caps_result(query
, ret
);
989 return gst_pad_query_default (pad
, parent
, query
);
993 static struct wg_parser_stream
*create_stream(struct wg_parser
*parser
)
995 struct wg_parser_stream
*stream
, **new_array
;
998 if (!(new_array
= realloc(parser
->streams
, (parser
->stream_count
+ 1) * sizeof(*parser
->streams
))))
1000 parser
->streams
= new_array
;
1002 if (!(stream
= calloc(1, sizeof(*stream
))))
1005 gst_segment_init(&stream
->segment
, GST_FORMAT_UNDEFINED
);
1007 stream
->parser
= parser
;
1008 pthread_cond_init(&stream
->event_cond
, NULL
);
1009 pthread_cond_init(&stream
->event_empty_cond
, NULL
);
1011 sprintf(pad_name
, "qz_sink_%u", parser
->stream_count
);
1012 stream
->my_sink
= gst_pad_new(pad_name
, GST_PAD_SINK
);
1013 gst_pad_set_element_private(stream
->my_sink
, stream
);
1014 gst_pad_set_chain_function(stream
->my_sink
, sink_chain_cb
);
1015 gst_pad_set_event_function(stream
->my_sink
, sink_event_cb
);
1016 gst_pad_set_query_function(stream
->my_sink
, sink_query_cb
);
1018 parser
->streams
[parser
->stream_count
++] = stream
;
1022 static void pad_added_cb(GstElement
*element
, GstPad
*pad
, gpointer user
)
1024 struct wg_parser
*parser
= user
;
1025 struct wg_parser_stream
*stream
;
1030 GST_LOG("parser %p, element %p, pad %p.", parser
, element
, pad
);
1032 if (gst_pad_is_linked(pad
))
1035 caps
= gst_pad_query_caps(pad
, NULL
);
1036 name
= gst_structure_get_name(gst_caps_get_structure(caps
, 0));
1038 if (!(stream
= create_stream(parser
)))
1041 if (!strcmp(name
, "video/x-raw"))
1043 GstElement
*deinterlace
, *vconv
, *flip
, *vconv2
;
1045 /* DirectShow can express interlaced video, but downstream filters can't
1046 * necessarily consume it. In particular, the video renderer can't. */
1047 if (!(deinterlace
= gst_element_factory_make("deinterlace", NULL
)))
1049 fprintf(stderr
, "winegstreamer: failed to create deinterlace, are %u-bit GStreamer \"good\" plugins installed?\n",
1050 8 * (int)sizeof(void *));
1054 /* decodebin considers many YUV formats to be "raw", but some quartz
1055 * filters can't handle those. Also, videoflip can't handle all "raw"
1056 * formats either. Add a videoconvert to swap color spaces. */
1057 if (!(vconv
= gst_element_factory_make("videoconvert", NULL
)))
1059 fprintf(stderr
, "winegstreamer: failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
1060 8 * (int)sizeof(void *));
1064 /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
1065 if (!(flip
= gst_element_factory_make("videoflip", NULL
)))
1067 fprintf(stderr
, "winegstreamer: failed to create videoflip, are %u-bit GStreamer \"good\" plugins installed?\n",
1068 8 * (int)sizeof(void *));
1072 /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert
1073 * to do the final conversion. */
1074 if (!(vconv2
= gst_element_factory_make("videoconvert", NULL
)))
1076 fprintf(stderr
, "winegstreamer: failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
1077 8 * (int)sizeof(void *));
1081 /* The bin takes ownership of these elements. */
1082 gst_bin_add(GST_BIN(parser
->container
), deinterlace
);
1083 gst_element_sync_state_with_parent(deinterlace
);
1084 gst_bin_add(GST_BIN(parser
->container
), vconv
);
1085 gst_element_sync_state_with_parent(vconv
);
1086 gst_bin_add(GST_BIN(parser
->container
), flip
);
1087 gst_element_sync_state_with_parent(flip
);
1088 gst_bin_add(GST_BIN(parser
->container
), vconv2
);
1089 gst_element_sync_state_with_parent(vconv2
);
1091 gst_element_link(deinterlace
, vconv
);
1092 gst_element_link(vconv
, flip
);
1093 gst_element_link(flip
, vconv2
);
1095 stream
->post_sink
= gst_element_get_static_pad(deinterlace
, "sink");
1096 stream
->post_src
= gst_element_get_static_pad(vconv2
, "src");
1097 stream
->flip
= flip
;
1099 else if (!strcmp(name
, "audio/x-raw"))
1101 GstElement
*convert
;
1103 /* Currently our dsound can't handle 64-bit formats or all
1104 * surround-sound configurations. Native dsound can't always handle
1105 * 64-bit formats either. Add an audioconvert to allow changing bit
1106 * depth and channel count. */
1107 if (!(convert
= gst_element_factory_make("audioconvert", NULL
)))
1109 fprintf(stderr
, "winegstreamer: failed to create audioconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
1110 8 * (int)sizeof(void *));
1114 gst_bin_add(GST_BIN(parser
->container
), convert
);
1115 gst_element_sync_state_with_parent(convert
);
1117 stream
->post_sink
= gst_element_get_static_pad(convert
, "sink");
1118 stream
->post_src
= gst_element_get_static_pad(convert
, "src");
1121 if (stream
->post_sink
)
1123 if ((ret
= gst_pad_link(pad
, stream
->post_sink
)) < 0)
1125 GST_ERROR("Failed to link decodebin source pad to post-processing elements, error %s.",
1126 gst_pad_link_get_name(ret
));
1127 gst_object_unref(stream
->post_sink
);
1128 stream
->post_sink
= NULL
;
1132 if ((ret
= gst_pad_link(stream
->post_src
, stream
->my_sink
)) < 0)
1134 GST_ERROR("Failed to link post-processing elements to our sink pad, error %s.",
1135 gst_pad_link_get_name(ret
));
1136 gst_object_unref(stream
->post_src
);
1137 stream
->post_src
= NULL
;
1138 gst_object_unref(stream
->post_sink
);
1139 stream
->post_sink
= NULL
;
1143 else if ((ret
= gst_pad_link(pad
, stream
->my_sink
)) < 0)
1145 GST_ERROR("Failed to link decodebin source pad to our sink pad, error %s.",
1146 gst_pad_link_get_name(ret
));
1150 gst_pad_set_active(stream
->my_sink
, 1);
1151 gst_object_ref(stream
->their_src
= pad
);
1153 gst_caps_unref(caps
);
1156 static void pad_removed_cb(GstElement
*element
, GstPad
*pad
, gpointer user
)
1158 struct wg_parser
*parser
= user
;
1162 GST_LOG("parser %p, element %p, pad %p.", parser
, element
, pad
);
1164 for (i
= 0; i
< parser
->stream_count
; ++i
)
1166 struct wg_parser_stream
*stream
= parser
->streams
[i
];
1168 if (stream
->their_src
== pad
)
1170 if (stream
->post_sink
)
1171 gst_pad_unlink(stream
->their_src
, stream
->post_sink
);
1173 gst_pad_unlink(stream
->their_src
, stream
->my_sink
);
1174 gst_object_unref(stream
->their_src
);
1175 stream
->their_src
= NULL
;
1180 name
= gst_pad_get_name(pad
);
1181 GST_WARNING("No pin matching pad \"%s\" found.", name
);
1185 static GstFlowReturn
src_getrange_cb(GstPad
*pad
, GstObject
*parent
,
1186 guint64 offset
, guint size
, GstBuffer
**buffer
)
1188 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1189 GstBuffer
*new_buffer
= NULL
;
1190 GstMapInfo map_info
;
1193 GST_LOG("pad %p, offset %" G_GINT64_MODIFIER
"u, length %u, buffer %p.", pad
, offset
, size
, *buffer
);
1195 if (offset
== GST_BUFFER_OFFSET_NONE
)
1196 offset
= parser
->next_pull_offset
;
1197 parser
->next_pull_offset
= offset
+ size
;
1198 if (offset
>= parser
->file_size
)
1199 return GST_FLOW_EOS
;
1200 if (offset
+ size
>= parser
->file_size
)
1201 size
= parser
->file_size
- offset
;
1204 *buffer
= new_buffer
= gst_buffer_new_and_alloc(size
);
1206 gst_buffer_map(*buffer
, &map_info
, GST_MAP_WRITE
);
1208 pthread_mutex_lock(&parser
->mutex
);
1210 assert(!parser
->read_request
.data
);
1211 parser
->read_request
.data
= map_info
.data
;
1212 parser
->read_request
.offset
= offset
;
1213 parser
->read_request
.size
= size
;
1214 parser
->read_request
.done
= false;
1215 pthread_cond_signal(&parser
->read_cond
);
1217 /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect
1218 * the upstream pin to flush if necessary. We should never be blocked on
1219 * read_thread() not running. */
1221 while (!parser
->read_request
.done
)
1222 pthread_cond_wait(&parser
->read_done_cond
, &parser
->mutex
);
1224 ret
= parser
->read_request
.ret
;
1226 pthread_mutex_unlock(&parser
->mutex
);
1228 gst_buffer_unmap(*buffer
, &map_info
);
1230 GST_LOG("Request returned %d.", ret
);
1232 if (!ret
&& new_buffer
)
1233 gst_buffer_unref(new_buffer
);
1235 return ret
? GST_FLOW_OK
: GST_FLOW_ERROR
;
1238 static gboolean
src_query_cb(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
1240 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1243 GST_LOG("parser %p, type %s.", parser
, GST_QUERY_TYPE_NAME(query
));
1245 switch (GST_QUERY_TYPE(query
))
1247 case GST_QUERY_DURATION
:
1248 gst_query_parse_duration(query
, &format
, NULL
);
1249 if (format
== GST_FORMAT_PERCENT
)
1251 gst_query_set_duration(query
, GST_FORMAT_PERCENT
, GST_FORMAT_PERCENT_MAX
);
1254 else if (format
== GST_FORMAT_BYTES
)
1256 gst_query_set_duration(query
, GST_FORMAT_BYTES
, parser
->file_size
);
1261 case GST_QUERY_SEEKING
:
1262 gst_query_parse_seeking (query
, &format
, NULL
, NULL
, NULL
);
1263 if (format
!= GST_FORMAT_BYTES
)
1265 GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format
));
1268 gst_query_set_seeking(query
, GST_FORMAT_BYTES
, 1, 0, parser
->file_size
);
1271 case GST_QUERY_SCHEDULING
:
1272 gst_query_set_scheduling(query
, GST_SCHEDULING_FLAG_SEEKABLE
, 1, -1, 0);
1273 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PUSH
);
1274 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PULL
);
1278 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query
));
1283 static void *push_data(void *arg
)
1285 struct wg_parser
*parser
= arg
;
1289 GST_DEBUG("Starting push thread.");
1291 if (!(buffer
= gst_buffer_new_allocate(NULL
, 16384, NULL
)))
1293 GST_ERROR("Failed to allocate memory.");
1297 max_size
= parser
->stop_offset
? parser
->stop_offset
: parser
->file_size
;
1304 if (parser
->next_offset
>= max_size
)
1306 size
= min(16384, max_size
- parser
->next_offset
);
1308 if ((ret
= src_getrange_cb(parser
->my_src
, NULL
, parser
->next_offset
, size
, &buffer
)) < 0)
1310 GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret
));
1314 parser
->next_offset
+= size
;
1316 buffer
->duration
= buffer
->pts
= -1;
1317 if ((ret
= gst_pad_push(parser
->my_src
, buffer
)) < 0)
1319 GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret
));
1324 gst_buffer_unref(buffer
);
1326 gst_pad_push_event(parser
->my_src
, gst_event_new_eos());
1328 GST_DEBUG("Stopping push thread.");
1333 static gboolean
activate_push(GstPad
*pad
, gboolean activate
)
1335 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1339 if (parser
->push_thread
)
1341 pthread_join(parser
->push_thread
, NULL
);
1342 parser
->push_thread
= 0;
1345 else if (!parser
->push_thread
)
1349 if ((ret
= pthread_create(&parser
->push_thread
, NULL
, push_data
, parser
)))
1351 GST_ERROR("Failed to create push thread: %s", strerror(errno
));
1352 parser
->push_thread
= 0;
1359 static gboolean
src_activate_mode_cb(GstPad
*pad
, GstObject
*parent
, GstPadMode mode
, gboolean activate
)
1361 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1363 GST_DEBUG("%s source pad for parser %p in %s mode.",
1364 activate
? "Activating" : "Deactivating", parser
, gst_pad_mode_get_name(mode
));
1368 case GST_PAD_MODE_PULL
:
1370 case GST_PAD_MODE_PUSH
:
1371 return activate_push(pad
, activate
);
1372 case GST_PAD_MODE_NONE
:
1378 static GstBusSyncReply
bus_handler_cb(GstBus
*bus
, GstMessage
*msg
, gpointer user
)
1380 struct wg_parser
*parser
= user
;
1381 gchar
*dbg_info
= NULL
;
1384 GST_DEBUG("parser %p, message type %s.", parser
, GST_MESSAGE_TYPE_NAME(msg
));
1388 case GST_MESSAGE_ERROR
:
1389 gst_message_parse_error(msg
, &err
, &dbg_info
);
1390 fprintf(stderr
, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg
->src
), err
->message
);
1391 fprintf(stderr
, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg
->src
), dbg_info
);
1394 pthread_mutex_lock(&parser
->mutex
);
1395 parser
->error
= true;
1396 pthread_mutex_unlock(&parser
->mutex
);
1397 pthread_cond_signal(&parser
->init_cond
);
1400 case GST_MESSAGE_WARNING
:
1401 gst_message_parse_warning(msg
, &err
, &dbg_info
);
1402 fprintf(stderr
, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg
->src
), err
->message
);
1403 fprintf(stderr
, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg
->src
), dbg_info
);
1408 case GST_MESSAGE_DURATION_CHANGED
:
1409 pthread_mutex_lock(&parser
->mutex
);
1410 parser
->has_duration
= true;
1411 pthread_mutex_unlock(&parser
->mutex
);
1412 pthread_cond_signal(&parser
->init_cond
);
1418 gst_message_unref(msg
);
1419 return GST_BUS_DROP
;
1422 static gboolean
src_perform_seek(struct wg_parser
*parser
, GstEvent
*event
)
1424 BOOL thread
= !!parser
->push_thread
;
1425 GstSeekType cur_type
, stop_type
;
1426 GstFormat seek_format
;
1427 GstEvent
*flush_event
;
1433 gst_event_parse_seek(event
, &rate
, &seek_format
, &flags
,
1434 &cur_type
, &cur
, &stop_type
, &stop
);
1436 if (seek_format
!= GST_FORMAT_BYTES
)
1438 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format
));
1442 seqnum
= gst_event_get_seqnum(event
);
1444 /* send flush start */
1445 if (flags
& GST_SEEK_FLAG_FLUSH
)
1447 flush_event
= gst_event_new_flush_start();
1448 gst_event_set_seqnum(flush_event
, seqnum
);
1449 gst_pad_push_event(parser
->my_src
, flush_event
);
1451 gst_pad_set_active(parser
->my_src
, 1);
1454 parser
->next_offset
= parser
->start_offset
= cur
;
1456 /* and prepare to continue streaming */
1457 if (flags
& GST_SEEK_FLAG_FLUSH
)
1459 flush_event
= gst_event_new_flush_stop(TRUE
);
1460 gst_event_set_seqnum(flush_event
, seqnum
);
1461 gst_pad_push_event(parser
->my_src
, flush_event
);
1463 gst_pad_set_active(parser
->my_src
, 1);
1469 static gboolean
src_event_cb(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
1471 struct wg_parser
*parser
= gst_pad_get_element_private(pad
);
1472 gboolean ret
= TRUE
;
1474 GST_LOG("parser %p, type \"%s\".", parser
, GST_EVENT_TYPE_NAME(event
));
1476 switch (event
->type
)
1478 case GST_EVENT_SEEK
:
1479 ret
= src_perform_seek(parser
, event
);
1482 case GST_EVENT_FLUSH_START
:
1483 case GST_EVENT_FLUSH_STOP
:
1485 case GST_EVENT_RECONFIGURE
:
1489 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
1493 gst_event_unref(event
);
1497 static LONGLONG
query_duration(GstPad
*pad
)
1499 gint64 duration
, byte_length
;
1501 if (gst_pad_query_duration(pad
, GST_FORMAT_TIME
, &duration
))
1502 return duration
/ 100;
1504 WARN("Failed to query time duration; trying to convert from byte length.\n");
1506 /* To accurately get a duration for the stream, we want to only consider the
1507 * length of that stream. Hence, query for the pad duration, instead of
1508 * using the file duration. */
1509 if (gst_pad_query_duration(pad
, GST_FORMAT_BYTES
, &byte_length
)
1510 && gst_pad_query_convert(pad
, GST_FORMAT_BYTES
, byte_length
, GST_FORMAT_TIME
, &duration
))
1511 return duration
/ 100;
1513 ERR("Failed to query duration.\n");
1517 static HRESULT CDECL
wg_parser_connect(struct wg_parser
*parser
, uint64_t file_size
)
1519 GstStaticPadTemplate src_template
= GST_STATIC_PAD_TEMPLATE("quartz_src",
1520 GST_PAD_SRC
, GST_PAD_ALWAYS
, GST_STATIC_CAPS_ANY
);
1523 parser
->file_size
= file_size
;
1524 parser
->sink_connected
= true;
1528 parser
->bus
= gst_bus_new();
1529 gst_bus_set_sync_handler(parser
->bus
, bus_handler_cb
, parser
, NULL
);
1532 parser
->container
= gst_bin_new(NULL
);
1533 gst_element_set_bus(parser
->container
, parser
->bus
);
1535 parser
->my_src
= gst_pad_new_from_static_template(&src_template
, "quartz-src");
1536 gst_pad_set_getrange_function(parser
->my_src
, src_getrange_cb
);
1537 gst_pad_set_query_function(parser
->my_src
, src_query_cb
);
1538 gst_pad_set_activatemode_function(parser
->my_src
, src_activate_mode_cb
);
1539 gst_pad_set_event_function(parser
->my_src
, src_event_cb
);
1540 gst_pad_set_element_private(parser
->my_src
, parser
);
1542 parser
->start_offset
= parser
->next_offset
= parser
->stop_offset
= 0;
1543 parser
->next_pull_offset
= 0;
1545 if (!parser
->init_gst(parser
))
1548 pthread_mutex_lock(&parser
->mutex
);
1550 for (i
= 0; i
< parser
->stream_count
; ++i
)
1552 struct wg_parser_stream
*stream
= parser
->streams
[i
];
1554 stream
->duration
= query_duration(stream
->their_src
);
1555 while (!stream
->has_caps
&& !parser
->error
)
1556 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1559 pthread_mutex_unlock(&parser
->mutex
);
1564 pthread_mutex_unlock(&parser
->mutex
);
1566 parser
->next_offset
= 0;
1570 static void free_stream(struct wg_parser_stream
*stream
)
1572 if (stream
->their_src
)
1574 if (stream
->post_sink
)
1576 gst_pad_unlink(stream
->their_src
, stream
->post_sink
);
1577 gst_pad_unlink(stream
->post_src
, stream
->my_sink
);
1578 gst_object_unref(stream
->post_src
);
1579 gst_object_unref(stream
->post_sink
);
1580 stream
->post_src
= stream
->post_sink
= NULL
;
1583 gst_pad_unlink(stream
->their_src
, stream
->my_sink
);
1584 gst_object_unref(stream
->their_src
);
1586 gst_object_unref(stream
->my_sink
);
1588 pthread_cond_destroy(&stream
->event_cond
);
1589 pthread_cond_destroy(&stream
->event_empty_cond
);
1594 static void CDECL
wg_parser_disconnect(struct wg_parser
*parser
)
1598 /* Unblock all of our streams. */
1599 pthread_mutex_lock(&parser
->mutex
);
1600 for (i
= 0; i
< parser
->stream_count
; ++i
)
1602 parser
->streams
[i
]->flushing
= true;
1603 pthread_cond_signal(&parser
->streams
[i
]->event_empty_cond
);
1605 pthread_mutex_unlock(&parser
->mutex
);
1607 gst_element_set_state(parser
->container
, GST_STATE_NULL
);
1608 gst_pad_unlink(parser
->my_src
, parser
->their_sink
);
1609 gst_object_unref(parser
->my_src
);
1610 gst_object_unref(parser
->their_sink
);
1611 parser
->my_src
= parser
->their_sink
= NULL
;
1613 pthread_mutex_lock(&parser
->mutex
);
1614 parser
->sink_connected
= false;
1615 pthread_mutex_unlock(&parser
->mutex
);
1616 pthread_cond_signal(&parser
->read_cond
);
1618 for (i
= 0; i
< parser
->stream_count
; ++i
)
1619 free_stream(parser
->streams
[i
]);
1621 parser
->stream_count
= 0;
1622 free(parser
->streams
);
1623 parser
->streams
= NULL
;
1625 gst_element_set_bus(parser
->container
, NULL
);
1626 gst_object_unref(parser
->container
);
1627 parser
->container
= NULL
;
1630 static BOOL
decodebin_parser_init_gst(struct wg_parser
*parser
)
1632 GstElement
*element
= gst_element_factory_make("decodebin", NULL
);
1637 ERR("Failed to create decodebin; are %u-bit GStreamer \"base\" plugins installed?\n",
1638 8 * (int)sizeof(void*));
1642 gst_bin_add(GST_BIN(parser
->container
), element
);
1643 parser
->decodebin
= element
;
1645 g_signal_connect(element
, "pad-added", G_CALLBACK(pad_added_cb
), parser
);
1646 g_signal_connect(element
, "pad-removed", G_CALLBACK(pad_removed_cb
), parser
);
1647 g_signal_connect(element
, "autoplug-select", G_CALLBACK(autoplug_select_cb
), parser
);
1648 g_signal_connect(element
, "no-more-pads", G_CALLBACK(no_more_pads_cb
), parser
);
1650 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1652 pthread_mutex_lock(&parser
->mutex
);
1653 parser
->no_more_pads
= parser
->error
= false;
1654 pthread_mutex_unlock(&parser
->mutex
);
1656 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1658 ERR("Failed to link pads, error %d.\n", ret
);
1662 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
1663 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
1664 if (ret
== GST_STATE_CHANGE_FAILURE
)
1666 ERR("Failed to play stream.\n");
1670 pthread_mutex_lock(&parser
->mutex
);
1671 while (!parser
->no_more_pads
&& !parser
->error
)
1672 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1675 pthread_mutex_unlock(&parser
->mutex
);
1678 pthread_mutex_unlock(&parser
->mutex
);
1683 static BOOL
avi_parser_init_gst(struct wg_parser
*parser
)
1685 GstElement
*element
= gst_element_factory_make("avidemux", NULL
);
1690 ERR("Failed to create avidemux; are %u-bit GStreamer \"good\" plugins installed?\n",
1691 8 * (int)sizeof(void*));
1695 gst_bin_add(GST_BIN(parser
->container
), element
);
1697 g_signal_connect(element
, "pad-added", G_CALLBACK(pad_added_cb
), parser
);
1698 g_signal_connect(element
, "pad-removed", G_CALLBACK(pad_removed_cb
), parser
);
1699 g_signal_connect(element
, "no-more-pads", G_CALLBACK(no_more_pads_cb
), parser
);
1701 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1703 pthread_mutex_lock(&parser
->mutex
);
1704 parser
->no_more_pads
= parser
->error
= false;
1705 pthread_mutex_unlock(&parser
->mutex
);
1707 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1709 ERR("Failed to link pads, error %d.\n", ret
);
1713 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
1714 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
1715 if (ret
== GST_STATE_CHANGE_FAILURE
)
1717 ERR("Failed to play stream.\n");
1721 pthread_mutex_lock(&parser
->mutex
);
1722 while (!parser
->no_more_pads
&& !parser
->error
)
1723 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1726 pthread_mutex_unlock(&parser
->mutex
);
1729 pthread_mutex_unlock(&parser
->mutex
);
1734 static BOOL
mpeg_audio_parser_init_gst(struct wg_parser
*parser
)
1736 struct wg_parser_stream
*stream
;
1737 GstElement
*element
;
1740 if (!(element
= gst_element_factory_make("mpegaudioparse", NULL
)))
1742 ERR("Failed to create mpegaudioparse; are %u-bit GStreamer \"good\" plugins installed?\n",
1743 8 * (int)sizeof(void*));
1747 gst_bin_add(GST_BIN(parser
->container
), element
);
1749 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1750 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1752 ERR("Failed to link sink pads, error %d.\n", ret
);
1756 if (!(stream
= create_stream(parser
)))
1759 gst_object_ref(stream
->their_src
= gst_element_get_static_pad(element
, "src"));
1760 if ((ret
= gst_pad_link(stream
->their_src
, stream
->my_sink
)) < 0)
1762 ERR("Failed to link source pads, error %d.\n", ret
);
1766 gst_pad_set_active(stream
->my_sink
, 1);
1767 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
1768 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
1769 if (ret
== GST_STATE_CHANGE_FAILURE
)
1771 ERR("Failed to play stream.\n");
1775 pthread_mutex_lock(&parser
->mutex
);
1776 while (!parser
->has_duration
&& !parser
->error
&& !stream
->eos
)
1777 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1780 pthread_mutex_unlock(&parser
->mutex
);
1783 pthread_mutex_unlock(&parser
->mutex
);
1787 static BOOL
wave_parser_init_gst(struct wg_parser
*parser
)
1789 struct wg_parser_stream
*stream
;
1790 GstElement
*element
;
1793 if (!(element
= gst_element_factory_make("wavparse", NULL
)))
1795 ERR("Failed to create wavparse; are %u-bit GStreamer \"good\" plugins installed?\n",
1796 8 * (int)sizeof(void*));
1800 gst_bin_add(GST_BIN(parser
->container
), element
);
1802 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1803 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1805 ERR("Failed to link sink pads, error %d.\n", ret
);
1809 if (!(stream
= create_stream(parser
)))
1812 stream
->their_src
= gst_element_get_static_pad(element
, "src");
1813 gst_object_ref(stream
->their_src
);
1814 if ((ret
= gst_pad_link(stream
->their_src
, stream
->my_sink
)) < 0)
1816 ERR("Failed to link source pads, error %d.\n", ret
);
1820 gst_pad_set_active(stream
->my_sink
, 1);
1821 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
1822 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
1823 if (ret
== GST_STATE_CHANGE_FAILURE
)
1825 ERR("Failed to play stream.\n");
1832 static struct wg_parser
*wg_parser_create(void)
1834 struct wg_parser
*parser
;
1836 if (!(parser
= calloc(1, sizeof(*parser
))))
1839 pthread_mutex_init(&parser
->mutex
, NULL
);
1840 pthread_cond_init(&parser
->init_cond
, NULL
);
1841 pthread_cond_init(&parser
->read_cond
, NULL
);
1842 pthread_cond_init(&parser
->read_done_cond
, NULL
);
1843 parser
->flushing
= true;
1845 TRACE("Created winegstreamer parser %p.\n", parser
);
1849 static struct wg_parser
* CDECL
wg_decodebin_parser_create(void)
1851 struct wg_parser
*parser
;
1853 if ((parser
= wg_parser_create()))
1854 parser
->init_gst
= decodebin_parser_init_gst
;
1858 static struct wg_parser
* CDECL
wg_avi_parser_create(void)
1860 struct wg_parser
*parser
;
1862 if ((parser
= wg_parser_create()))
1863 parser
->init_gst
= avi_parser_init_gst
;
1867 static struct wg_parser
* CDECL
wg_mpeg_audio_parser_create(void)
1869 struct wg_parser
*parser
;
1871 if ((parser
= wg_parser_create()))
1872 parser
->init_gst
= mpeg_audio_parser_init_gst
;
1876 static struct wg_parser
* CDECL
wg_wave_parser_create(void)
1878 struct wg_parser
*parser
;
1880 if ((parser
= wg_parser_create()))
1881 parser
->init_gst
= wave_parser_init_gst
;
1885 static void CDECL
wg_parser_destroy(struct wg_parser
*parser
)
1889 gst_bus_set_sync_handler(parser
->bus
, NULL
, NULL
, NULL
);
1890 gst_object_unref(parser
->bus
);
1893 pthread_mutex_destroy(&parser
->mutex
);
1894 pthread_cond_destroy(&parser
->init_cond
);
1895 pthread_cond_destroy(&parser
->read_cond
);
1896 pthread_cond_destroy(&parser
->read_done_cond
);
1901 static const struct unix_funcs funcs
=
1903 wg_decodebin_parser_create
,
1904 wg_avi_parser_create
,
1905 wg_mpeg_audio_parser_create
,
1906 wg_wave_parser_create
,
1910 wg_parser_disconnect
,
1912 wg_parser_begin_flush
,
1913 wg_parser_end_flush
,
1915 wg_parser_get_read_request
,
1916 wg_parser_complete_read_request
,
1918 wg_parser_set_unlimited_buffering
,
1920 wg_parser_get_stream_count
,
1921 wg_parser_get_stream
,
1923 wg_parser_stream_get_preferred_format
,
1924 wg_parser_stream_enable
,
1925 wg_parser_stream_disable
,
1927 wg_parser_stream_get_event
,
1928 wg_parser_stream_copy_buffer
,
1929 wg_parser_stream_release_buffer
,
1930 wg_parser_stream_notify_qos
,
1932 wg_parser_stream_get_duration
,
1933 wg_parser_stream_seek
,
1936 NTSTATUS CDECL
__wine_init_unix_lib(HMODULE module
, DWORD reason
, const void *ptr_in
, void *ptr_out
)
1938 if (reason
== DLL_PROCESS_ATTACH
)
1940 char arg0
[] = "wine";
1941 char arg1
[] = "--gst-disable-registry-fork";
1942 char *args
[] = {arg0
, arg1
, NULL
};
1943 int argc
= ARRAY_SIZE(args
) - 1;
1947 if (!gst_init_check(&argc
, &argv
, &err
))
1949 ERR("Failed to initialize GStreamer: %s\n", debugstr_a(err
->message
));
1951 return STATUS_UNSUCCESSFUL
;
1953 TRACE("GStreamer library version %s; wine built with %d.%d.%d.\n",
1954 gst_version_string(), GST_VERSION_MAJOR
, GST_VERSION_MINOR
, GST_VERSION_MICRO
);
1956 GST_DEBUG_CATEGORY_INIT(wine
, "WINE", GST_DEBUG_FG_RED
, "Wine GStreamer support");
1958 *(const struct unix_funcs
**)ptr_out
= &funcs
;
1960 return STATUS_SUCCESS
;