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
23 #include "gst_private.h"
24 #include "gst_guids.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
39 #include "wmcodecdsp.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}};
51 GstElement
*container
;
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
;
74 bool flushing
, sink_connected
;
77 enum wg_parser_event_type
79 WG_PARSER_EVENT_NONE
= 0,
80 WG_PARSER_EVENT_BUFFER
,
82 WG_PARSER_EVENT_SEGMENT
,
85 struct wg_parser_event
87 enum wg_parser_event_type type
;
93 uint64_t position
, stop
;
99 struct wg_parser_stream
101 GstPad
*their_src
, *post_sink
, *post_src
, *my_sink
;
106 pthread_cond_t event_cond
, event_empty_cond
;
107 struct wg_parser_event event
;
109 bool flushing
, eos
, enabled
;
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
;
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
131 bool streaming
, sink_connected
;
133 uint64_t next_pull_offset
;
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
);
144 struct strmbase_source pin
;
145 IQualityControl IQualityControl_iface
;
147 struct wg_parser_stream
*wg_stream
;
151 CRITICAL_SECTION flushing_cs
;
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
;
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
;
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)
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;
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
;
216 wfe
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
217 if (wfx
->nChannels
<= 2 && bpp
<= 16 && depth
== bpp
) {
218 wfx
->wFormatTag
= WAVE_FORMAT_PCM
;
220 amt
->cbFormat
= sizeof(WAVEFORMATEX
);
223 amt
->lSampleSize
= wfx
->nBlockAlign
= wfx
->nChannels
* wfx
->wBitsPerSample
/8;
224 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
228 static gboolean
amt_from_gst_video_info(const GstVideoInfo
*info
, AM_MEDIA_TYPE
*amt
)
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;
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;
259 case GST_VIDEO_FORMAT_BGRx
:
260 amt
->subtype
= MEDIASUBTYPE_RGB32
;
261 bih
->biBitCount
= 32;
263 case GST_VIDEO_FORMAT_BGR
:
264 amt
->subtype
= MEDIASUBTYPE_RGB24
;
265 bih
->biBitCount
= 24;
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
;
276 case GST_VIDEO_FORMAT_RGB15
:
277 amt
->subtype
= MEDIASUBTYPE_RGB555
;
278 bih
->biBitCount
= 16;
281 WARN("Cannot convert %s to a DirectShow type.\n", GST_VIDEO_INFO_NAME(info
));
286 amt
->subtype
= MEDIATYPE_Video
;
287 if (!(amt
->subtype
.Data1
= gst_video_format_to_fourcc(GST_VIDEO_INFO_FORMAT(info
))))
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
;
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
;
326 mt
->formattype
= FORMAT_WaveFormatEx
;
329 if (!gst_structure_get_int(structure
, "layer", &layer
))
331 WARN("Missing 'layer' value.\n");
334 if (!gst_structure_get_int(structure
, "channels", &channels
))
336 WARN("Missing 'channels' value.\n");
339 if (!gst_structure_get_int(structure
, "rate", &rate
))
341 WARN("Missing 'rate' value.\n");
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;
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
;
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"))
393 if (!(gst_audio_info_from_caps(&info
, caps
)))
395 return amt_from_gst_audio_info(&info
, mt
);
397 else if (!strcmp(type
, "video/x-raw"))
401 if (!gst_video_info_from_caps(&info
, caps
))
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
;
412 mt
->majortype
= MEDIATYPE_Video
;
413 mt
->subtype
= MEDIASUBTYPE_CVID
;
414 mt
->bTemporalCompression
= TRUE
;
416 mt
->formattype
= FORMAT_VideoInfo
;
417 if (!(vih
= CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
))))
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;
440 FIXME("Unhandled type %s.\n", debugstr_a(type
));
445 static GstCaps
*amt_to_gst_caps_video(const AM_MEDIA_TYPE
*mt
)
450 GstVideoFormat format
;
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
;
467 if (!IsEqualGUID(&mt
->formattype
, &FORMAT_VideoInfo
)
468 || mt
->cbFormat
< sizeof(VIDEOINFOHEADER
) || !mt
->pbFormat
)
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
;
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
);
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
);
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
;
509 if (!IsEqualGUID(&mt
->formattype
, &FORMAT_WaveFormatEx
)
510 || mt
->cbFormat
< sizeof(WAVEFORMATEX
) || !mt
->pbFormat
)
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
);
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
));
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
));
557 GstCaps
*caps
, *filter
, *temp
;
559 gst_query_parse_caps(query
, &filter
);
562 caps
= amt_to_gst_caps(&pin
->pin
.pin
.mt
);
564 caps
= gst_caps_new_any();
570 temp
= gst_caps_intersect(caps
, filter
);
571 gst_caps_unref(caps
);
575 gst_query_set_caps_result(query
, caps
);
576 gst_caps_unref(caps
);
579 case GST_QUERY_ACCEPT_CAPS
:
585 if (!stream
->enabled
)
587 gst_query_set_accept_caps_result(query
, TRUE
);
591 gst_query_parse_accept_caps(query
, &caps
);
592 if (!amt_from_gst_caps(caps
, &mt
))
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
))
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
)
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
)
624 if (!ret
&& WARN_ON(gstreamer
))
626 gchar
*str
= gst_caps_to_string(caps
);
627 WARN("Rejecting caps \"%s\".\n", debugstr_a(str
));
631 gst_query_set_accept_caps_result(query
, ret
);
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
;
644 GstFormat seek_format
;
646 GstSeekType cur_type
, stop_type
;
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
));
662 flush
= flags
& GST_SEEK_FLAG_FLUSH
;
663 seqnum
= gst_event_get_seqnum(event
);
665 /* send flush start */
667 tevent
= gst_event_new_flush_start();
668 gst_event_set_seqnum(tevent
, seqnum
);
669 gst_pad_push_event(parser
->my_src
, tevent
);
671 gst_pad_set_active(parser
->my_src
, 1);
674 parser
->next_offset
= parser
->start_offset
= cur
;
676 /* and prepare to continue streaming */
678 tevent
= gst_event_new_flush_stop(TRUE
);
679 gst_event_set_seqnum(tevent
, seqnum
);
680 gst_pad_push_event(parser
->my_src
, tevent
);
682 gst_pad_set_active(parser
->my_src
, 1);
688 static gboolean
event_src(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
690 struct parser
*This
= gst_pad_get_element_private(pad
);
693 GST_LOG("filter %p, type \"%s\".", This
, GST_EVENT_TYPE_NAME(event
));
698 ret
= gst_base_src_perform_seek(This
, event
);
701 case GST_EVENT_FLUSH_START
:
702 case GST_EVENT_FLUSH_STOP
:
704 case GST_EVENT_RECONFIGURE
:
708 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
712 gst_event_unref(event
);
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.");
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
));
754 case GST_EVENT_SEGMENT
:
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
));
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
);
781 struct wg_parser_event stream_event
;
783 stream_event
.type
= WG_PARSER_EVENT_EOS
;
784 queue_stream_event(pin
, &stream_event
);
788 pthread_mutex_lock(&parser
->mutex
);
790 pthread_mutex_unlock(&parser
->mutex
);
791 pthread_cond_signal(&parser
->init_cond
);
795 case GST_EVENT_FLUSH_START
:
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
:
810 case WG_PARSER_EVENT_BUFFER
:
811 gst_buffer_unref(stream
->event
.u
.buffer
);
814 stream
->event
.type
= WG_PARSER_EVENT_NONE
;
816 pthread_mutex_unlock(&parser
->mutex
);
820 case GST_EVENT_FLUSH_STOP
:
821 gst_segment_init(stream
->segment
, GST_FORMAT_TIME
);
824 pthread_mutex_lock(&parser
->mutex
);
825 stream
->flushing
= false;
826 pthread_mutex_unlock(&parser
->mutex
);
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
);
843 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
845 gst_event_unref(event
);
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
;
858 GST_DEBUG("Starting push thread.");
860 if (!(buffer
= gst_buffer_new_allocate(NULL
, 16384, NULL
)))
862 GST_ERROR("Failed to allocate memory.");
866 maxlen
= parser
->stop_offset
? parser
->stop_offset
: parser
->file_size
;
872 if (parser
->next_offset
>= maxlen
)
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
));
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
));
892 gst_buffer_unref(buffer
);
894 gst_pad_push_event(parser
->my_src
, gst_event_new_eos());
896 GST_DEBUG("Stopping push thread.");
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
;
908 GST_LOG("pin %p, buffer %p.", pin
, buffer
);
910 if (!stream
->enabled
)
912 gst_buffer_unref(buffer
);
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
);
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
;
932 hr
= IMediaSample_SetActualDataLength(sample
, size
);
934 WARN("SetActualDataLength failed: %08x\n", 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
;
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
);
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
);
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
);
967 IMediaSample_SetTime(sample
, rtStart
>= 0 ? &rtStart
: NULL
, NULL
);
968 IMediaSample_SetMediaTime(sample
, NULL
, NULL
);
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
;
982 hr
= IMemInputPin_Receive(pin
->pin
.pMemInputPin
, sample
);
984 TRACE("sending sample returned: %08x\n", hr
);
989 /* Send a single GStreamer buffer (splitting it into multiple IMediaSamples if
991 static void send_buffer(struct parser_source
*pin
, GstBuffer
*buf
)
994 IMediaSample
*sample
;
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
;
1005 while (offset
< info
.size
)
1009 hr
= BaseOutputPinImpl_GetDeliveryBuffer(&pin
->pin
, &sample
, NULL
, NULL
, 0);
1013 if (hr
!= VFW_E_NOT_CONNECTED
)
1014 ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr
);
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
);
1032 hr
= BaseOutputPinImpl_GetDeliveryBuffer(&pin
->pin
, &sample
, NULL
, NULL
, 0);
1036 if (hr
!= VFW_E_NOT_CONNECTED
)
1037 ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr
);
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");
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
);
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
);
1098 TRACE("Got event of type %#x.\n", event
.type
);
1102 case WG_PARSER_EVENT_BUFFER
:
1103 send_buffer(pin
, event
.u
.buffer
);
1106 case WG_PARSER_EVENT_EOS
:
1107 IPin_EndOfStream(pin
->pin
.pin
.peer
);
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
);
1115 case WG_PARSER_EVENT_NONE
:
1119 LeaveCriticalSection(&pin
->flushing_cs
);
1122 TRACE("Streaming stopped; exiting.\n");
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
;
1133 GST_LOG("pad %p, offset %" G_GINT64_MODIFIER
"u, length %u, buffer %p.", pad
, offset
, size
, *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
);
1166 static GstFlowReturn
read_buffer(struct parser
*This
, guint64 ofs
, guint len
, GstBuffer
*buffer
)
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
);
1189 ERR("Failed to read data, hr %#x.\n", hr
);
1190 return GST_FLOW_ERROR
;
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
)
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");
1226 static void removed_decoded_pad(GstElement
*bin
, GstPad
*pad
, gpointer user
)
1228 struct parser
*filter
= user
;
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
);
1243 gst_pad_unlink(stream
->their_src
, stream
->my_sink
);
1244 gst_object_unref(stream
->their_src
);
1245 stream
->their_src
= NULL
;
1250 name
= gst_pad_get_name(pad
);
1251 GST_LOG("No pin matching pad \"%s\" found.", 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
;
1264 struct parser_source
*pin
;
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
);
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");
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 *));
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 *));
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 *));
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 *));
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 *));
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
;
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
;
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
));
1397 gst_pad_set_active(stream
->my_sink
, 1);
1398 gst_object_ref(stream
->their_src
= pad
);
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
))
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
;
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
);
1431 else if (format
== GST_FORMAT_BYTES
)
1433 gst_query_set_duration(query
, GST_FORMAT_BYTES
, parser
->file_size
);
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
));
1444 gst_query_set_seeking(query
, GST_FORMAT_BYTES
, 1, 0, parser
->file_size
);
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
);
1452 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query
));
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
;
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
) {
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;
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
));
1490 case GST_PAD_MODE_PULL
:
1492 case GST_PAD_MODE_PUSH
:
1493 return activate_push(pad
, activate
);
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
;
1537 gchar
*dbg_info
= NULL
;
1539 GST_DEBUG("filter %p, message type %s.", filter
, GST_MESSAGE_TYPE_NAME(msg
));
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
);
1549 pthread_mutex_lock(&parser
->mutex
);
1550 parser
->error
= true;
1551 pthread_mutex_unlock(&parser
->mutex
);
1552 pthread_cond_signal(&parser
->init_cond
);
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
);
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
);
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");
1597 static HRESULT
GST_Connect(struct parser
*This
, IPin
*pConnectPin
)
1599 struct wg_parser
*parser
= This
->wg_parser
;
1602 GstStaticPadTemplate src_template
= GST_STATIC_PAD_TEMPLATE(
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
);
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
))
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
);
1651 pthread_mutex_unlock(&parser
->mutex
);
1656 pthread_mutex_unlock(&parser
->mutex
);
1658 parser
->next_offset
= 0;
1659 This
->next_pull_offset
= 0;
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
)
1675 return &filter
->sink
.pin
;
1676 else if (index
<= filter
->source_count
)
1677 return &filter
->sources
[index
- 1]->pin
.pin
;
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
;
1689 static void wg_parser_destroy(struct wg_parser
*parser
)
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
);
1705 static void parser_destroy(struct strmbase_filter
*iface
)
1707 struct parser
*filter
= impl_from_strmbase_filter(iface
);
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
);
1715 hr
= IPin_Disconnect(&filter
->sink
.pin
.IPin_iface
);
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
);
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
;
1738 if (!parser
->container
)
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
)
1761 if (!filter
->sources
[i
]->pin
.pin
.peer
)
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
);
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
;
1779 if (!parser
->container
)
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
)
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
)
1804 IMemAllocator_Decommit(pin
->pin
.pAllocator
);
1806 WaitForSingleObject(pin
->thread
, INFINITE
);
1807 CloseHandle(pin
->thread
);
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
))
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
);
1841 filter
->reader
= NULL
;
1842 if (FAILED(hr
= IPin_QueryInterface(peer
, &IID_IAsyncReader
, (void **)&filter
->reader
)))
1845 if (FAILED(hr
= GST_Connect(filter
, peer
)))
1850 GST_RemoveOutputPins(filter
);
1851 IAsyncReader_Release(filter
->reader
);
1852 filter
->reader
= NULL
;
1856 static void parser_sink_disconnect(struct strmbase_sink
*iface
)
1858 struct parser
*filter
= impl_from_strmbase_sink(iface
);
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
;
1883 ERR("Failed to create decodebin; are %u-bit GStreamer \"base\" plugins installed?\n",
1884 8 * (int)sizeof(void*));
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
);
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");
1915 pthread_mutex_lock(&parser
->mutex
);
1916 while (!parser
->no_more_pads
&& !parser
->error
)
1917 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1920 pthread_mutex_unlock(&parser
->mutex
);
1923 pthread_mutex_unlock(&parser
->mutex
);
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
);
1934 gst_caps_unref(caps
);
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
;
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
))
1978 if (!strcmp(type
, "video/x-raw") && index
< ARRAY_SIZE(video_formats
))
1980 gint width
, height
, fps_n
, fps_d
;
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
)
1991 if (!amt_from_gst_video_info(&info
, mt
))
1992 return E_OUTOFMEMORY
;
1995 else if (!strcmp(type
, "audio/x-raw") && !index
)
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
;
2007 return VFW_S_NO_MORE_ITEMS
;
2010 static BOOL
parser_init_gstreamer(void)
2012 if (!init_gstreamer())
2014 GST_DEBUG_CATEGORY_INIT(wine
, "WINE", GST_DEBUG_FG_RED
, "Wine GStreamer support");
2018 static struct wg_parser
*wg_parser_create(void)
2020 struct wg_parser
*parser
;
2022 if (!(parser
= calloc(1, sizeof(*parser
))))
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
);
2035 HRESULT
decodebin_parser_create(IUnknown
*outer
, IUnknown
**out
)
2037 struct parser
*object
;
2039 if (!parser_init_gstreamer())
2044 if (!(object
= heap_alloc_zero(sizeof(*object
))))
2045 return E_OUTOFMEMORY
;
2047 if (!(object
->wg_parser
= wg_parser_create()))
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
;
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
);
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
);
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
);
2109 static const IAMStreamSelectVtbl stream_select_vtbl
=
2111 stream_select_QueryInterface
,
2112 stream_select_AddRef
,
2113 stream_select_Release
,
2114 stream_select_Count
,
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
);
2126 static HRESULT WINAPI
GST_ChangeStop(IMediaSeeking
*iface
)
2128 struct parser_source
*This
= impl_from_IMediaSeeking(iface
);
2129 TRACE("(%p)\n", This
);
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
);
2140 gst_pad_push_event(stream
->my_sink
, ev
);
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;
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
);
2180 if (pin
->pin
.pin
.filter
->state
== State_Stopped
)
2182 SourceSeekingImpl_SetPositions(iface
, current
, current_flags
, stop
, stop_flags
);
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
);
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
));
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
);
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
);
2261 static const IMediaSeekingVtbl GST_Seeking_Vtbl
=
2263 GST_Seeking_QueryInterface
,
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
;
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
));
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
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
)
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. */
2352 WARN("Ignoring quality message with zero proportion.\n");
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
);
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
);
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
;
2394 return E_NOINTERFACE
;
2396 IUnknown_AddRef((IUnknown
*)*out
);
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
;
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
);
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
);
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
;
2517 if (!(new_array
= heap_realloc(filter
->sources
, (filter
->source_count
+ 1) * sizeof(*new_array
))))
2519 filter
->sources
= new_array
;
2521 if (!(pin
= heap_alloc_zero(sizeof(*pin
))))
2524 if (!(stream
= calloc(1, sizeof(*stream
))))
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
;
2555 static HRESULT
GST_RemoveOutputPins(struct parser
*This
)
2557 struct wg_parser
*parser
= This
->wg_parser
;
2560 TRACE("(%p)\n", This
);
2563 if (!parser
->container
)
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
);
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
);
2616 struct query_sink_data
*data
= &cbdata
->u
.query_sink_data
;
2617 cbdata
->u
.query_sink_data
.ret
= query_sink(data
->pad
, data
->parent
,
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
))
2641 if (IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_WAVE
))
2643 if (IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_AU
) || IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_AIFF
))
2644 FIXME("AU and AIFF files are not yet supported.\n");
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
;
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*));
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
);
2680 if (!(pin
= create_pin(filter
, source_name
)))
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
);
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");
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
;
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
);
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
;
2722 return VFW_S_NO_MORE_ITEMS
;
2723 if (!amt_from_gst_caps(stream
->caps
, mt
))
2724 return E_OUTOFMEMORY
;
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())
2738 if (!(object
= heap_alloc_zero(sizeof(*object
))))
2739 return E_OUTOFMEMORY
;
2741 if (!(object
->wg_parser
= wg_parser_create()))
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
;
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
))
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
;
2781 ERR("Failed to create avidemux; are %u-bit GStreamer \"good\" plugins installed?\n",
2782 8 * (int)sizeof(void*));
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
);
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");
2812 pthread_mutex_lock(&parser
->mutex
);
2813 while (!parser
->no_more_pads
&& !parser
->error
)
2814 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
2817 pthread_mutex_unlock(&parser
->mutex
);
2820 pthread_mutex_unlock(&parser
->mutex
);
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
;
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
);
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
;
2843 return VFW_S_NO_MORE_ITEMS
;
2844 if (!amt_from_gst_caps(stream
->caps
, mt
))
2845 return E_OUTOFMEMORY
;
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())
2859 if (!(object
= heap_alloc_zero(sizeof(*object
))))
2860 return E_OUTOFMEMORY
;
2862 if (!(object
->wg_parser
= wg_parser_create()))
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
;
2879 static HRESULT
mpeg_splitter_sink_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
2881 if (!IsEqualGUID(&mt
->majortype
, &MEDIATYPE_Stream
))
2883 if (IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_MPEG1Audio
))
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
));
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
;
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*));
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
);
2924 if (!(pin
= create_pin(filter
, source_name
)))
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
);
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");
2943 pthread_mutex_lock(&parser
->mutex
);
2944 while (!parser
->has_duration
&& !parser
->error
&& !stream
->eos
)
2945 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
2948 pthread_mutex_unlock(&parser
->mutex
);
2951 pthread_mutex_unlock(&parser
->mutex
);
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
;
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
);
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
;
2974 return VFW_S_NO_MORE_ITEMS
;
2975 if (!amt_from_gst_caps(stream
->caps
, mt
))
2976 return E_OUTOFMEMORY
;
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
);
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())
3013 if (!(object
= heap_alloc_zero(sizeof(*object
))))
3014 return E_OUTOFMEMORY
;
3016 if (!(object
->wg_parser
= wg_parser_create()))
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
;