winegstreamer: Avoid accessing the DirectShow peer from GStreamer callbacks.
[wine.git] / dlls / winegstreamer / gstdemux.c
blobe47b4a303882a477e9a396f968d4b1bd87c38cc2
1 /*
2 * GStreamer splitter + decoder, adapted from parser.c
4 * Copyright 2010 Maarten Lankhorst for CodeWeavers
5 * Copyright 2010 Aric Stewart for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "gst_private.h"
24 #include "gst_guids.h"
25 #include "gst_cbs.h"
27 #include "vfwmsgs.h"
28 #include "amvideo.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
33 #include <assert.h>
35 #include "dvdmedia.h"
36 #include "mmreg.h"
37 #include "ks.h"
38 #include "initguid.h"
39 #include "wmcodecdsp.h"
40 #include "ksmedia.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(gstreamer);
44 GST_DEBUG_CATEGORY_STATIC(wine);
45 #define GST_CAT_DEFAULT wine
47 static const GUID MEDIASUBTYPE_CVID = {mmioFOURCC('c','v','i','d'), 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
49 struct wg_parser
51 GstElement *container;
52 GstBus *bus;
53 GstPad *my_src, *their_sink;
55 guint64 file_size, start_offset, next_offset, stop_offset;
57 pthread_t push_thread;
59 pthread_mutex_t mutex;
61 pthread_cond_t init_cond;
62 bool no_more_pads, has_duration, error;
64 pthread_cond_t read_cond, read_done_cond;
65 struct
67 GstBuffer *buffer;
68 uint64_t offset;
69 uint32_t size;
70 bool done;
71 GstFlowReturn ret;
72 } read_request;
74 bool flushing, sink_connected;
77 enum wg_parser_event_type
79 WG_PARSER_EVENT_NONE = 0,
80 WG_PARSER_EVENT_BUFFER,
81 WG_PARSER_EVENT_EOS,
82 WG_PARSER_EVENT_SEGMENT,
85 struct wg_parser_event
87 enum wg_parser_event_type type;
88 union
90 GstBuffer *buffer;
91 struct
93 uint64_t position, stop;
94 double rate;
95 } segment;
96 } u;
99 struct wg_parser_stream
101 GstPad *their_src, *post_sink, *post_src, *my_sink;
102 GstElement *flip;
103 GstSegment *segment;
104 GstCaps *caps;
106 pthread_cond_t event_cond, event_empty_cond;
107 struct wg_parser_event event;
109 bool flushing, eos, enabled;
112 struct parser
114 struct strmbase_filter filter;
115 IAMStreamSelect IAMStreamSelect_iface;
117 struct strmbase_sink sink;
118 IAsyncReader *reader;
120 struct parser_source **sources;
121 unsigned int source_count;
122 BOOL enum_sink_first;
124 LONGLONG file_size;
126 struct wg_parser *wg_parser;
128 /* FIXME: It would be nice to avoid duplicating these with strmbase.
129 * However, synchronization is tricky; we need access to be protected by a
130 * separate lock. */
131 bool streaming, sink_connected;
133 uint64_t next_pull_offset;
135 HANDLE read_thread;
137 BOOL (*init_gst)(struct parser *filter);
138 HRESULT (*source_query_accept)(struct parser_source *pin, const AM_MEDIA_TYPE *mt);
139 HRESULT (*source_get_media_type)(struct parser_source *pin, unsigned int index, AM_MEDIA_TYPE *mt);
142 struct parser_source
144 struct strmbase_source pin;
145 IQualityControl IQualityControl_iface;
147 struct wg_parser_stream *wg_stream;
149 SourceSeeking seek;
151 CRITICAL_SECTION flushing_cs;
152 HANDLE thread;
155 static inline struct parser *impl_from_strmbase_filter(struct strmbase_filter *iface)
157 return CONTAINING_RECORD(iface, struct parser, filter);
160 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
161 static const IMediaSeekingVtbl GST_Seeking_Vtbl;
162 static const IQualityControlVtbl GSTOutPin_QualityControl_Vtbl;
164 static struct parser_source *create_pin(struct parser *filter, const WCHAR *name);
165 static HRESULT GST_RemoveOutputPins(struct parser *This);
166 static HRESULT WINAPI GST_ChangeCurrent(IMediaSeeking *iface);
167 static HRESULT WINAPI GST_ChangeStop(IMediaSeeking *iface);
168 static HRESULT WINAPI GST_ChangeRate(IMediaSeeking *iface);
170 static gboolean amt_from_gst_audio_info(const GstAudioInfo *info, AM_MEDIA_TYPE *amt)
172 WAVEFORMATEXTENSIBLE *wfe;
173 WAVEFORMATEX *wfx;
174 gint32 depth, bpp;
176 wfe = CoTaskMemAlloc(sizeof(*wfe));
177 wfx = (WAVEFORMATEX*)wfe;
178 amt->majortype = MEDIATYPE_Audio;
179 amt->subtype = MEDIASUBTYPE_PCM;
180 amt->formattype = FORMAT_WaveFormatEx;
181 amt->pbFormat = (BYTE*)wfe;
182 amt->cbFormat = sizeof(*wfe);
183 amt->bFixedSizeSamples = TRUE;
184 amt->bTemporalCompression = FALSE;
185 amt->pUnk = NULL;
187 wfx->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
189 wfx->nChannels = info->channels;
190 wfx->nSamplesPerSec = info->rate;
191 depth = GST_AUDIO_INFO_WIDTH(info);
192 bpp = GST_AUDIO_INFO_DEPTH(info);
194 if (!depth || depth > 32 || depth % 8)
195 depth = bpp;
196 else if (!bpp)
197 bpp = depth;
198 wfe->Samples.wValidBitsPerSample = depth;
199 wfx->wBitsPerSample = bpp;
200 wfx->cbSize = sizeof(*wfe)-sizeof(*wfx);
201 switch (wfx->nChannels) {
202 case 1: wfe->dwChannelMask = KSAUDIO_SPEAKER_MONO; break;
203 case 2: wfe->dwChannelMask = KSAUDIO_SPEAKER_STEREO; break;
204 case 4: wfe->dwChannelMask = KSAUDIO_SPEAKER_SURROUND; break;
205 case 5: wfe->dwChannelMask = (KSAUDIO_SPEAKER_5POINT1 & ~SPEAKER_LOW_FREQUENCY); break;
206 case 6: wfe->dwChannelMask = KSAUDIO_SPEAKER_5POINT1; break;
207 case 8: wfe->dwChannelMask = KSAUDIO_SPEAKER_7POINT1; break;
208 default:
209 wfe->dwChannelMask = 0;
211 if (GST_AUDIO_INFO_IS_FLOAT(info))
213 amt->subtype = MEDIASUBTYPE_IEEE_FLOAT;
214 wfe->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
215 } else {
216 wfe->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
217 if (wfx->nChannels <= 2 && bpp <= 16 && depth == bpp) {
218 wfx->wFormatTag = WAVE_FORMAT_PCM;
219 wfx->cbSize = 0;
220 amt->cbFormat = sizeof(WAVEFORMATEX);
223 amt->lSampleSize = wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample/8;
224 wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
225 return TRUE;
228 static gboolean amt_from_gst_video_info(const GstVideoInfo *info, AM_MEDIA_TYPE *amt)
230 VIDEOINFO *vih;
231 BITMAPINFOHEADER *bih;
232 gint32 width, height;
234 width = GST_VIDEO_INFO_WIDTH(info);
235 height = GST_VIDEO_INFO_HEIGHT(info);
237 vih = CoTaskMemAlloc(sizeof(*vih));
238 bih = &vih->bmiHeader;
240 amt->formattype = FORMAT_VideoInfo;
241 amt->pbFormat = (BYTE*)vih;
242 amt->cbFormat = sizeof(VIDEOINFOHEADER);
243 amt->bFixedSizeSamples = FALSE;
244 amt->bTemporalCompression = TRUE;
245 amt->lSampleSize = 1;
246 amt->pUnk = NULL;
247 ZeroMemory(vih, sizeof(*vih));
248 amt->majortype = MEDIATYPE_Video;
250 if (GST_VIDEO_INFO_IS_RGB(info))
252 bih->biCompression = BI_RGB;
253 switch (GST_VIDEO_INFO_FORMAT(info))
255 case GST_VIDEO_FORMAT_BGRA:
256 amt->subtype = MEDIASUBTYPE_ARGB32;
257 bih->biBitCount = 32;
258 break;
259 case GST_VIDEO_FORMAT_BGRx:
260 amt->subtype = MEDIASUBTYPE_RGB32;
261 bih->biBitCount = 32;
262 break;
263 case GST_VIDEO_FORMAT_BGR:
264 amt->subtype = MEDIASUBTYPE_RGB24;
265 bih->biBitCount = 24;
266 break;
267 case GST_VIDEO_FORMAT_RGB16:
268 amt->subtype = MEDIASUBTYPE_RGB565;
269 amt->cbFormat = offsetof(VIDEOINFO, u.dwBitMasks[3]);
270 vih->u.dwBitMasks[iRED] = 0xf800;
271 vih->u.dwBitMasks[iGREEN] = 0x07e0;
272 vih->u.dwBitMasks[iBLUE] = 0x001f;
273 bih->biBitCount = 16;
274 bih->biCompression = BI_BITFIELDS;
275 break;
276 case GST_VIDEO_FORMAT_RGB15:
277 amt->subtype = MEDIASUBTYPE_RGB555;
278 bih->biBitCount = 16;
279 break;
280 default:
281 WARN("Cannot convert %s to a DirectShow type.\n", GST_VIDEO_INFO_NAME(info));
282 CoTaskMemFree(vih);
283 return FALSE;
285 } else {
286 amt->subtype = MEDIATYPE_Video;
287 if (!(amt->subtype.Data1 = gst_video_format_to_fourcc(GST_VIDEO_INFO_FORMAT(info))))
289 CoTaskMemFree(vih);
290 return FALSE;
292 switch (amt->subtype.Data1) {
293 case mmioFOURCC('I','4','2','0'):
294 case mmioFOURCC('Y','V','1','2'):
295 case mmioFOURCC('N','V','1','2'):
296 case mmioFOURCC('N','V','2','1'):
297 bih->biBitCount = 12; break;
298 case mmioFOURCC('Y','U','Y','2'):
299 case mmioFOURCC('Y','V','Y','U'):
300 case mmioFOURCC('U','Y','V','Y'):
301 bih->biBitCount = 16; break;
303 bih->biCompression = amt->subtype.Data1;
305 bih->biSizeImage = GST_VIDEO_INFO_SIZE(info);
306 if ((vih->AvgTimePerFrame = (REFERENCE_TIME)MulDiv(10000000,
307 GST_VIDEO_INFO_FPS_D(info), GST_VIDEO_INFO_FPS_N(info))) == -1)
308 vih->AvgTimePerFrame = 0; /* zero division or integer overflow */
309 bih->biSize = sizeof(*bih);
310 bih->biWidth = width;
311 bih->biHeight = height;
312 bih->biPlanes = 1;
313 return TRUE;
316 static gboolean amt_from_gst_caps_audio_mpeg(const GstCaps *caps, AM_MEDIA_TYPE *mt)
318 GstStructure *structure = gst_caps_get_structure(caps, 0);
319 gint layer, channels, rate;
321 mt->majortype = MEDIATYPE_Audio;
322 mt->subtype = MEDIASUBTYPE_MPEG1AudioPayload;
323 mt->bFixedSizeSamples = FALSE;
324 mt->bTemporalCompression = FALSE;
325 mt->lSampleSize = 0;
326 mt->formattype = FORMAT_WaveFormatEx;
327 mt->pUnk = NULL;
329 if (!gst_structure_get_int(structure, "layer", &layer))
331 WARN("Missing 'layer' value.\n");
332 return FALSE;
334 if (!gst_structure_get_int(structure, "channels", &channels))
336 WARN("Missing 'channels' value.\n");
337 return FALSE;
339 if (!gst_structure_get_int(structure, "rate", &rate))
341 WARN("Missing 'rate' value.\n");
342 return FALSE;
345 if (layer == 3)
347 MPEGLAYER3WAVEFORMAT *wfx = CoTaskMemAlloc(sizeof(*wfx));
348 memset(wfx, 0, sizeof(*wfx));
350 mt->subtype.Data1 = WAVE_FORMAT_MPEGLAYER3;
351 mt->cbFormat = sizeof(*wfx);
352 mt->pbFormat = (BYTE *)wfx;
353 wfx->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3;
354 wfx->wfx.nChannels = channels;
355 wfx->wfx.nSamplesPerSec = rate;
356 /* FIXME: We can't get most of the MPEG data from the caps. We may have
357 * to manually parse the header. */
358 wfx->wfx.cbSize = sizeof(*wfx) - sizeof(WAVEFORMATEX);
359 wfx->wID = MPEGLAYER3_ID_MPEG;
360 wfx->fdwFlags = MPEGLAYER3_FLAG_PADDING_ON;
361 wfx->nFramesPerBlock = 1;
362 wfx->nCodecDelay = 1393;
364 else
366 MPEG1WAVEFORMAT *wfx = CoTaskMemAlloc(sizeof(*wfx));
367 memset(wfx, 0, sizeof(*wfx));
369 mt->subtype.Data1 = WAVE_FORMAT_MPEG;
370 mt->cbFormat = sizeof(*wfx);
371 mt->pbFormat = (BYTE *)wfx;
372 wfx->wfx.wFormatTag = WAVE_FORMAT_MPEG;
373 wfx->wfx.nChannels = channels;
374 wfx->wfx.nSamplesPerSec = rate;
375 wfx->wfx.cbSize = sizeof(*wfx) - sizeof(WAVEFORMATEX);
376 wfx->fwHeadLayer = layer;
379 return TRUE;
382 static gboolean amt_from_gst_caps(const GstCaps *caps, AM_MEDIA_TYPE *mt)
384 const char *type = gst_structure_get_name(gst_caps_get_structure(caps, 0));
385 GstStructure *structure = gst_caps_get_structure(caps, 0);
387 memset(mt, 0, sizeof(AM_MEDIA_TYPE));
389 if (!strcmp(type, "audio/x-raw"))
391 GstAudioInfo info;
393 if (!(gst_audio_info_from_caps(&info, caps)))
394 return FALSE;
395 return amt_from_gst_audio_info(&info, mt);
397 else if (!strcmp(type, "video/x-raw"))
399 GstVideoInfo info;
401 if (!gst_video_info_from_caps(&info, caps))
402 return FALSE;
403 return amt_from_gst_video_info(&info, mt);
405 else if (!strcmp(type, "audio/mpeg"))
406 return amt_from_gst_caps_audio_mpeg(caps, mt);
407 else if (!strcmp(type, "video/x-cinepak"))
409 VIDEOINFOHEADER *vih;
410 gint i;
412 mt->majortype = MEDIATYPE_Video;
413 mt->subtype = MEDIASUBTYPE_CVID;
414 mt->bTemporalCompression = TRUE;
415 mt->lSampleSize = 1;
416 mt->formattype = FORMAT_VideoInfo;
417 if (!(vih = CoTaskMemAlloc(sizeof(VIDEOINFOHEADER))))
418 return FALSE;
419 mt->cbFormat = sizeof(VIDEOINFOHEADER);
420 mt->pbFormat = (BYTE *)vih;
422 memset(vih, 0, sizeof(VIDEOINFOHEADER));
423 vih->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
424 if (gst_structure_get_int(structure, "width", &i))
425 vih->bmiHeader.biWidth = i;
426 if (gst_structure_get_int(structure, "height", &i))
427 vih->bmiHeader.biHeight = i;
428 vih->bmiHeader.biPlanes = 1;
429 /* Both ffmpeg's encoder and a Cinepak file seen in the wild report
430 * 24 bpp. ffmpeg sets biSizeImage as below; others may be smaller, but
431 * as long as every sample fits into our allocator, we're fine. */
432 vih->bmiHeader.biBitCount = 24;
433 vih->bmiHeader.biCompression = mmioFOURCC('c','v','i','d');
434 vih->bmiHeader.biSizeImage = vih->bmiHeader.biWidth
435 * vih->bmiHeader.biHeight * vih->bmiHeader.biBitCount / 8;
436 return TRUE;
438 else
440 FIXME("Unhandled type %s.\n", debugstr_a(type));
441 return FALSE;
445 static GstCaps *amt_to_gst_caps_video(const AM_MEDIA_TYPE *mt)
447 static const struct
449 const GUID *subtype;
450 GstVideoFormat format;
452 format_map[] =
454 {&MEDIASUBTYPE_ARGB32, GST_VIDEO_FORMAT_BGRA},
455 {&MEDIASUBTYPE_RGB32, GST_VIDEO_FORMAT_BGRx},
456 {&MEDIASUBTYPE_RGB24, GST_VIDEO_FORMAT_BGR},
457 {&MEDIASUBTYPE_RGB565, GST_VIDEO_FORMAT_RGB16},
458 {&MEDIASUBTYPE_RGB555, GST_VIDEO_FORMAT_RGB15},
461 const VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)mt->pbFormat;
462 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
463 GstVideoInfo info;
464 unsigned int i;
465 GstCaps *caps;
467 if (!IsEqualGUID(&mt->formattype, &FORMAT_VideoInfo)
468 || mt->cbFormat < sizeof(VIDEOINFOHEADER) || !mt->pbFormat)
469 return NULL;
471 for (i = 0; i < ARRAY_SIZE(format_map); ++i)
473 if (IsEqualGUID(&mt->subtype, format_map[i].subtype))
475 format = format_map[i].format;
476 break;
480 if (format == GST_VIDEO_FORMAT_UNKNOWN)
481 format = gst_video_format_from_fourcc(vih->bmiHeader.biCompression);
483 if (format == GST_VIDEO_FORMAT_UNKNOWN)
485 FIXME("Unknown video format (subtype %s, compression %#x).\n",
486 debugstr_guid(&mt->subtype), vih->bmiHeader.biCompression);
487 return NULL;
490 gst_video_info_set_format(&info, format, vih->bmiHeader.biWidth, vih->bmiHeader.biHeight);
491 if ((caps = gst_video_info_to_caps(&info)))
493 /* Clear some fields that shouldn't prevent us from connecting. */
494 for (i = 0; i < gst_caps_get_size(caps); ++i)
496 gst_structure_remove_fields(gst_caps_get_structure(caps, i),
497 "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL);
500 return caps;
503 static GstCaps *amt_to_gst_caps_audio(const AM_MEDIA_TYPE *mt)
505 const WAVEFORMATEX *wfx = (WAVEFORMATEX *)mt->pbFormat;
506 GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN;
507 GstAudioInfo info;
509 if (!IsEqualGUID(&mt->formattype, &FORMAT_WaveFormatEx)
510 || mt->cbFormat < sizeof(WAVEFORMATEX) || !mt->pbFormat)
511 return NULL;
513 if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_PCM))
514 format = gst_audio_format_build_integer(wfx->wBitsPerSample != 8,
515 G_LITTLE_ENDIAN, wfx->wBitsPerSample, wfx->wBitsPerSample);
516 else if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_IEEE_FLOAT))
518 if (wfx->wBitsPerSample == 32)
519 format = GST_AUDIO_FORMAT_F32LE;
520 else if (wfx->wBitsPerSample == 64)
521 format = GST_AUDIO_FORMAT_F64LE;
524 if (format == GST_AUDIO_FORMAT_UNKNOWN)
526 FIXME("Unknown audio format (subtype %s, depth %u).\n",
527 debugstr_guid(&mt->subtype), wfx->wBitsPerSample);
528 return NULL;
531 gst_audio_info_set_format(&info, format, wfx->nSamplesPerSec, wfx->nChannels, NULL);
532 return gst_audio_info_to_caps(&info);
535 static GstCaps *amt_to_gst_caps(const AM_MEDIA_TYPE *mt)
537 if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Video))
538 return amt_to_gst_caps_video(mt);
539 else if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Audio))
540 return amt_to_gst_caps_audio(mt);
542 FIXME("Unknown major type %s.\n", debugstr_guid(&mt->majortype));
543 return NULL;
546 static gboolean query_sink(GstPad *pad, GstObject *parent, GstQuery *query)
548 struct parser_source *pin = gst_pad_get_element_private(pad);
549 struct wg_parser_stream *stream = pin->wg_stream;
551 TRACE("pin %p, type \"%s\".\n", pin, gst_query_type_get_name(query->type));
553 switch (query->type)
555 case GST_QUERY_CAPS:
557 GstCaps *caps, *filter, *temp;
559 gst_query_parse_caps(query, &filter);
561 if (stream->enabled)
562 caps = amt_to_gst_caps(&pin->pin.pin.mt);
563 else
564 caps = gst_caps_new_any();
565 if (!caps)
566 return FALSE;
568 if (filter)
570 temp = gst_caps_intersect(caps, filter);
571 gst_caps_unref(caps);
572 caps = temp;
575 gst_query_set_caps_result(query, caps);
576 gst_caps_unref(caps);
577 return TRUE;
579 case GST_QUERY_ACCEPT_CAPS:
581 gboolean ret = TRUE;
582 AM_MEDIA_TYPE mt;
583 GstCaps *caps;
585 if (!stream->enabled)
587 gst_query_set_accept_caps_result(query, TRUE);
588 return TRUE;
591 gst_query_parse_accept_caps(query, &caps);
592 if (!amt_from_gst_caps(caps, &mt))
593 return FALSE;
595 if (!IsEqualGUID(&mt.majortype, &pin->pin.pin.mt.majortype)
596 || !IsEqualGUID(&mt.subtype, &pin->pin.pin.mt.subtype)
597 || !IsEqualGUID(&mt.formattype, &pin->pin.pin.mt.formattype))
598 ret = FALSE;
600 if (IsEqualGUID(&mt.majortype, &MEDIATYPE_Video))
602 const VIDEOINFOHEADER *req_vih = (VIDEOINFOHEADER *)mt.pbFormat;
603 const VIDEOINFOHEADER *our_vih = (VIDEOINFOHEADER *)pin->pin.pin.mt.pbFormat;
605 if (req_vih->bmiHeader.biWidth != our_vih->bmiHeader.biWidth
606 || req_vih->bmiHeader.biHeight != our_vih->bmiHeader.biHeight
607 || req_vih->bmiHeader.biBitCount != our_vih->bmiHeader.biBitCount
608 || req_vih->bmiHeader.biCompression != our_vih->bmiHeader.biCompression)
609 ret = FALSE;
611 else if (IsEqualGUID(&mt.majortype, &MEDIATYPE_Audio))
613 const WAVEFORMATEX *req_wfx = (WAVEFORMATEX *)mt.pbFormat;
614 const WAVEFORMATEX *our_wfx = (WAVEFORMATEX *)pin->pin.pin.mt.pbFormat;
616 if (req_wfx->nChannels != our_wfx->nChannels
617 || req_wfx->nSamplesPerSec != our_wfx->nSamplesPerSec
618 || req_wfx->wBitsPerSample != our_wfx->wBitsPerSample)
619 ret = FALSE;
622 FreeMediaType(&mt);
624 if (!ret && WARN_ON(gstreamer))
626 gchar *str = gst_caps_to_string(caps);
627 WARN("Rejecting caps \"%s\".\n", debugstr_a(str));
628 g_free(str);
631 gst_query_set_accept_caps_result(query, ret);
632 return TRUE;
634 default:
635 return gst_pad_query_default (pad, parent, query);
639 static gboolean gst_base_src_perform_seek(struct parser *This, GstEvent *event)
641 struct wg_parser *parser = This->wg_parser;
642 gboolean res = TRUE;
643 gdouble rate;
644 GstFormat seek_format;
645 GstSeekFlags flags;
646 GstSeekType cur_type, stop_type;
647 gint64 cur, stop;
648 gboolean flush;
649 guint32 seqnum;
650 GstEvent *tevent;
651 BOOL thread = !!parser->push_thread;
653 gst_event_parse_seek(event, &rate, &seek_format, &flags,
654 &cur_type, &cur, &stop_type, &stop);
656 if (seek_format != GST_FORMAT_BYTES)
658 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format));
659 return FALSE;
662 flush = flags & GST_SEEK_FLAG_FLUSH;
663 seqnum = gst_event_get_seqnum(event);
665 /* send flush start */
666 if (flush) {
667 tevent = gst_event_new_flush_start();
668 gst_event_set_seqnum(tevent, seqnum);
669 gst_pad_push_event(parser->my_src, tevent);
670 if (thread)
671 gst_pad_set_active(parser->my_src, 1);
674 parser->next_offset = parser->start_offset = cur;
676 /* and prepare to continue streaming */
677 if (flush) {
678 tevent = gst_event_new_flush_stop(TRUE);
679 gst_event_set_seqnum(tevent, seqnum);
680 gst_pad_push_event(parser->my_src, tevent);
681 if (thread)
682 gst_pad_set_active(parser->my_src, 1);
685 return res;
688 static gboolean event_src(GstPad *pad, GstObject *parent, GstEvent *event)
690 struct parser *This = gst_pad_get_element_private(pad);
691 gboolean ret = TRUE;
693 GST_LOG("filter %p, type \"%s\".", This, GST_EVENT_TYPE_NAME(event));
695 switch (event->type)
697 case GST_EVENT_SEEK:
698 ret = gst_base_src_perform_seek(This, event);
699 break;
701 case GST_EVENT_FLUSH_START:
702 case GST_EVENT_FLUSH_STOP:
703 case GST_EVENT_QOS:
704 case GST_EVENT_RECONFIGURE:
705 break;
707 default:
708 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
709 ret = FALSE;
710 break;
712 gst_event_unref(event);
713 return ret;
716 static GstFlowReturn queue_stream_event(struct parser_source *pin, const struct wg_parser_event *event)
718 struct wg_parser *parser = impl_from_strmbase_filter(pin->pin.pin.filter)->wg_parser;
719 struct wg_parser_stream *stream = pin->wg_stream;
721 /* Unlike request_buffer_src() [q.v.], we need to watch for GStreamer
722 * flushes here. The difference is that we can be blocked by the streaming
723 * thread not running (or itself flushing on the DirectShow side).
724 * request_buffer_src() can only be blocked by the upstream source, and that
725 * is solved by flushing the upstream source. */
727 pthread_mutex_lock(&parser->mutex);
728 while (!stream->flushing && stream->event.type != WG_PARSER_EVENT_NONE)
729 pthread_cond_wait(&stream->event_empty_cond, &parser->mutex);
730 if (stream->flushing)
732 pthread_mutex_unlock(&parser->mutex);
733 GST_DEBUG("Filter is flushing; discarding event.");
734 return GST_FLOW_FLUSHING;
736 stream->event = *event;
737 pthread_mutex_unlock(&parser->mutex);
738 pthread_cond_signal(&stream->event_cond);
739 GST_LOG("Event queued.");
740 return GST_FLOW_OK;
743 static gboolean event_sink(GstPad *pad, GstObject *parent, GstEvent *event)
745 struct parser_source *pin = gst_pad_get_element_private(pad);
746 struct wg_parser_stream *stream = pin->wg_stream;
747 struct parser *filter = impl_from_strmbase_filter(pin->pin.pin.filter);
748 struct wg_parser *parser = filter->wg_parser;
750 GST_LOG("pin %p, type \"%s\".", pin, GST_EVENT_TYPE_NAME(event));
752 switch (event->type)
754 case GST_EVENT_SEGMENT:
755 if (stream->enabled)
757 struct wg_parser_event stream_event;
758 const GstSegment *segment;
760 gst_event_parse_segment(event, &segment);
762 if (segment->format != GST_FORMAT_TIME)
764 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(segment->format));
765 break;
768 gst_segment_copy_into(segment, stream->segment);
770 stream_event.type = WG_PARSER_EVENT_SEGMENT;
771 stream_event.u.segment.position = segment->position / 100;
772 stream_event.u.segment.stop = segment->stop / 100;
773 stream_event.u.segment.rate = segment->rate * segment->applied_rate;
774 queue_stream_event(pin, &stream_event);
776 break;
778 case GST_EVENT_EOS:
779 if (stream->enabled)
781 struct wg_parser_event stream_event;
783 stream_event.type = WG_PARSER_EVENT_EOS;
784 queue_stream_event(pin, &stream_event);
786 else
788 pthread_mutex_lock(&parser->mutex);
789 stream->eos = true;
790 pthread_mutex_unlock(&parser->mutex);
791 pthread_cond_signal(&parser->init_cond);
793 break;
795 case GST_EVENT_FLUSH_START:
796 if (stream->enabled)
798 pthread_mutex_lock(&parser->mutex);
800 stream->flushing = true;
801 pthread_cond_signal(&stream->event_empty_cond);
803 switch (stream->event.type)
805 case WG_PARSER_EVENT_NONE:
806 case WG_PARSER_EVENT_EOS:
807 case WG_PARSER_EVENT_SEGMENT:
808 break;
810 case WG_PARSER_EVENT_BUFFER:
811 gst_buffer_unref(stream->event.u.buffer);
812 break;
814 stream->event.type = WG_PARSER_EVENT_NONE;
816 pthread_mutex_unlock(&parser->mutex);
818 break;
820 case GST_EVENT_FLUSH_STOP:
821 gst_segment_init(stream->segment, GST_FORMAT_TIME);
822 if (stream->enabled)
824 pthread_mutex_lock(&parser->mutex);
825 stream->flushing = false;
826 pthread_mutex_unlock(&parser->mutex);
828 break;
830 case GST_EVENT_CAPS:
832 GstCaps *caps;
834 gst_event_parse_caps(event, &caps);
835 pthread_mutex_lock(&parser->mutex);
836 gst_caps_replace(&stream->caps, caps);
837 pthread_mutex_unlock(&parser->mutex);
838 pthread_cond_signal(&parser->init_cond);
839 break;
842 default:
843 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event));
845 gst_event_unref(event);
846 return TRUE;
849 static GstFlowReturn request_buffer_src(GstPad *pad, GstObject *parent, guint64 offset, guint size, GstBuffer **buffer);
851 static void *push_data(void *iface)
853 struct parser *This = iface;
854 struct wg_parser *parser = This->wg_parser;
855 GstBuffer *buffer;
856 LONGLONG maxlen;
858 GST_DEBUG("Starting push thread.");
860 if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL)))
862 GST_ERROR("Failed to allocate memory.");
863 return NULL;
866 maxlen = parser->stop_offset ? parser->stop_offset : parser->file_size;
868 for (;;) {
869 ULONG len;
870 int ret;
872 if (parser->next_offset >= maxlen)
873 break;
874 len = min(16384, maxlen - parser->next_offset);
876 if ((ret = request_buffer_src(parser->my_src, NULL, parser->next_offset, len, &buffer)) < 0)
878 GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret));
879 break;
882 parser->next_offset += len;
884 buffer->duration = buffer->pts = -1;
885 if ((ret = gst_pad_push(parser->my_src, buffer)) < 0)
887 GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret));
888 break;
892 gst_buffer_unref(buffer);
894 gst_pad_push_event(parser->my_src, gst_event_new_eos());
896 GST_DEBUG("Stopping push thread.");
898 return NULL;
901 static GstFlowReturn got_data_sink(GstPad *pad, GstObject *parent, GstBuffer *buffer)
903 struct parser_source *pin = gst_pad_get_element_private(pad);
904 struct wg_parser_stream *stream = pin->wg_stream;
905 struct wg_parser_event stream_event;
906 GstFlowReturn ret;
908 GST_LOG("pin %p, buffer %p.", pin, buffer);
910 if (!stream->enabled)
912 gst_buffer_unref(buffer);
913 return GST_FLOW_OK;
916 stream_event.type = WG_PARSER_EVENT_BUFFER;
917 stream_event.u.buffer = buffer;
918 /* Transfer our reference to the buffer to the thread. */
919 if ((ret = queue_stream_event(pin, &stream_event)) != GST_FLOW_OK)
920 gst_buffer_unref(buffer);
921 return ret;
924 /* Fill and send a single IMediaSample. */
925 static HRESULT send_sample(struct parser_source *pin, IMediaSample *sample,
926 GstBuffer *buf, GstMapInfo *info, gsize offset, gsize size, DWORD bytes_per_second)
928 struct wg_parser_stream *stream = pin->wg_stream;
929 HRESULT hr;
930 BYTE *ptr = NULL;
932 hr = IMediaSample_SetActualDataLength(sample, size);
933 if(FAILED(hr)){
934 WARN("SetActualDataLength failed: %08x\n", hr);
935 return hr;
938 IMediaSample_GetPointer(sample, &ptr);
940 memcpy(ptr, &info->data[offset], size);
942 if (GST_BUFFER_PTS_IS_VALID(buf)) {
943 REFERENCE_TIME rtStart;
944 GstClockTime ptsStart = buf->pts;
945 if (offset > 0)
946 ptsStart = buf->pts + gst_util_uint64_scale(offset, GST_SECOND, bytes_per_second);
947 rtStart = gst_segment_to_running_time(stream->segment, GST_FORMAT_TIME, ptsStart);
948 if (rtStart >= 0)
949 rtStart /= 100;
951 if (GST_BUFFER_DURATION_IS_VALID(buf)) {
952 REFERENCE_TIME rtStop;
953 REFERENCE_TIME tStart;
954 REFERENCE_TIME tStop;
955 GstClockTime ptsStop = buf->pts + buf->duration;
956 if (offset + size < info->size)
957 ptsStop = buf->pts + gst_util_uint64_scale(offset + size, GST_SECOND, bytes_per_second);
958 tStart = ptsStart / 100;
959 tStop = ptsStop / 100;
960 rtStop = gst_segment_to_running_time(stream->segment, GST_FORMAT_TIME, ptsStop);
961 if (rtStop >= 0)
962 rtStop /= 100;
963 TRACE("Current time on %p: %i to %i ms\n", pin, (int)(rtStart / 10000), (int)(rtStop / 10000));
964 IMediaSample_SetTime(sample, &rtStart, rtStop >= 0 ? &rtStop : NULL);
965 IMediaSample_SetMediaTime(sample, &tStart, &tStop);
966 } else {
967 IMediaSample_SetTime(sample, rtStart >= 0 ? &rtStart : NULL, NULL);
968 IMediaSample_SetMediaTime(sample, NULL, NULL);
970 } else {
971 IMediaSample_SetTime(sample, NULL, NULL);
972 IMediaSample_SetMediaTime(sample, NULL, NULL);
975 IMediaSample_SetDiscontinuity(sample, !offset && GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT));
976 IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_LIVE));
977 IMediaSample_SetSyncPoint(sample, !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT));
979 if (!pin->pin.pin.peer)
980 hr = VFW_E_NOT_CONNECTED;
981 else
982 hr = IMemInputPin_Receive(pin->pin.pMemInputPin, sample);
984 TRACE("sending sample returned: %08x\n", hr);
986 return hr;
989 /* Send a single GStreamer buffer (splitting it into multiple IMediaSamples if
990 * necessary). */
991 static void send_buffer(struct parser_source *pin, GstBuffer *buf)
993 HRESULT hr;
994 IMediaSample *sample;
995 GstMapInfo info;
997 gst_buffer_map(buf, &info, GST_MAP_READ);
999 if (IsEqualGUID(&pin->pin.pin.mt.formattype, &FORMAT_WaveFormatEx)
1000 && (IsEqualGUID(&pin->pin.pin.mt.subtype, &MEDIASUBTYPE_PCM)
1001 || IsEqualGUID(&pin->pin.pin.mt.subtype, &MEDIASUBTYPE_IEEE_FLOAT)))
1003 WAVEFORMATEX *format = (WAVEFORMATEX *)pin->pin.pin.mt.pbFormat;
1004 gsize offset = 0;
1005 while (offset < info.size)
1007 gsize advance;
1009 hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0);
1011 if (FAILED(hr))
1013 if (hr != VFW_E_NOT_CONNECTED)
1014 ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr);
1015 break;
1018 advance = min(IMediaSample_GetSize(sample), info.size - offset);
1020 hr = send_sample(pin, sample, buf, &info, offset, advance, format->nAvgBytesPerSec);
1022 IMediaSample_Release(sample);
1024 if (FAILED(hr))
1025 break;
1027 offset += advance;
1030 else
1032 hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0);
1034 if (FAILED(hr))
1036 if (hr != VFW_E_NOT_CONNECTED)
1037 ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr);
1039 else
1041 hr = send_sample(pin, sample, buf, &info, 0, info.size, 0);
1043 IMediaSample_Release(sample);
1047 gst_buffer_unmap(buf, &info);
1049 gst_buffer_unref(buf);
1052 static bool get_stream_event(struct parser_source *pin, struct wg_parser_event *event)
1054 struct parser *filter = impl_from_strmbase_filter(pin->pin.pin.filter);
1055 struct wg_parser_stream *stream = pin->wg_stream;
1056 struct wg_parser *parser = filter->wg_parser;
1058 pthread_mutex_lock(&parser->mutex);
1060 while (!parser->flushing && stream->event.type == WG_PARSER_EVENT_NONE)
1061 pthread_cond_wait(&stream->event_cond, &parser->mutex);
1063 if (parser->flushing)
1065 pthread_mutex_unlock(&parser->mutex);
1066 TRACE("Filter is flushing.\n");
1067 return false;
1070 *event = stream->event;
1071 stream->event.type = WG_PARSER_EVENT_NONE;
1073 pthread_mutex_unlock(&parser->mutex);
1074 pthread_cond_signal(&stream->event_empty_cond);
1076 return true;
1079 static DWORD CALLBACK stream_thread(void *arg)
1081 struct parser_source *pin = arg;
1082 struct parser *filter = impl_from_strmbase_filter(pin->pin.pin.filter);
1084 TRACE("Starting streaming thread for pin %p.\n", pin);
1086 while (filter->streaming)
1088 struct wg_parser_event event;
1090 EnterCriticalSection(&pin->flushing_cs);
1092 if (!get_stream_event(pin, &event))
1094 LeaveCriticalSection(&pin->flushing_cs);
1095 continue;
1098 TRACE("Got event of type %#x.\n", event.type);
1100 switch (event.type)
1102 case WG_PARSER_EVENT_BUFFER:
1103 send_buffer(pin, event.u.buffer);
1104 break;
1106 case WG_PARSER_EVENT_EOS:
1107 IPin_EndOfStream(pin->pin.pin.peer);
1108 break;
1110 case WG_PARSER_EVENT_SEGMENT:
1111 IPin_NewSegment(pin->pin.pin.peer, event.u.segment.position,
1112 event.u.segment.stop, event.u.segment.rate);
1113 break;
1115 case WG_PARSER_EVENT_NONE:
1116 assert(0);
1119 LeaveCriticalSection(&pin->flushing_cs);
1122 TRACE("Streaming stopped; exiting.\n");
1123 return 0;
1126 static GstFlowReturn request_buffer_src(GstPad *pad, GstObject *parent, guint64 offset, guint size, GstBuffer **buffer)
1128 struct parser *filter = gst_pad_get_element_private(pad);
1129 struct wg_parser *parser = filter->wg_parser;
1130 GstBuffer *new_buffer = NULL;
1131 GstFlowReturn ret;
1133 GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, length %u, buffer %p.", pad, offset, size, *buffer);
1135 if (!*buffer)
1136 *buffer = new_buffer = gst_buffer_new_and_alloc(size);
1138 pthread_mutex_lock(&parser->mutex);
1140 assert(!parser->read_request.buffer);
1141 parser->read_request.buffer = *buffer;
1142 parser->read_request.offset = offset;
1143 parser->read_request.size = size;
1144 parser->read_request.done = false;
1145 pthread_cond_signal(&parser->read_cond);
1147 /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect
1148 * the upstream pin to flush if necessary. We should never be blocked on
1149 * read_thread() not running. */
1151 while (!parser->read_request.done)
1152 pthread_cond_wait(&parser->read_done_cond, &parser->mutex);
1154 ret = parser->read_request.ret;
1156 pthread_mutex_unlock(&parser->mutex);
1158 GST_LOG("Request returned %s.", gst_flow_get_name(ret));
1160 if (ret != GST_FLOW_OK && new_buffer)
1161 gst_buffer_unref(new_buffer);
1163 return ret;
1166 static GstFlowReturn read_buffer(struct parser *This, guint64 ofs, guint len, GstBuffer *buffer)
1168 HRESULT hr;
1169 GstMapInfo info;
1171 TRACE("filter %p, offset %s, length %u, buffer %p.\n", This, wine_dbgstr_longlong(ofs), len, buffer);
1173 if (ofs == GST_BUFFER_OFFSET_NONE)
1174 ofs = This->next_pull_offset;
1175 if (ofs >= This->file_size)
1177 WARN("Reading past eof: %s, %u\n", wine_dbgstr_longlong(ofs), len);
1178 return GST_FLOW_EOS;
1180 if (len + ofs > This->file_size)
1181 len = This->file_size - ofs;
1182 This->next_pull_offset = ofs + len;
1184 gst_buffer_map(buffer, &info, GST_MAP_WRITE);
1185 hr = IAsyncReader_SyncRead(This->reader, ofs, len, info.data);
1186 gst_buffer_unmap(buffer, &info);
1187 if (FAILED(hr))
1189 ERR("Failed to read data, hr %#x.\n", hr);
1190 return GST_FLOW_ERROR;
1193 return GST_FLOW_OK;
1196 static DWORD CALLBACK read_thread(void *arg)
1198 struct parser *filter = arg;
1199 struct wg_parser *parser = filter->wg_parser;
1201 TRACE("Starting read thread for filter %p.\n", filter);
1203 pthread_mutex_lock(&parser->mutex);
1205 while (filter->sink_connected)
1207 while (parser->sink_connected && !parser->read_request.buffer)
1208 pthread_cond_wait(&parser->read_cond, &parser->mutex);
1210 if (!parser->sink_connected)
1211 break;
1213 parser->read_request.done = true;
1214 parser->read_request.ret = read_buffer(filter, parser->read_request.offset,
1215 parser->read_request.size, parser->read_request.buffer);
1216 parser->read_request.buffer = NULL;
1217 pthread_cond_signal(&parser->read_done_cond);
1220 pthread_mutex_unlock(&parser->mutex);
1222 TRACE("Streaming stopped; exiting.\n");
1223 return 0;
1226 static void removed_decoded_pad(GstElement *bin, GstPad *pad, gpointer user)
1228 struct parser *filter = user;
1229 unsigned int i;
1230 char *name;
1232 GST_LOG("filter %p, bin %p, pad %p.", filter, bin, pad);
1234 for (i = 0; i < filter->source_count; ++i)
1236 struct wg_parser_stream *stream = filter->sources[i]->wg_stream;
1238 if (stream->their_src == pad)
1240 if (stream->post_sink)
1241 gst_pad_unlink(stream->their_src, stream->post_sink);
1242 else
1243 gst_pad_unlink(stream->their_src, stream->my_sink);
1244 gst_object_unref(stream->their_src);
1245 stream->their_src = NULL;
1246 return;
1250 name = gst_pad_get_name(pad);
1251 GST_LOG("No pin matching pad \"%s\" found.", name);
1252 g_free(name);
1255 static void init_new_decoded_pad(GstElement *bin, GstPad *pad, struct parser *This)
1257 static const WCHAR formatW[] = {'S','t','r','e','a','m',' ','%','0','2','u',0};
1258 struct wg_parser *parser = This->wg_parser;
1259 struct wg_parser_stream *stream;
1260 const char *typename;
1261 char *name;
1262 GstCaps *caps;
1263 GstStructure *arg;
1264 struct parser_source *pin;
1265 int ret;
1266 WCHAR nameW[128];
1268 TRACE("%p %p %p\n", This, bin, pad);
1270 sprintfW(nameW, formatW, This->source_count);
1272 name = gst_pad_get_name(pad);
1273 TRACE("Name: %s\n", name);
1274 g_free(name);
1276 caps = gst_pad_query_caps(pad, NULL);
1277 caps = gst_caps_make_writable(caps);
1278 arg = gst_caps_get_structure(caps, 0);
1279 typename = gst_structure_get_name(arg);
1281 if (!(pin = create_pin(This, nameW)))
1283 ERR("Failed to allocate memory.\n");
1284 goto out;
1286 stream = pin->wg_stream;
1288 if (!strcmp(typename, "video/x-raw"))
1290 GstElement *deinterlace, *vconv, *flip, *vconv2;
1292 /* DirectShow can express interlaced video, but downstream filters can't
1293 * necessarily consume it. In particular, the video renderer can't. */
1294 if (!(deinterlace = gst_element_factory_make("deinterlace", NULL)))
1296 ERR("Failed to create deinterlace, are %u-bit GStreamer \"good\" plugins installed?\n",
1297 8 * (int)sizeof(void *));
1298 goto out;
1301 /* decodebin considers many YUV formats to be "raw", but some quartz
1302 * filters can't handle those. Also, videoflip can't handle all "raw"
1303 * formats either. Add a videoconvert to swap color spaces. */
1304 if (!(vconv = gst_element_factory_make("videoconvert", NULL)))
1306 ERR("Failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
1307 8 * (int)sizeof(void *));
1308 goto out;
1311 /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
1312 if (!(flip = gst_element_factory_make("videoflip", NULL)))
1314 ERR("Failed to create videoflip, are %u-bit GStreamer \"good\" plugins installed?\n",
1315 8 * (int)sizeof(void *));
1316 goto out;
1319 /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert
1320 * to do the final conversion. */
1321 if (!(vconv2 = gst_element_factory_make("videoconvert", NULL)))
1323 ERR("Failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
1324 8 * (int)sizeof(void *));
1325 goto out;
1328 /* The bin takes ownership of these elements. */
1329 gst_bin_add(GST_BIN(parser->container), deinterlace);
1330 gst_element_sync_state_with_parent(deinterlace);
1331 gst_bin_add(GST_BIN(parser->container), vconv);
1332 gst_element_sync_state_with_parent(vconv);
1333 gst_bin_add(GST_BIN(parser->container), flip);
1334 gst_element_sync_state_with_parent(flip);
1335 gst_bin_add(GST_BIN(parser->container), vconv2);
1336 gst_element_sync_state_with_parent(vconv2);
1338 gst_element_link(deinterlace, vconv);
1339 gst_element_link(vconv, flip);
1340 gst_element_link(flip, vconv2);
1342 stream->post_sink = gst_element_get_static_pad(deinterlace, "sink");
1343 stream->post_src = gst_element_get_static_pad(vconv2, "src");
1344 stream->flip = flip;
1346 else if (!strcmp(typename, "audio/x-raw"))
1348 GstElement *convert;
1350 /* Currently our dsound can't handle 64-bit formats or all
1351 * surround-sound configurations. Native dsound can't always handle
1352 * 64-bit formats either. Add an audioconvert to allow changing bit
1353 * depth and channel count. */
1354 if (!(convert = gst_element_factory_make("audioconvert", NULL)))
1356 ERR("Failed to create audioconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
1357 8 * (int)sizeof(void *));
1358 goto out;
1361 gst_bin_add(GST_BIN(parser->container), convert);
1362 gst_element_sync_state_with_parent(convert);
1364 stream->post_sink = gst_element_get_static_pad(convert, "sink");
1365 stream->post_src = gst_element_get_static_pad(convert, "src");
1368 if (stream->post_sink)
1370 if ((ret = gst_pad_link(pad, stream->post_sink)) < 0)
1372 ERR("Failed to link decodebin source pad to post-processing elements, error %s.\n",
1373 gst_pad_link_get_name(ret));
1374 gst_object_unref(stream->post_sink);
1375 stream->post_sink = NULL;
1376 goto out;
1379 if ((ret = gst_pad_link(stream->post_src, stream->my_sink)) < 0)
1381 ERR("Failed to link post-processing elements to our sink pad, error %s.\n",
1382 gst_pad_link_get_name(ret));
1383 gst_object_unref(stream->post_src);
1384 stream->post_src = NULL;
1385 gst_object_unref(stream->post_sink);
1386 stream->post_sink = NULL;
1387 goto out;
1390 else if ((ret = gst_pad_link(pad, stream->my_sink)) < 0)
1392 ERR("Failed to link decodebin source pad to our sink pad, error %s.\n",
1393 gst_pad_link_get_name(ret));
1394 goto out;
1397 gst_pad_set_active(stream->my_sink, 1);
1398 gst_object_ref(stream->their_src = pad);
1399 out:
1400 gst_caps_unref(caps);
1403 static void existing_new_pad(GstElement *bin, GstPad *pad, gpointer user)
1405 struct parser *This = user;
1407 TRACE("%p %p %p\n", This, bin, pad);
1409 if (gst_pad_is_linked(pad))
1410 return;
1412 init_new_decoded_pad(bin, pad, This);
1415 static gboolean query_function(GstPad *pad, GstObject *parent, GstQuery *query)
1417 struct parser *This = gst_pad_get_element_private(pad);
1418 struct wg_parser *parser = This->wg_parser;
1419 GstFormat format;
1421 GST_LOG("filter %p, type %s.", This, GST_QUERY_TYPE_NAME(query));
1423 switch (GST_QUERY_TYPE(query)) {
1424 case GST_QUERY_DURATION:
1425 gst_query_parse_duration(query, &format, NULL);
1426 if (format == GST_FORMAT_PERCENT)
1428 gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX);
1429 return TRUE;
1431 else if (format == GST_FORMAT_BYTES)
1433 gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size);
1434 return TRUE;
1436 return FALSE;
1437 case GST_QUERY_SEEKING:
1438 gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
1439 if (format != GST_FORMAT_BYTES)
1441 GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format));
1442 return FALSE;
1444 gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size);
1445 return TRUE;
1446 case GST_QUERY_SCHEDULING:
1447 gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
1448 gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH);
1449 gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL);
1450 return TRUE;
1451 default:
1452 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query));
1453 return FALSE;
1457 static gboolean activate_push(GstPad *pad, gboolean activate)
1459 struct parser *This = gst_pad_get_element_private(pad);
1460 struct wg_parser *parser = This->wg_parser;
1462 if (!activate) {
1463 if (parser->push_thread) {
1464 pthread_join(parser->push_thread, NULL);
1465 parser->push_thread = 0;
1467 if (This->filter.state == State_Stopped)
1468 parser->next_offset = parser->start_offset;
1469 } else if (!parser->push_thread) {
1470 int ret;
1472 if ((ret = pthread_create(&parser->push_thread, NULL, push_data, This)))
1474 GST_ERROR("Failed to create push thread: %s", strerror(errno));
1475 parser->push_thread = 0;
1476 return FALSE;
1479 return TRUE;
1482 static gboolean activate_mode(GstPad *pad, GstObject *parent, GstPadMode mode, gboolean activate)
1484 struct parser *filter = gst_pad_get_element_private(pad);
1486 GST_DEBUG("%s source pad for filter %p in %s mode.",
1487 activate ? "Activating" : "Deactivating", filter, gst_pad_mode_get_name(mode));
1489 switch (mode) {
1490 case GST_PAD_MODE_PULL:
1491 return TRUE;
1492 case GST_PAD_MODE_PUSH:
1493 return activate_push(pad, activate);
1494 default:
1495 return FALSE;
1497 return FALSE;
1500 static void no_more_pads(GstElement *decodebin, gpointer user)
1502 struct parser *filter = user;
1503 struct wg_parser *parser = filter->wg_parser;
1505 GST_DEBUG("filter %p.", filter);
1507 pthread_mutex_lock(&parser->mutex);
1508 parser->no_more_pads = true;
1509 pthread_mutex_unlock(&parser->mutex);
1510 pthread_cond_signal(&parser->init_cond);
1513 static GstAutoplugSelectResult autoplug_blacklist(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *fact, gpointer user)
1515 const char *name = gst_element_factory_get_longname(fact);
1517 GST_TRACE("Using \"%s\".", name);
1519 if (strstr(name, "Player protection"))
1521 GST_WARNING("Blacklisted a/52 decoder because it only works in Totem.");
1522 return GST_AUTOPLUG_SELECT_SKIP;
1524 if (!strcmp(name, "Fluendo Hardware Accelerated Video Decoder"))
1526 GST_WARNING("Disabled video acceleration since it breaks in wine.");
1527 return GST_AUTOPLUG_SELECT_SKIP;
1529 return GST_AUTOPLUG_SELECT_TRY;
1532 static GstBusSyncReply watch_bus(GstBus *bus, GstMessage *msg, gpointer data)
1534 struct parser *filter = data;
1535 struct wg_parser *parser = filter->wg_parser;
1536 GError *err = NULL;
1537 gchar *dbg_info = NULL;
1539 GST_DEBUG("filter %p, message type %s.", filter, GST_MESSAGE_TYPE_NAME(msg));
1541 switch (msg->type)
1543 case GST_MESSAGE_ERROR:
1544 gst_message_parse_error(msg, &err, &dbg_info);
1545 fprintf(stderr, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
1546 fprintf(stderr, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg->src), dbg_info);
1547 g_error_free(err);
1548 g_free(dbg_info);
1549 pthread_mutex_lock(&parser->mutex);
1550 parser->error = true;
1551 pthread_mutex_unlock(&parser->mutex);
1552 pthread_cond_signal(&parser->init_cond);
1553 break;
1555 case GST_MESSAGE_WARNING:
1556 gst_message_parse_warning(msg, &err, &dbg_info);
1557 fprintf(stderr, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
1558 fprintf(stderr, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg->src), dbg_info);
1559 g_error_free(err);
1560 g_free(dbg_info);
1561 break;
1563 case GST_MESSAGE_DURATION_CHANGED:
1564 pthread_mutex_lock(&parser->mutex);
1565 parser->has_duration = true;
1566 pthread_mutex_unlock(&parser->mutex);
1567 pthread_cond_signal(&parser->init_cond);
1568 break;
1570 default:
1571 break;
1573 gst_message_unref(msg);
1574 return GST_BUS_DROP;
1577 static LONGLONG query_duration(GstPad *pad)
1579 gint64 duration, byte_length;
1581 if (gst_pad_query_duration(pad, GST_FORMAT_TIME, &duration))
1582 return duration / 100;
1584 WARN("Failed to query time duration; trying to convert from byte length.\n");
1586 /* To accurately get a duration for the stream, we want to only consider the
1587 * length of that stream. Hence, query for the pad duration, instead of
1588 * using the file duration. */
1589 if (gst_pad_query_duration(pad, GST_FORMAT_BYTES, &byte_length)
1590 && gst_pad_query_convert(pad, GST_FORMAT_BYTES, byte_length, GST_FORMAT_TIME, &duration))
1591 return duration / 100;
1593 ERR("Failed to query duration.\n");
1594 return 0;
1597 static HRESULT GST_Connect(struct parser *This, IPin *pConnectPin)
1599 struct wg_parser *parser = This->wg_parser;
1600 unsigned int i;
1601 LONGLONG avail;
1602 GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE(
1603 "quartz_src",
1604 GST_PAD_SRC,
1605 GST_PAD_ALWAYS,
1606 GST_STATIC_CAPS_ANY);
1608 IAsyncReader_Length(This->reader, &This->file_size, &avail);
1609 parser->file_size = This->file_size;
1611 This->sink_connected = true;
1612 parser->sink_connected = true;
1614 This->read_thread = CreateThread(NULL, 0, read_thread, This, 0, NULL);
1616 if (!parser->bus)
1618 parser->bus = gst_bus_new();
1619 gst_bus_set_sync_handler(parser->bus, watch_bus, This, NULL);
1622 parser->container = gst_bin_new(NULL);
1623 gst_element_set_bus(parser->container, parser->bus);
1625 parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src");
1626 gst_pad_set_getrange_function(parser->my_src, request_buffer_src);
1627 gst_pad_set_query_function(parser->my_src, query_function);
1628 gst_pad_set_activatemode_function(parser->my_src, activate_mode);
1629 gst_pad_set_event_function(parser->my_src, event_src);
1630 gst_pad_set_element_private (parser->my_src, This);
1632 parser->start_offset = parser->next_offset = parser->stop_offset = 0;
1633 This->next_pull_offset = 0;
1635 if (!This->init_gst(This))
1636 return E_FAIL;
1638 pthread_mutex_lock(&parser->mutex);
1640 for (i = 0; i < This->source_count; ++i)
1642 struct parser_source *pin = This->sources[i];
1643 struct wg_parser_stream *stream = pin->wg_stream;
1645 pin->seek.llDuration = pin->seek.llStop = query_duration(stream->their_src);
1646 pin->seek.llCurrent = 0;
1647 while (!stream->caps && !parser->error)
1648 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1649 if (parser->error)
1651 pthread_mutex_unlock(&parser->mutex);
1652 return E_FAIL;
1656 pthread_mutex_unlock(&parser->mutex);
1658 parser->next_offset = 0;
1659 This->next_pull_offset = 0;
1660 return S_OK;
1663 static inline struct parser_source *impl_from_IMediaSeeking(IMediaSeeking *iface)
1665 return CONTAINING_RECORD(iface, struct parser_source, seek.IMediaSeeking_iface);
1668 static struct strmbase_pin *parser_get_pin(struct strmbase_filter *base, unsigned int index)
1670 struct parser *filter = impl_from_strmbase_filter(base);
1672 if (filter->enum_sink_first)
1674 if (!index)
1675 return &filter->sink.pin;
1676 else if (index <= filter->source_count)
1677 return &filter->sources[index - 1]->pin.pin;
1679 else
1681 if (index < filter->source_count)
1682 return &filter->sources[index]->pin.pin;
1683 else if (index == filter->source_count)
1684 return &filter->sink.pin;
1686 return NULL;
1689 static void wg_parser_destroy(struct wg_parser *parser)
1691 if (parser->bus)
1693 gst_bus_set_sync_handler(parser->bus, NULL, NULL, NULL);
1694 gst_object_unref(parser->bus);
1697 pthread_mutex_destroy(&parser->mutex);
1698 pthread_cond_destroy(&parser->init_cond);
1699 pthread_cond_destroy(&parser->read_cond);
1700 pthread_cond_destroy(&parser->read_done_cond);
1702 free(parser);
1705 static void parser_destroy(struct strmbase_filter *iface)
1707 struct parser *filter = impl_from_strmbase_filter(iface);
1708 HRESULT hr;
1710 /* Don't need to clean up output pins, disconnecting input pin will do that */
1711 if (filter->sink.pin.peer)
1713 hr = IPin_Disconnect(filter->sink.pin.peer);
1714 assert(hr == S_OK);
1715 hr = IPin_Disconnect(&filter->sink.pin.IPin_iface);
1716 assert(hr == S_OK);
1719 if (filter->reader)
1720 IAsyncReader_Release(filter->reader);
1721 filter->reader = NULL;
1723 wg_parser_destroy(filter->wg_parser);
1725 strmbase_sink_cleanup(&filter->sink);
1726 strmbase_filter_cleanup(&filter->filter);
1727 heap_free(filter);
1730 static HRESULT parser_init_stream(struct strmbase_filter *iface)
1732 struct parser *filter = impl_from_strmbase_filter(iface);
1733 struct wg_parser *parser = filter->wg_parser;
1734 GstSeekType stop_type = GST_SEEK_TYPE_NONE;
1735 const SourceSeeking *seeking;
1736 unsigned int i;
1738 if (!parser->container)
1739 return S_OK;
1741 filter->streaming = true;
1742 pthread_mutex_lock(&parser->mutex);
1743 parser->flushing = false;
1744 pthread_mutex_unlock(&parser->mutex);
1746 /* DirectShow retains the old seek positions, but resets to them every time
1747 * it transitions from stopped -> paused. */
1749 seeking = &filter->sources[0]->seek;
1750 if (seeking->llStop && seeking->llStop != seeking->llDuration)
1751 stop_type = GST_SEEK_TYPE_SET;
1752 gst_pad_push_event(filter->sources[0]->wg_stream->my_sink, gst_event_new_seek(
1753 seeking->dRate, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH,
1754 GST_SEEK_TYPE_SET, seeking->llCurrent * 100,
1755 stop_type, seeking->llStop * 100));
1757 for (i = 0; i < filter->source_count; ++i)
1759 HRESULT hr;
1761 if (!filter->sources[i]->pin.pin.peer)
1762 continue;
1764 if (FAILED(hr = IMemAllocator_Commit(filter->sources[i]->pin.pAllocator)))
1765 ERR("Failed to commit allocator, hr %#x.\n", hr);
1767 filter->sources[i]->thread = CreateThread(NULL, 0, stream_thread, filter->sources[i], 0, NULL);
1770 return S_OK;
1773 static HRESULT parser_cleanup_stream(struct strmbase_filter *iface)
1775 struct parser *filter = impl_from_strmbase_filter(iface);
1776 struct wg_parser *parser = filter->wg_parser;
1777 unsigned int i;
1779 if (!parser->container)
1780 return S_OK;
1782 filter->streaming = false;
1783 pthread_mutex_lock(&parser->mutex);
1784 parser->flushing = true;
1785 pthread_mutex_unlock(&parser->mutex);
1787 for (i = 0; i < filter->source_count; ++i)
1789 struct parser_source *pin = filter->sources[i];
1791 if (!pin->pin.pin.peer)
1792 continue;
1794 pthread_cond_signal(&pin->wg_stream->event_cond);
1797 for (i = 0; i < filter->source_count; ++i)
1799 struct parser_source *pin = filter->sources[i];
1801 if (!pin->pin.pin.peer)
1802 continue;
1804 IMemAllocator_Decommit(pin->pin.pAllocator);
1806 WaitForSingleObject(pin->thread, INFINITE);
1807 CloseHandle(pin->thread);
1808 pin->thread = NULL;
1811 return S_OK;
1814 static const struct strmbase_filter_ops filter_ops =
1816 .filter_get_pin = parser_get_pin,
1817 .filter_destroy = parser_destroy,
1818 .filter_init_stream = parser_init_stream,
1819 .filter_cleanup_stream = parser_cleanup_stream,
1822 static inline struct parser *impl_from_strmbase_sink(struct strmbase_sink *iface)
1824 return CONTAINING_RECORD(iface, struct parser, sink);
1827 static HRESULT sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
1829 if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Stream))
1830 return S_OK;
1831 return S_FALSE;
1834 static HRESULT parser_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *pmt)
1836 struct parser *filter = impl_from_strmbase_sink(iface);
1837 HRESULT hr = S_OK;
1839 mark_wine_thread();
1841 filter->reader = NULL;
1842 if (FAILED(hr = IPin_QueryInterface(peer, &IID_IAsyncReader, (void **)&filter->reader)))
1843 return hr;
1845 if (FAILED(hr = GST_Connect(filter, peer)))
1846 goto err;
1848 return S_OK;
1849 err:
1850 GST_RemoveOutputPins(filter);
1851 IAsyncReader_Release(filter->reader);
1852 filter->reader = NULL;
1853 return hr;
1856 static void parser_sink_disconnect(struct strmbase_sink *iface)
1858 struct parser *filter = impl_from_strmbase_sink(iface);
1860 mark_wine_thread();
1862 GST_RemoveOutputPins(filter);
1864 IAsyncReader_Release(filter->reader);
1865 filter->reader = NULL;
1868 static const struct strmbase_sink_ops sink_ops =
1870 .base.pin_query_accept = sink_query_accept,
1871 .sink_connect = parser_sink_connect,
1872 .sink_disconnect = parser_sink_disconnect,
1875 static BOOL decodebin_parser_init_gst(struct parser *filter)
1877 GstElement *element = gst_element_factory_make("decodebin", NULL);
1878 struct wg_parser *parser = filter->wg_parser;
1879 int ret;
1881 if (!element)
1883 ERR("Failed to create decodebin; are %u-bit GStreamer \"base\" plugins installed?\n",
1884 8 * (int)sizeof(void*));
1885 return FALSE;
1888 gst_bin_add(GST_BIN(parser->container), element);
1890 g_signal_connect(element, "pad-added", G_CALLBACK(existing_new_pad_wrapper), filter);
1891 g_signal_connect(element, "pad-removed", G_CALLBACK(removed_decoded_pad), filter);
1892 g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_blacklist), filter);
1893 g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads), filter);
1895 parser->their_sink = gst_element_get_static_pad(element, "sink");
1897 pthread_mutex_lock(&parser->mutex);
1898 parser->no_more_pads = parser->error = false;
1899 pthread_mutex_unlock(&parser->mutex);
1901 if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
1903 ERR("Failed to link pads, error %d.\n", ret);
1904 return FALSE;
1907 gst_element_set_state(parser->container, GST_STATE_PAUSED);
1908 ret = gst_element_get_state(parser->container, NULL, NULL, -1);
1909 if (ret == GST_STATE_CHANGE_FAILURE)
1911 ERR("Failed to play stream.\n");
1912 return FALSE;
1915 pthread_mutex_lock(&parser->mutex);
1916 while (!parser->no_more_pads && !parser->error)
1917 pthread_cond_wait(&parser->init_cond, &parser->mutex);
1918 if (parser->error)
1920 pthread_mutex_unlock(&parser->mutex);
1921 return FALSE;
1923 pthread_mutex_unlock(&parser->mutex);
1924 return TRUE;
1927 static HRESULT decodebin_parser_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE *mt)
1929 /* At least make sure we can convert it to GstCaps. */
1930 GstCaps *caps = amt_to_gst_caps(mt);
1932 if (!caps)
1933 return S_FALSE;
1934 gst_caps_unref(caps);
1935 return S_OK;
1938 static HRESULT decodebin_parser_source_get_media_type(struct parser_source *pin,
1939 unsigned int index, AM_MEDIA_TYPE *mt)
1941 struct wg_parser_stream *stream = pin->wg_stream;
1942 const GstCaps *caps = stream->caps;
1943 const GstStructure *structure;
1944 const char *type;
1946 static const GstVideoFormat video_formats[] =
1948 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
1949 * YUV color space, and it's generally much less expensive for
1950 * videoconvert to do YUV -> YUV transformations. */
1951 GST_VIDEO_FORMAT_AYUV,
1952 GST_VIDEO_FORMAT_I420,
1953 GST_VIDEO_FORMAT_YV12,
1954 GST_VIDEO_FORMAT_YUY2,
1955 GST_VIDEO_FORMAT_UYVY,
1956 GST_VIDEO_FORMAT_YVYU,
1957 GST_VIDEO_FORMAT_NV12,
1958 GST_VIDEO_FORMAT_BGRA,
1959 GST_VIDEO_FORMAT_BGRx,
1960 GST_VIDEO_FORMAT_BGR,
1961 GST_VIDEO_FORMAT_RGB16,
1962 GST_VIDEO_FORMAT_RGB15,
1965 assert(caps); /* We shouldn't be able to get here if caps haven't been set. */
1966 structure = gst_caps_get_structure(caps, 0);
1967 type = gst_structure_get_name(structure);
1969 memset(mt, 0, sizeof(AM_MEDIA_TYPE));
1971 if (amt_from_gst_caps(caps, mt))
1973 if (!index--)
1974 return S_OK;
1975 FreeMediaType(mt);
1978 if (!strcmp(type, "video/x-raw") && index < ARRAY_SIZE(video_formats))
1980 gint width, height, fps_n, fps_d;
1981 GstVideoInfo info;
1983 gst_structure_get_int(structure, "width", &width);
1984 gst_structure_get_int(structure, "height", &height);
1985 gst_video_info_set_format(&info, video_formats[index], width, height);
1986 if (gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d) && fps_n)
1988 info.fps_n = fps_n;
1989 info.fps_d = fps_d;
1991 if (!amt_from_gst_video_info(&info, mt))
1992 return E_OUTOFMEMORY;
1993 return S_OK;
1995 else if (!strcmp(type, "audio/x-raw") && !index)
1997 GstAudioInfo info;
1998 gint rate;
2000 gst_structure_get_int(structure, "rate", &rate);
2001 gst_audio_info_set_format(&info, GST_AUDIO_FORMAT_S16LE, rate, 2, NULL);
2002 if (!amt_from_gst_audio_info(&info, mt))
2003 return E_OUTOFMEMORY;
2004 return S_OK;
2007 return VFW_S_NO_MORE_ITEMS;
2010 static BOOL parser_init_gstreamer(void)
2012 if (!init_gstreamer())
2013 return FALSE;
2014 GST_DEBUG_CATEGORY_INIT(wine, "WINE", GST_DEBUG_FG_RED, "Wine GStreamer support");
2015 return TRUE;
2018 static struct wg_parser *wg_parser_create(void)
2020 struct wg_parser *parser;
2022 if (!(parser = calloc(1, sizeof(*parser))))
2023 return NULL;
2025 pthread_mutex_init(&parser->mutex, NULL);
2026 pthread_cond_init(&parser->init_cond, NULL);
2027 pthread_cond_init(&parser->read_cond, NULL);
2028 pthread_cond_init(&parser->read_done_cond, NULL);
2029 parser->flushing = true;
2031 TRACE("Created winegstreamer parser %p.\n", parser);
2032 return parser;
2035 HRESULT decodebin_parser_create(IUnknown *outer, IUnknown **out)
2037 struct parser *object;
2039 if (!parser_init_gstreamer())
2040 return E_FAIL;
2042 mark_wine_thread();
2044 if (!(object = heap_alloc_zero(sizeof(*object))))
2045 return E_OUTOFMEMORY;
2047 if (!(object->wg_parser = wg_parser_create()))
2049 heap_free(object);
2050 return E_OUTOFMEMORY;
2053 strmbase_filter_init(&object->filter, outer, &CLSID_decodebin_parser, &filter_ops);
2054 strmbase_sink_init(&object->sink, &object->filter, wcsInputPinName, &sink_ops, NULL);
2056 object->init_gst = decodebin_parser_init_gst;
2057 object->source_query_accept = decodebin_parser_source_query_accept;
2058 object->source_get_media_type = decodebin_parser_source_get_media_type;
2060 TRACE("Created GStreamer demuxer %p.\n", object);
2061 *out = &object->filter.IUnknown_inner;
2062 return S_OK;
2065 static struct parser *impl_from_IAMStreamSelect(IAMStreamSelect *iface)
2067 return CONTAINING_RECORD(iface, struct parser, IAMStreamSelect_iface);
2070 static HRESULT WINAPI stream_select_QueryInterface(IAMStreamSelect *iface, REFIID iid, void **out)
2072 struct parser *filter = impl_from_IAMStreamSelect(iface);
2073 return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out);
2076 static ULONG WINAPI stream_select_AddRef(IAMStreamSelect *iface)
2078 struct parser *filter = impl_from_IAMStreamSelect(iface);
2079 return IUnknown_AddRef(filter->filter.outer_unk);
2082 static ULONG WINAPI stream_select_Release(IAMStreamSelect *iface)
2084 struct parser *filter = impl_from_IAMStreamSelect(iface);
2085 return IUnknown_Release(filter->filter.outer_unk);
2088 static HRESULT WINAPI stream_select_Count(IAMStreamSelect *iface, DWORD *count)
2090 FIXME("iface %p, count %p, stub!\n", iface, count);
2091 return E_NOTIMPL;
2094 static HRESULT WINAPI stream_select_Info(IAMStreamSelect *iface, LONG index,
2095 AM_MEDIA_TYPE **mt, DWORD *flags, LCID *lcid, DWORD *group, WCHAR **name,
2096 IUnknown **object, IUnknown **unknown)
2098 FIXME("iface %p, index %d, mt %p, flags %p, lcid %p, group %p, name %p, object %p, unknown %p, stub!\n",
2099 iface, index, mt, flags, lcid, group, name, object, unknown);
2100 return E_NOTIMPL;
2103 static HRESULT WINAPI stream_select_Enable(IAMStreamSelect *iface, LONG index, DWORD flags)
2105 FIXME("iface %p, index %d, flags %#x, stub!\n", iface, index, flags);
2106 return E_NOTIMPL;
2109 static const IAMStreamSelectVtbl stream_select_vtbl =
2111 stream_select_QueryInterface,
2112 stream_select_AddRef,
2113 stream_select_Release,
2114 stream_select_Count,
2115 stream_select_Info,
2116 stream_select_Enable,
2119 static HRESULT WINAPI GST_ChangeCurrent(IMediaSeeking *iface)
2121 struct parser_source *This = impl_from_IMediaSeeking(iface);
2122 TRACE("(%p)\n", This);
2123 return S_OK;
2126 static HRESULT WINAPI GST_ChangeStop(IMediaSeeking *iface)
2128 struct parser_source *This = impl_from_IMediaSeeking(iface);
2129 TRACE("(%p)\n", This);
2130 return S_OK;
2133 static HRESULT WINAPI GST_ChangeRate(IMediaSeeking *iface)
2135 struct parser_source *This = impl_from_IMediaSeeking(iface);
2136 struct wg_parser_stream *stream = This->wg_stream;
2137 GstEvent *ev = gst_event_new_seek(This->seek.dRate, GST_FORMAT_TIME, 0, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1);
2138 TRACE("(%p) New rate %g\n", This, This->seek.dRate);
2139 mark_wine_thread();
2140 gst_pad_push_event(stream->my_sink, ev);
2141 return S_OK;
2144 static HRESULT WINAPI GST_Seeking_QueryInterface(IMediaSeeking *iface, REFIID riid, void **ppv)
2146 struct parser_source *This = impl_from_IMediaSeeking(iface);
2147 return IPin_QueryInterface(&This->pin.pin.IPin_iface, riid, ppv);
2150 static ULONG WINAPI GST_Seeking_AddRef(IMediaSeeking *iface)
2152 struct parser_source *This = impl_from_IMediaSeeking(iface);
2153 return IPin_AddRef(&This->pin.pin.IPin_iface);
2156 static ULONG WINAPI GST_Seeking_Release(IMediaSeeking *iface)
2158 struct parser_source *This = impl_from_IMediaSeeking(iface);
2159 return IPin_Release(&This->pin.pin.IPin_iface);
2162 static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface,
2163 LONGLONG *current, DWORD current_flags, LONGLONG *stop, DWORD stop_flags)
2165 GstSeekType current_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET;
2166 struct parser_source *pin = impl_from_IMediaSeeking(iface);
2167 struct wg_parser_stream *stream = pin->wg_stream;
2168 struct parser *filter = impl_from_strmbase_filter(pin->pin.pin.filter);
2169 struct wg_parser *parser = filter->wg_parser;
2170 GstSeekFlags flags = 0;
2171 HRESULT hr = S_OK;
2172 int i;
2174 TRACE("pin %p, current %s, current_flags %#x, stop %s, stop_flags %#x.\n",
2175 pin, current ? debugstr_time(*current) : "<null>", current_flags,
2176 stop ? debugstr_time(*stop) : "<null>", stop_flags);
2178 mark_wine_thread();
2180 if (pin->pin.pin.filter->state == State_Stopped)
2182 SourceSeekingImpl_SetPositions(iface, current, current_flags, stop, stop_flags);
2183 return S_OK;
2186 if (!(current_flags & AM_SEEKING_NoFlush))
2188 pthread_mutex_lock(&parser->mutex);
2189 parser->flushing = true;
2190 pthread_mutex_unlock(&parser->mutex);
2192 for (i = 0; i < filter->source_count; ++i)
2194 if (filter->sources[i]->pin.pin.peer)
2196 pthread_cond_signal(&stream->event_cond);
2197 IPin_BeginFlush(filter->sources[i]->pin.pin.peer);
2201 if (filter->reader)
2202 IAsyncReader_BeginFlush(filter->reader);
2205 /* Acquire the flushing locks. This blocks the streaming threads, and
2206 * ensures the seek is serialized between flushes. */
2207 for (i = 0; i < filter->source_count; ++i)
2209 if (filter->sources[i]->pin.pin.peer)
2210 EnterCriticalSection(&pin->flushing_cs);
2213 SourceSeekingImpl_SetPositions(iface, current, current_flags, stop, stop_flags);
2215 if (current_flags & AM_SEEKING_SeekToKeyFrame)
2216 flags |= GST_SEEK_FLAG_KEY_UNIT;
2217 if (current_flags & AM_SEEKING_Segment)
2218 flags |= GST_SEEK_FLAG_SEGMENT;
2219 if (!(current_flags & AM_SEEKING_NoFlush))
2220 flags |= GST_SEEK_FLAG_FLUSH;
2222 if ((current_flags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
2223 current_type = GST_SEEK_TYPE_NONE;
2224 if ((stop_flags & AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
2225 stop_type = GST_SEEK_TYPE_NONE;
2227 if (!gst_pad_push_event(stream->my_sink, gst_event_new_seek(pin->seek.dRate, GST_FORMAT_TIME, flags,
2228 current_type, pin->seek.llCurrent * 100, stop_type, pin->seek.llStop * 100)))
2230 ERR("Failed to seek (current %s, stop %s).\n",
2231 debugstr_time(pin->seek.llCurrent), debugstr_time(pin->seek.llStop));
2232 hr = E_FAIL;
2235 if (!(current_flags & AM_SEEKING_NoFlush))
2237 pthread_mutex_lock(&parser->mutex);
2238 parser->flushing = false;
2239 pthread_mutex_unlock(&parser->mutex);
2241 for (i = 0; i < filter->source_count; ++i)
2243 if (filter->sources[i]->pin.pin.peer)
2244 IPin_EndFlush(filter->sources[i]->pin.pin.peer);
2247 if (filter->reader)
2248 IAsyncReader_EndFlush(filter->reader);
2251 /* Release the flushing locks. */
2252 for (i = filter->source_count - 1; i >= 0; --i)
2254 if (filter->sources[i]->pin.pin.peer)
2255 LeaveCriticalSection(&pin->flushing_cs);
2258 return hr;
2261 static const IMediaSeekingVtbl GST_Seeking_Vtbl =
2263 GST_Seeking_QueryInterface,
2264 GST_Seeking_AddRef,
2265 GST_Seeking_Release,
2266 SourceSeekingImpl_GetCapabilities,
2267 SourceSeekingImpl_CheckCapabilities,
2268 SourceSeekingImpl_IsFormatSupported,
2269 SourceSeekingImpl_QueryPreferredFormat,
2270 SourceSeekingImpl_GetTimeFormat,
2271 SourceSeekingImpl_IsUsingTimeFormat,
2272 SourceSeekingImpl_SetTimeFormat,
2273 SourceSeekingImpl_GetDuration,
2274 SourceSeekingImpl_GetStopPosition,
2275 SourceSeekingImpl_GetCurrentPosition,
2276 SourceSeekingImpl_ConvertTimeFormat,
2277 GST_Seeking_SetPositions,
2278 SourceSeekingImpl_GetPositions,
2279 SourceSeekingImpl_GetAvailable,
2280 SourceSeekingImpl_SetRate,
2281 SourceSeekingImpl_GetRate,
2282 SourceSeekingImpl_GetPreroll
2285 static inline struct parser_source *impl_from_IQualityControl( IQualityControl *iface )
2287 return CONTAINING_RECORD(iface, struct parser_source, IQualityControl_iface);
2290 static HRESULT WINAPI GST_QualityControl_QueryInterface(IQualityControl *iface, REFIID riid, void **ppv)
2292 struct parser_source *pin = impl_from_IQualityControl(iface);
2293 return IPin_QueryInterface(&pin->pin.pin.IPin_iface, riid, ppv);
2296 static ULONG WINAPI GST_QualityControl_AddRef(IQualityControl *iface)
2298 struct parser_source *pin = impl_from_IQualityControl(iface);
2299 return IPin_AddRef(&pin->pin.pin.IPin_iface);
2302 static ULONG WINAPI GST_QualityControl_Release(IQualityControl *iface)
2304 struct parser_source *pin = impl_from_IQualityControl(iface);
2305 return IPin_Release(&pin->pin.pin.IPin_iface);
2308 static HRESULT WINAPI GST_QualityControl_Notify(IQualityControl *iface, IBaseFilter *sender, Quality q)
2310 struct parser_source *pin = impl_from_IQualityControl(iface);
2311 struct wg_parser_stream *stream = pin->wg_stream;
2312 GstQOSType type = GST_QOS_TYPE_OVERFLOW;
2313 GstClockTime timestamp;
2314 GstClockTimeDiff diff;
2315 GstEvent *event;
2317 TRACE("pin %p, sender %p, type %s, proportion %u, late %s, timestamp %s.\n",
2318 pin, sender, q.Type == Famine ? "Famine" : "Flood", q.Proportion,
2319 debugstr_time(q.Late), debugstr_time(q.TimeStamp));
2321 mark_wine_thread();
2323 /* GST_QOS_TYPE_OVERFLOW is also used for buffers that arrive on time, but
2324 * DirectShow filters might use Famine, so check that there actually is an
2325 * underrun. */
2326 if (q.Type == Famine && q.Proportion < 1000)
2327 type = GST_QOS_TYPE_UNDERFLOW;
2329 /* DirectShow filters sometimes pass negative timestamps (Audiosurf uses the
2330 * current time instead of the time of the last buffer). GstClockTime is
2331 * unsigned, so clamp it to 0. */
2332 timestamp = max(q.TimeStamp * 100, 0);
2334 /* The documentation specifies that timestamp + diff must be nonnegative. */
2335 diff = q.Late * 100;
2336 if (diff < 0 && timestamp < (GstClockTime)-diff)
2337 diff = -timestamp;
2339 /* DirectShow "Proportion" describes what percentage of buffers the upstream
2340 * filter should keep (i.e. dropping the rest). If frames are late, the
2341 * proportion will be less than 1. For example, a proportion of 500 means
2342 * that the element should drop half of its frames, essentially because
2343 * frames are taking twice as long as they should to arrive.
2345 * GStreamer "proportion" is the inverse of this; it describes how much
2346 * faster the upstream element should produce frames. I.e. if frames are
2347 * taking twice as long as they should to arrive, we want the frames to be
2348 * decoded twice as fast, and so we pass 2.0 to GStreamer. */
2350 if (!q.Proportion)
2352 WARN("Ignoring quality message with zero proportion.\n");
2353 return S_OK;
2356 if (!(event = gst_event_new_qos(type, 1000.0 / q.Proportion, diff, timestamp)))
2357 ERR("Failed to create QOS event.\n");
2359 gst_pad_push_event(stream->my_sink, event);
2361 return S_OK;
2364 static HRESULT WINAPI GST_QualityControl_SetSink(IQualityControl *iface, IQualityControl *tonotify)
2366 struct parser_source *pin = impl_from_IQualityControl(iface);
2367 TRACE("(%p)->(%p)\n", pin, pin);
2368 /* Do nothing */
2369 return S_OK;
2372 static const IQualityControlVtbl GSTOutPin_QualityControl_Vtbl = {
2373 GST_QualityControl_QueryInterface,
2374 GST_QualityControl_AddRef,
2375 GST_QualityControl_Release,
2376 GST_QualityControl_Notify,
2377 GST_QualityControl_SetSink
2380 static inline struct parser_source *impl_source_from_IPin(IPin *iface)
2382 return CONTAINING_RECORD(iface, struct parser_source, pin.pin.IPin_iface);
2385 static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
2387 struct parser_source *pin = impl_source_from_IPin(&iface->IPin_iface);
2389 if (IsEqualGUID(iid, &IID_IMediaSeeking))
2390 *out = &pin->seek.IMediaSeeking_iface;
2391 else if (IsEqualGUID(iid, &IID_IQualityControl))
2392 *out = &pin->IQualityControl_iface;
2393 else
2394 return E_NOINTERFACE;
2396 IUnknown_AddRef((IUnknown *)*out);
2397 return S_OK;
2400 static HRESULT source_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
2402 struct parser_source *pin = impl_source_from_IPin(&iface->IPin_iface);
2403 struct parser *filter = impl_from_strmbase_filter(iface->filter);
2404 return filter->source_query_accept(pin, mt);
2407 static HRESULT source_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt)
2409 struct parser_source *pin = impl_source_from_IPin(&iface->IPin_iface);
2410 struct parser *filter = impl_from_strmbase_filter(iface->filter);
2411 return filter->source_get_media_type(pin, index, mt);
2414 static HRESULT WINAPI GSTOutPin_DecideBufferSize(struct strmbase_source *iface,
2415 IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props)
2417 struct parser_source *pin = impl_source_from_IPin(&iface->pin.IPin_iface);
2418 struct wg_parser_stream *stream = pin->wg_stream;
2419 unsigned int buffer_size = 16384;
2420 ALLOCATOR_PROPERTIES ret_props;
2422 if (IsEqualGUID(&pin->pin.pin.mt.formattype, &FORMAT_VideoInfo))
2424 VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)pin->pin.pin.mt.pbFormat;
2425 buffer_size = format->bmiHeader.biSizeImage;
2427 gst_util_set_object_arg(G_OBJECT(stream->flip), "method",
2428 (format->bmiHeader.biCompression == BI_RGB
2429 || format->bmiHeader.biCompression == BI_BITFIELDS) ? "vertical-flip" : "none");
2431 else if (IsEqualGUID(&pin->pin.pin.mt.formattype, &FORMAT_WaveFormatEx)
2432 && (IsEqualGUID(&pin->pin.pin.mt.subtype, &MEDIASUBTYPE_PCM)
2433 || IsEqualGUID(&pin->pin.pin.mt.subtype, &MEDIASUBTYPE_IEEE_FLOAT)))
2435 WAVEFORMATEX *format = (WAVEFORMATEX *)pin->pin.pin.mt.pbFormat;
2436 buffer_size = format->nAvgBytesPerSec;
2439 stream->enabled = true;
2441 gst_pad_push_event(stream->my_sink, gst_event_new_reconfigure());
2442 /* We do need to drop any buffers that might have been sent with the old
2443 * caps, but this will be handled in parser_init_stream(). */
2445 props->cBuffers = max(props->cBuffers, 1);
2446 props->cbBuffer = max(props->cbBuffer, buffer_size);
2447 props->cbAlign = max(props->cbAlign, 1);
2448 return IMemAllocator_SetProperties(allocator, props, &ret_props);
2451 static void source_disconnect(struct strmbase_source *iface)
2453 struct parser_source *pin = impl_source_from_IPin(&iface->pin.IPin_iface);
2454 struct wg_parser_stream *stream = pin->wg_stream;
2456 stream->enabled = false;
2459 static void free_source_pin(struct parser_source *pin)
2461 struct wg_parser_stream *stream = pin->wg_stream;
2463 if (pin->pin.pin.peer)
2465 if (SUCCEEDED(IMemAllocator_Decommit(pin->pin.pAllocator)))
2466 IPin_Disconnect(pin->pin.pin.peer);
2467 IPin_Disconnect(&pin->pin.pin.IPin_iface);
2470 if (stream->their_src)
2472 if (stream->post_sink)
2474 gst_pad_unlink(stream->their_src, stream->post_sink);
2475 gst_pad_unlink(stream->post_src, stream->my_sink);
2476 gst_object_unref(stream->post_src);
2477 gst_object_unref(stream->post_sink);
2478 stream->post_src = stream->post_sink = NULL;
2480 else
2481 gst_pad_unlink(stream->their_src, stream->my_sink);
2482 gst_object_unref(stream->their_src);
2484 gst_object_unref(stream->my_sink);
2485 gst_segment_free(stream->segment);
2487 pthread_cond_destroy(&stream->event_cond);
2488 pthread_cond_destroy(&stream->event_empty_cond);
2490 free(stream);
2492 pin->flushing_cs.DebugInfo->Spare[0] = 0;
2493 DeleteCriticalSection(&pin->flushing_cs);
2495 strmbase_seeking_cleanup(&pin->seek);
2496 strmbase_source_cleanup(&pin->pin);
2497 heap_free(pin);
2500 static const struct strmbase_source_ops source_ops =
2502 .base.pin_query_interface = source_query_interface,
2503 .base.pin_query_accept = source_query_accept,
2504 .base.pin_get_media_type = source_get_media_type,
2505 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
2506 .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator,
2507 .pfnDecideBufferSize = GSTOutPin_DecideBufferSize,
2508 .source_disconnect = source_disconnect,
2511 static struct parser_source *create_pin(struct parser *filter, const WCHAR *name)
2513 struct parser_source *pin, **new_array;
2514 struct wg_parser_stream *stream;
2515 char pad_name[19];
2517 if (!(new_array = heap_realloc(filter->sources, (filter->source_count + 1) * sizeof(*new_array))))
2518 return NULL;
2519 filter->sources = new_array;
2521 if (!(pin = heap_alloc_zero(sizeof(*pin))))
2522 return NULL;
2524 if (!(stream = calloc(1, sizeof(*stream))))
2526 heap_free(pin);
2527 return NULL;
2529 pin->wg_stream = stream;
2531 strmbase_source_init(&pin->pin, &filter->filter, name, &source_ops);
2532 stream->segment = gst_segment_new();
2533 gst_segment_init(stream->segment, GST_FORMAT_TIME);
2534 pin->IQualityControl_iface.lpVtbl = &GSTOutPin_QualityControl_Vtbl;
2535 strmbase_seeking_init(&pin->seek, &GST_Seeking_Vtbl, GST_ChangeStop,
2536 GST_ChangeCurrent, GST_ChangeRate);
2537 pthread_cond_init(&stream->event_cond, NULL);
2538 pthread_cond_init(&stream->event_empty_cond, NULL);
2539 BaseFilterImpl_IncrementPinVersion(&filter->filter);
2541 InitializeCriticalSection(&pin->flushing_cs);
2542 pin->flushing_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": pin.flushing_cs");
2544 sprintf(pad_name, "qz_sink_%u", filter->source_count);
2545 stream->my_sink = gst_pad_new(pad_name, GST_PAD_SINK);
2546 gst_pad_set_element_private(stream->my_sink, pin);
2547 gst_pad_set_chain_function(stream->my_sink, got_data_sink);
2548 gst_pad_set_event_function(stream->my_sink, event_sink);
2549 gst_pad_set_query_function(stream->my_sink, query_sink_wrapper);
2551 filter->sources[filter->source_count++] = pin;
2552 return pin;
2555 static HRESULT GST_RemoveOutputPins(struct parser *This)
2557 struct wg_parser *parser = This->wg_parser;
2558 unsigned int i;
2560 TRACE("(%p)\n", This);
2561 mark_wine_thread();
2563 if (!parser->container)
2564 return S_OK;
2566 /* Unblock all of our streams. */
2567 pthread_mutex_lock(&parser->mutex);
2568 for (i = 0; i < This->source_count; ++i)
2570 This->sources[i]->wg_stream->flushing = true;
2571 pthread_cond_signal(&This->sources[i]->wg_stream->event_empty_cond);
2573 pthread_mutex_unlock(&parser->mutex);
2575 gst_element_set_state(parser->container, GST_STATE_NULL);
2576 gst_pad_unlink(parser->my_src, parser->their_sink);
2577 gst_object_unref(parser->my_src);
2578 gst_object_unref(parser->their_sink);
2579 parser->my_src = parser->their_sink = NULL;
2581 /* read_thread() needs to stay alive to service any read requests GStreamer
2582 * sends, so we can only shut it down after GStreamer stops. */
2583 This->sink_connected = false;
2584 pthread_mutex_lock(&parser->mutex);
2585 parser->sink_connected = false;
2586 pthread_mutex_unlock(&parser->mutex);
2587 pthread_cond_signal(&parser->read_cond);
2588 WaitForSingleObject(This->read_thread, INFINITE);
2589 CloseHandle(This->read_thread);
2591 for (i = 0; i < This->source_count; ++i)
2592 free_source_pin(This->sources[i]);
2594 This->source_count = 0;
2595 heap_free(This->sources);
2596 This->sources = NULL;
2597 gst_element_set_bus(parser->container, NULL);
2598 gst_object_unref(parser->container);
2599 parser->container = NULL;
2600 BaseFilterImpl_IncrementPinVersion(&This->filter);
2601 return S_OK;
2604 void perform_cb_gstdemux(struct cb_data *cbdata)
2606 switch(cbdata->type)
2608 case EXISTING_NEW_PAD:
2610 struct pad_added_data *data = &cbdata->u.pad_added_data;
2611 existing_new_pad(data->element, data->pad, data->user);
2612 break;
2614 case QUERY_SINK:
2616 struct query_sink_data *data = &cbdata->u.query_sink_data;
2617 cbdata->u.query_sink_data.ret = query_sink(data->pad, data->parent,
2618 data->query);
2619 break;
2621 default:
2623 assert(0);
2628 static BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TYPE *b)
2630 return IsEqualGUID(&a->majortype, &b->majortype)
2631 && IsEqualGUID(&a->subtype, &b->subtype)
2632 && IsEqualGUID(&a->formattype, &b->formattype)
2633 && a->cbFormat == b->cbFormat
2634 && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat);
2637 static HRESULT wave_parser_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
2639 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Stream))
2640 return S_FALSE;
2641 if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WAVE))
2642 return S_OK;
2643 if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_AU) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_AIFF))
2644 FIXME("AU and AIFF files are not yet supported.\n");
2645 return S_FALSE;
2648 static const struct strmbase_sink_ops wave_parser_sink_ops =
2650 .base.pin_query_accept = wave_parser_sink_query_accept,
2651 .sink_connect = parser_sink_connect,
2652 .sink_disconnect = parser_sink_disconnect,
2655 static BOOL wave_parser_init_gst(struct parser *filter)
2657 static const WCHAR source_name[] = {'o','u','t','p','u','t',0};
2658 struct wg_parser *parser = filter->wg_parser;
2659 struct wg_parser_stream *stream;
2660 struct parser_source *pin;
2661 GstElement *element;
2662 int ret;
2664 if (!(element = gst_element_factory_make("wavparse", NULL)))
2666 ERR("Failed to create wavparse; are %u-bit GStreamer \"good\" plugins installed?\n",
2667 8 * (int)sizeof(void*));
2668 return FALSE;
2671 gst_bin_add(GST_BIN(parser->container), element);
2673 parser->their_sink = gst_element_get_static_pad(element, "sink");
2674 if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
2676 ERR("Failed to link sink pads, error %d.\n", ret);
2677 return FALSE;
2680 if (!(pin = create_pin(filter, source_name)))
2681 return FALSE;
2682 stream = pin->wg_stream;
2683 stream->their_src = gst_element_get_static_pad(element, "src");
2684 gst_object_ref(stream->their_src);
2685 if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0)
2687 ERR("Failed to link source pads, error %d.\n", ret);
2688 return FALSE;
2691 gst_pad_set_active(stream->my_sink, 1);
2692 gst_element_set_state(parser->container, GST_STATE_PAUSED);
2693 ret = gst_element_get_state(parser->container, NULL, NULL, -1);
2694 if (ret == GST_STATE_CHANGE_FAILURE)
2696 ERR("Failed to play stream.\n");
2697 return FALSE;
2700 return TRUE;
2703 static HRESULT wave_parser_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE *mt)
2705 struct wg_parser_stream *stream = pin->wg_stream;
2706 AM_MEDIA_TYPE pad_mt;
2707 HRESULT hr;
2709 if (!amt_from_gst_caps(stream->caps, &pad_mt))
2710 return E_OUTOFMEMORY;
2711 hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE;
2712 FreeMediaType(&pad_mt);
2713 return hr;
2716 static HRESULT wave_parser_source_get_media_type(struct parser_source *pin,
2717 unsigned int index, AM_MEDIA_TYPE *mt)
2719 struct wg_parser_stream *stream = pin->wg_stream;
2721 if (index > 0)
2722 return VFW_S_NO_MORE_ITEMS;
2723 if (!amt_from_gst_caps(stream->caps, mt))
2724 return E_OUTOFMEMORY;
2725 return S_OK;
2728 HRESULT wave_parser_create(IUnknown *outer, IUnknown **out)
2730 static const WCHAR sink_name[] = {'i','n','p','u','t',' ','p','i','n',0};
2731 struct parser *object;
2733 if (!parser_init_gstreamer())
2734 return E_FAIL;
2736 mark_wine_thread();
2738 if (!(object = heap_alloc_zero(sizeof(*object))))
2739 return E_OUTOFMEMORY;
2741 if (!(object->wg_parser = wg_parser_create()))
2743 heap_free(object);
2744 return E_OUTOFMEMORY;
2747 strmbase_filter_init(&object->filter, outer, &CLSID_WAVEParser, &filter_ops);
2748 strmbase_sink_init(&object->sink, &object->filter, sink_name, &wave_parser_sink_ops, NULL);
2749 object->init_gst = wave_parser_init_gst;
2750 object->source_query_accept = wave_parser_source_query_accept;
2751 object->source_get_media_type = wave_parser_source_get_media_type;
2753 TRACE("Created WAVE parser %p.\n", object);
2754 *out = &object->filter.IUnknown_inner;
2755 return S_OK;
2758 static HRESULT avi_splitter_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
2760 if (IsEqualGUID(&mt->majortype, &MEDIATYPE_Stream)
2761 && IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_Avi))
2762 return S_OK;
2763 return S_FALSE;
2766 static const struct strmbase_sink_ops avi_splitter_sink_ops =
2768 .base.pin_query_accept = avi_splitter_sink_query_accept,
2769 .sink_connect = parser_sink_connect,
2770 .sink_disconnect = parser_sink_disconnect,
2773 static BOOL avi_splitter_init_gst(struct parser *filter)
2775 GstElement *element = gst_element_factory_make("avidemux", NULL);
2776 struct wg_parser *parser = filter->wg_parser;
2777 int ret;
2779 if (!element)
2781 ERR("Failed to create avidemux; are %u-bit GStreamer \"good\" plugins installed?\n",
2782 8 * (int)sizeof(void*));
2783 return FALSE;
2786 gst_bin_add(GST_BIN(parser->container), element);
2788 g_signal_connect(element, "pad-added", G_CALLBACK(existing_new_pad_wrapper), filter);
2789 g_signal_connect(element, "pad-removed", G_CALLBACK(removed_decoded_pad), filter);
2790 g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads), filter);
2792 parser->their_sink = gst_element_get_static_pad(element, "sink");
2794 pthread_mutex_lock(&parser->mutex);
2795 parser->no_more_pads = parser->error = false;
2796 pthread_mutex_unlock(&parser->mutex);
2798 if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
2800 ERR("Failed to link pads, error %d.\n", ret);
2801 return FALSE;
2804 gst_element_set_state(parser->container, GST_STATE_PAUSED);
2805 ret = gst_element_get_state(parser->container, NULL, NULL, -1);
2806 if (ret == GST_STATE_CHANGE_FAILURE)
2808 ERR("Failed to play stream.\n");
2809 return FALSE;
2812 pthread_mutex_lock(&parser->mutex);
2813 while (!parser->no_more_pads && !parser->error)
2814 pthread_cond_wait(&parser->init_cond, &parser->mutex);
2815 if (parser->error)
2817 pthread_mutex_unlock(&parser->mutex);
2818 return FALSE;
2820 pthread_mutex_unlock(&parser->mutex);
2821 return TRUE;
2824 static HRESULT avi_splitter_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE *mt)
2826 struct wg_parser_stream *stream = pin->wg_stream;
2827 AM_MEDIA_TYPE pad_mt;
2828 HRESULT hr;
2830 if (!amt_from_gst_caps(stream->caps, &pad_mt))
2831 return E_OUTOFMEMORY;
2832 hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE;
2833 FreeMediaType(&pad_mt);
2834 return hr;
2837 static HRESULT avi_splitter_source_get_media_type(struct parser_source *pin,
2838 unsigned int index, AM_MEDIA_TYPE *mt)
2840 struct wg_parser_stream *stream = pin->wg_stream;
2842 if (index > 0)
2843 return VFW_S_NO_MORE_ITEMS;
2844 if (!amt_from_gst_caps(stream->caps, mt))
2845 return E_OUTOFMEMORY;
2846 return S_OK;
2849 HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out)
2851 static const WCHAR sink_name[] = {'i','n','p','u','t',' ','p','i','n',0};
2852 struct parser *object;
2854 if (!parser_init_gstreamer())
2855 return E_FAIL;
2857 mark_wine_thread();
2859 if (!(object = heap_alloc_zero(sizeof(*object))))
2860 return E_OUTOFMEMORY;
2862 if (!(object->wg_parser = wg_parser_create()))
2864 heap_free(object);
2865 return E_OUTOFMEMORY;
2868 strmbase_filter_init(&object->filter, outer, &CLSID_AviSplitter, &filter_ops);
2869 strmbase_sink_init(&object->sink, &object->filter, sink_name, &avi_splitter_sink_ops, NULL);
2870 object->init_gst = avi_splitter_init_gst;
2871 object->source_query_accept = avi_splitter_source_query_accept;
2872 object->source_get_media_type = avi_splitter_source_get_media_type;
2874 TRACE("Created AVI splitter %p.\n", object);
2875 *out = &object->filter.IUnknown_inner;
2876 return S_OK;
2879 static HRESULT mpeg_splitter_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
2881 if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Stream))
2882 return S_FALSE;
2883 if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1Audio))
2884 return S_OK;
2885 if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1Video)
2886 || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1System)
2887 || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1VideoCD))
2888 FIXME("Unsupported subtype %s.\n", wine_dbgstr_guid(&mt->subtype));
2889 return S_FALSE;
2892 static const struct strmbase_sink_ops mpeg_splitter_sink_ops =
2894 .base.pin_query_accept = mpeg_splitter_sink_query_accept,
2895 .sink_connect = parser_sink_connect,
2896 .sink_disconnect = parser_sink_disconnect,
2899 static BOOL mpeg_splitter_init_gst(struct parser *filter)
2901 static const WCHAR source_name[] = {'A','u','d','i','o',0};
2902 struct wg_parser *parser = filter->wg_parser;
2903 struct wg_parser_stream *stream;
2904 struct parser_source *pin;
2905 GstElement *element;
2906 int ret;
2908 if (!(element = gst_element_factory_make("mpegaudioparse", NULL)))
2910 ERR("Failed to create mpegaudioparse; are %u-bit GStreamer \"good\" plugins installed?\n",
2911 8 * (int)sizeof(void*));
2912 return FALSE;
2915 gst_bin_add(GST_BIN(parser->container), element);
2917 parser->their_sink = gst_element_get_static_pad(element, "sink");
2918 if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0)
2920 ERR("Failed to link sink pads, error %d.\n", ret);
2921 return FALSE;
2924 if (!(pin = create_pin(filter, source_name)))
2925 return FALSE;
2926 stream = pin->wg_stream;
2927 gst_object_ref(stream->their_src = gst_element_get_static_pad(element, "src"));
2928 if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0)
2930 ERR("Failed to link source pads, error %d.\n", ret);
2931 return FALSE;
2934 gst_pad_set_active(stream->my_sink, 1);
2935 gst_element_set_state(parser->container, GST_STATE_PAUSED);
2936 ret = gst_element_get_state(parser->container, NULL, NULL, -1);
2937 if (ret == GST_STATE_CHANGE_FAILURE)
2939 ERR("Failed to play stream.\n");
2940 return FALSE;
2943 pthread_mutex_lock(&parser->mutex);
2944 while (!parser->has_duration && !parser->error && !stream->eos)
2945 pthread_cond_wait(&parser->init_cond, &parser->mutex);
2946 if (parser->error)
2948 pthread_mutex_unlock(&parser->mutex);
2949 return FALSE;
2951 pthread_mutex_unlock(&parser->mutex);
2952 return TRUE;
2955 static HRESULT mpeg_splitter_source_query_accept(struct parser_source *pin, const AM_MEDIA_TYPE *mt)
2957 struct wg_parser_stream *stream = pin->wg_stream;
2958 AM_MEDIA_TYPE pad_mt;
2959 HRESULT hr;
2961 if (!amt_from_gst_caps(stream->caps, &pad_mt))
2962 return E_OUTOFMEMORY;
2963 hr = compare_media_types(mt, &pad_mt) ? S_OK : S_FALSE;
2964 FreeMediaType(&pad_mt);
2965 return hr;
2968 static HRESULT mpeg_splitter_source_get_media_type(struct parser_source *pin,
2969 unsigned int index, AM_MEDIA_TYPE *mt)
2971 struct wg_parser_stream *stream = pin->wg_stream;
2973 if (index > 0)
2974 return VFW_S_NO_MORE_ITEMS;
2975 if (!amt_from_gst_caps(stream->caps, mt))
2976 return E_OUTOFMEMORY;
2977 return S_OK;
2980 static HRESULT mpeg_splitter_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
2982 struct parser *filter = impl_from_strmbase_filter(iface);
2984 if (IsEqualGUID(iid, &IID_IAMStreamSelect))
2986 *out = &filter->IAMStreamSelect_iface;
2987 IUnknown_AddRef((IUnknown *)*out);
2988 return S_OK;
2991 return E_NOINTERFACE;
2994 static const struct strmbase_filter_ops mpeg_splitter_ops =
2996 .filter_query_interface = mpeg_splitter_query_interface,
2997 .filter_get_pin = parser_get_pin,
2998 .filter_destroy = parser_destroy,
2999 .filter_init_stream = parser_init_stream,
3000 .filter_cleanup_stream = parser_cleanup_stream,
3003 HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out)
3005 static const WCHAR sink_name[] = {'I','n','p','u','t',0};
3006 struct parser *object;
3008 if (!parser_init_gstreamer())
3009 return E_FAIL;
3011 mark_wine_thread();
3013 if (!(object = heap_alloc_zero(sizeof(*object))))
3014 return E_OUTOFMEMORY;
3016 if (!(object->wg_parser = wg_parser_create()))
3018 heap_free(object);
3019 return E_OUTOFMEMORY;
3022 strmbase_filter_init(&object->filter, outer, &CLSID_MPEG1Splitter, &mpeg_splitter_ops);
3023 strmbase_sink_init(&object->sink, &object->filter, sink_name, &mpeg_splitter_sink_ops, NULL);
3024 object->IAMStreamSelect_iface.lpVtbl = &stream_select_vtbl;
3026 object->init_gst = mpeg_splitter_init_gst;
3027 object->source_query_accept = mpeg_splitter_source_query_accept;
3028 object->source_get_media_type = mpeg_splitter_source_get_media_type;
3029 object->enum_sink_first = TRUE;
3031 TRACE("Created MPEG-1 splitter %p.\n", object);
3032 *out = &object->filter.IUnknown_inner;
3033 return S_OK;