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 struct wg_parser_stream
79 GstPad
*their_src
, *post_sink
, *post_src
, *my_sink
;
86 struct strmbase_filter filter
;
87 IAMStreamSelect IAMStreamSelect_iface
;
89 struct strmbase_sink sink
;
92 struct parser_source
**sources
;
93 unsigned int source_count
;
98 struct wg_parser
*wg_parser
;
100 /* FIXME: It would be nice to avoid duplicating these with strmbase.
101 * However, synchronization is tricky; we need access to be protected by a
103 bool streaming
, sink_connected
;
105 uint64_t next_pull_offset
;
109 BOOL (*init_gst
)(struct parser
*filter
);
110 HRESULT (*source_query_accept
)(struct parser_source
*pin
, const AM_MEDIA_TYPE
*mt
);
111 HRESULT (*source_get_media_type
)(struct parser_source
*pin
, unsigned int index
, AM_MEDIA_TYPE
*mt
);
114 enum parser_event_type
116 PARSER_EVENT_NONE
= 0,
119 PARSER_EVENT_SEGMENT
,
124 enum parser_event_type type
;
130 uint64_t position
, stop
;
138 struct strmbase_source pin
;
139 IQualityControl IQualityControl_iface
;
141 struct wg_parser_stream
*wg_stream
;
146 CRITICAL_SECTION flushing_cs
;
147 pthread_cond_t event_cond
, event_empty_cond
;
149 struct parser_event event
;
153 static inline struct parser
*impl_from_strmbase_filter(struct strmbase_filter
*iface
)
155 return CONTAINING_RECORD(iface
, struct parser
, filter
);
158 static const WCHAR wcsInputPinName
[] = {'i','n','p','u','t',' ','p','i','n',0};
159 static const IMediaSeekingVtbl GST_Seeking_Vtbl
;
160 static const IQualityControlVtbl GSTOutPin_QualityControl_Vtbl
;
162 static struct parser_source
*create_pin(struct parser
*filter
, const WCHAR
*name
);
163 static HRESULT
GST_RemoveOutputPins(struct parser
*This
);
164 static HRESULT WINAPI
GST_ChangeCurrent(IMediaSeeking
*iface
);
165 static HRESULT WINAPI
GST_ChangeStop(IMediaSeeking
*iface
);
166 static HRESULT WINAPI
GST_ChangeRate(IMediaSeeking
*iface
);
168 static gboolean
amt_from_gst_audio_info(const GstAudioInfo
*info
, AM_MEDIA_TYPE
*amt
)
170 WAVEFORMATEXTENSIBLE
*wfe
;
174 wfe
= CoTaskMemAlloc(sizeof(*wfe
));
175 wfx
= (WAVEFORMATEX
*)wfe
;
176 amt
->majortype
= MEDIATYPE_Audio
;
177 amt
->subtype
= MEDIASUBTYPE_PCM
;
178 amt
->formattype
= FORMAT_WaveFormatEx
;
179 amt
->pbFormat
= (BYTE
*)wfe
;
180 amt
->cbFormat
= sizeof(*wfe
);
181 amt
->bFixedSizeSamples
= TRUE
;
182 amt
->bTemporalCompression
= FALSE
;
185 wfx
->wFormatTag
= WAVE_FORMAT_EXTENSIBLE
;
187 wfx
->nChannels
= info
->channels
;
188 wfx
->nSamplesPerSec
= info
->rate
;
189 depth
= GST_AUDIO_INFO_WIDTH(info
);
190 bpp
= GST_AUDIO_INFO_DEPTH(info
);
192 if (!depth
|| depth
> 32 || depth
% 8)
196 wfe
->Samples
.wValidBitsPerSample
= depth
;
197 wfx
->wBitsPerSample
= bpp
;
198 wfx
->cbSize
= sizeof(*wfe
)-sizeof(*wfx
);
199 switch (wfx
->nChannels
) {
200 case 1: wfe
->dwChannelMask
= KSAUDIO_SPEAKER_MONO
; break;
201 case 2: wfe
->dwChannelMask
= KSAUDIO_SPEAKER_STEREO
; break;
202 case 4: wfe
->dwChannelMask
= KSAUDIO_SPEAKER_SURROUND
; break;
203 case 5: wfe
->dwChannelMask
= (KSAUDIO_SPEAKER_5POINT1
& ~SPEAKER_LOW_FREQUENCY
); break;
204 case 6: wfe
->dwChannelMask
= KSAUDIO_SPEAKER_5POINT1
; break;
205 case 8: wfe
->dwChannelMask
= KSAUDIO_SPEAKER_7POINT1
; break;
207 wfe
->dwChannelMask
= 0;
209 if (GST_AUDIO_INFO_IS_FLOAT(info
))
211 amt
->subtype
= MEDIASUBTYPE_IEEE_FLOAT
;
212 wfe
->SubFormat
= KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
;
214 wfe
->SubFormat
= KSDATAFORMAT_SUBTYPE_PCM
;
215 if (wfx
->nChannels
<= 2 && bpp
<= 16 && depth
== bpp
) {
216 wfx
->wFormatTag
= WAVE_FORMAT_PCM
;
218 amt
->cbFormat
= sizeof(WAVEFORMATEX
);
221 amt
->lSampleSize
= wfx
->nBlockAlign
= wfx
->nChannels
* wfx
->wBitsPerSample
/8;
222 wfx
->nAvgBytesPerSec
= wfx
->nSamplesPerSec
* wfx
->nBlockAlign
;
226 static gboolean
amt_from_gst_video_info(const GstVideoInfo
*info
, AM_MEDIA_TYPE
*amt
)
229 BITMAPINFOHEADER
*bih
;
230 gint32 width
, height
;
232 width
= GST_VIDEO_INFO_WIDTH(info
);
233 height
= GST_VIDEO_INFO_HEIGHT(info
);
235 vih
= CoTaskMemAlloc(sizeof(*vih
));
236 bih
= &vih
->bmiHeader
;
238 amt
->formattype
= FORMAT_VideoInfo
;
239 amt
->pbFormat
= (BYTE
*)vih
;
240 amt
->cbFormat
= sizeof(VIDEOINFOHEADER
);
241 amt
->bFixedSizeSamples
= FALSE
;
242 amt
->bTemporalCompression
= TRUE
;
243 amt
->lSampleSize
= 1;
245 ZeroMemory(vih
, sizeof(*vih
));
246 amt
->majortype
= MEDIATYPE_Video
;
248 if (GST_VIDEO_INFO_IS_RGB(info
))
250 bih
->biCompression
= BI_RGB
;
251 switch (GST_VIDEO_INFO_FORMAT(info
))
253 case GST_VIDEO_FORMAT_BGRA
:
254 amt
->subtype
= MEDIASUBTYPE_ARGB32
;
255 bih
->biBitCount
= 32;
257 case GST_VIDEO_FORMAT_BGRx
:
258 amt
->subtype
= MEDIASUBTYPE_RGB32
;
259 bih
->biBitCount
= 32;
261 case GST_VIDEO_FORMAT_BGR
:
262 amt
->subtype
= MEDIASUBTYPE_RGB24
;
263 bih
->biBitCount
= 24;
265 case GST_VIDEO_FORMAT_RGB16
:
266 amt
->subtype
= MEDIASUBTYPE_RGB565
;
267 amt
->cbFormat
= offsetof(VIDEOINFO
, u
.dwBitMasks
[3]);
268 vih
->u
.dwBitMasks
[iRED
] = 0xf800;
269 vih
->u
.dwBitMasks
[iGREEN
] = 0x07e0;
270 vih
->u
.dwBitMasks
[iBLUE
] = 0x001f;
271 bih
->biBitCount
= 16;
272 bih
->biCompression
= BI_BITFIELDS
;
274 case GST_VIDEO_FORMAT_RGB15
:
275 amt
->subtype
= MEDIASUBTYPE_RGB555
;
276 bih
->biBitCount
= 16;
279 WARN("Cannot convert %s to a DirectShow type.\n", GST_VIDEO_INFO_NAME(info
));
284 amt
->subtype
= MEDIATYPE_Video
;
285 if (!(amt
->subtype
.Data1
= gst_video_format_to_fourcc(GST_VIDEO_INFO_FORMAT(info
))))
290 switch (amt
->subtype
.Data1
) {
291 case mmioFOURCC('I','4','2','0'):
292 case mmioFOURCC('Y','V','1','2'):
293 case mmioFOURCC('N','V','1','2'):
294 case mmioFOURCC('N','V','2','1'):
295 bih
->biBitCount
= 12; break;
296 case mmioFOURCC('Y','U','Y','2'):
297 case mmioFOURCC('Y','V','Y','U'):
298 case mmioFOURCC('U','Y','V','Y'):
299 bih
->biBitCount
= 16; break;
301 bih
->biCompression
= amt
->subtype
.Data1
;
303 bih
->biSizeImage
= GST_VIDEO_INFO_SIZE(info
);
304 if ((vih
->AvgTimePerFrame
= (REFERENCE_TIME
)MulDiv(10000000,
305 GST_VIDEO_INFO_FPS_D(info
), GST_VIDEO_INFO_FPS_N(info
))) == -1)
306 vih
->AvgTimePerFrame
= 0; /* zero division or integer overflow */
307 bih
->biSize
= sizeof(*bih
);
308 bih
->biWidth
= width
;
309 bih
->biHeight
= height
;
314 static gboolean
amt_from_gst_caps_audio_mpeg(const GstCaps
*caps
, AM_MEDIA_TYPE
*mt
)
316 GstStructure
*structure
= gst_caps_get_structure(caps
, 0);
317 gint layer
, channels
, rate
;
319 mt
->majortype
= MEDIATYPE_Audio
;
320 mt
->subtype
= MEDIASUBTYPE_MPEG1AudioPayload
;
321 mt
->bFixedSizeSamples
= FALSE
;
322 mt
->bTemporalCompression
= FALSE
;
324 mt
->formattype
= FORMAT_WaveFormatEx
;
327 if (!gst_structure_get_int(structure
, "layer", &layer
))
329 WARN("Missing 'layer' value.\n");
332 if (!gst_structure_get_int(structure
, "channels", &channels
))
334 WARN("Missing 'channels' value.\n");
337 if (!gst_structure_get_int(structure
, "rate", &rate
))
339 WARN("Missing 'rate' value.\n");
345 MPEGLAYER3WAVEFORMAT
*wfx
= CoTaskMemAlloc(sizeof(*wfx
));
346 memset(wfx
, 0, sizeof(*wfx
));
348 mt
->subtype
.Data1
= WAVE_FORMAT_MPEGLAYER3
;
349 mt
->cbFormat
= sizeof(*wfx
);
350 mt
->pbFormat
= (BYTE
*)wfx
;
351 wfx
->wfx
.wFormatTag
= WAVE_FORMAT_MPEGLAYER3
;
352 wfx
->wfx
.nChannels
= channels
;
353 wfx
->wfx
.nSamplesPerSec
= rate
;
354 /* FIXME: We can't get most of the MPEG data from the caps. We may have
355 * to manually parse the header. */
356 wfx
->wfx
.cbSize
= sizeof(*wfx
) - sizeof(WAVEFORMATEX
);
357 wfx
->wID
= MPEGLAYER3_ID_MPEG
;
358 wfx
->fdwFlags
= MPEGLAYER3_FLAG_PADDING_ON
;
359 wfx
->nFramesPerBlock
= 1;
360 wfx
->nCodecDelay
= 1393;
364 MPEG1WAVEFORMAT
*wfx
= CoTaskMemAlloc(sizeof(*wfx
));
365 memset(wfx
, 0, sizeof(*wfx
));
367 mt
->subtype
.Data1
= WAVE_FORMAT_MPEG
;
368 mt
->cbFormat
= sizeof(*wfx
);
369 mt
->pbFormat
= (BYTE
*)wfx
;
370 wfx
->wfx
.wFormatTag
= WAVE_FORMAT_MPEG
;
371 wfx
->wfx
.nChannels
= channels
;
372 wfx
->wfx
.nSamplesPerSec
= rate
;
373 wfx
->wfx
.cbSize
= sizeof(*wfx
) - sizeof(WAVEFORMATEX
);
374 wfx
->fwHeadLayer
= layer
;
380 static gboolean
amt_from_gst_caps(const GstCaps
*caps
, AM_MEDIA_TYPE
*mt
)
382 const char *type
= gst_structure_get_name(gst_caps_get_structure(caps
, 0));
383 GstStructure
*structure
= gst_caps_get_structure(caps
, 0);
385 memset(mt
, 0, sizeof(AM_MEDIA_TYPE
));
387 if (!strcmp(type
, "audio/x-raw"))
391 if (!(gst_audio_info_from_caps(&info
, caps
)))
393 return amt_from_gst_audio_info(&info
, mt
);
395 else if (!strcmp(type
, "video/x-raw"))
399 if (!gst_video_info_from_caps(&info
, caps
))
401 return amt_from_gst_video_info(&info
, mt
);
403 else if (!strcmp(type
, "audio/mpeg"))
404 return amt_from_gst_caps_audio_mpeg(caps
, mt
);
405 else if (!strcmp(type
, "video/x-cinepak"))
407 VIDEOINFOHEADER
*vih
;
410 mt
->majortype
= MEDIATYPE_Video
;
411 mt
->subtype
= MEDIASUBTYPE_CVID
;
412 mt
->bTemporalCompression
= TRUE
;
414 mt
->formattype
= FORMAT_VideoInfo
;
415 if (!(vih
= CoTaskMemAlloc(sizeof(VIDEOINFOHEADER
))))
417 mt
->cbFormat
= sizeof(VIDEOINFOHEADER
);
418 mt
->pbFormat
= (BYTE
*)vih
;
420 memset(vih
, 0, sizeof(VIDEOINFOHEADER
));
421 vih
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
422 if (gst_structure_get_int(structure
, "width", &i
))
423 vih
->bmiHeader
.biWidth
= i
;
424 if (gst_structure_get_int(structure
, "height", &i
))
425 vih
->bmiHeader
.biHeight
= i
;
426 vih
->bmiHeader
.biPlanes
= 1;
427 /* Both ffmpeg's encoder and a Cinepak file seen in the wild report
428 * 24 bpp. ffmpeg sets biSizeImage as below; others may be smaller, but
429 * as long as every sample fits into our allocator, we're fine. */
430 vih
->bmiHeader
.biBitCount
= 24;
431 vih
->bmiHeader
.biCompression
= mmioFOURCC('c','v','i','d');
432 vih
->bmiHeader
.biSizeImage
= vih
->bmiHeader
.biWidth
433 * vih
->bmiHeader
.biHeight
* vih
->bmiHeader
.biBitCount
/ 8;
438 FIXME("Unhandled type %s.\n", debugstr_a(type
));
443 static GstCaps
*amt_to_gst_caps_video(const AM_MEDIA_TYPE
*mt
)
448 GstVideoFormat format
;
452 {&MEDIASUBTYPE_ARGB32
, GST_VIDEO_FORMAT_BGRA
},
453 {&MEDIASUBTYPE_RGB32
, GST_VIDEO_FORMAT_BGRx
},
454 {&MEDIASUBTYPE_RGB24
, GST_VIDEO_FORMAT_BGR
},
455 {&MEDIASUBTYPE_RGB565
, GST_VIDEO_FORMAT_RGB16
},
456 {&MEDIASUBTYPE_RGB555
, GST_VIDEO_FORMAT_RGB15
},
459 const VIDEOINFOHEADER
*vih
= (VIDEOINFOHEADER
*)mt
->pbFormat
;
460 GstVideoFormat format
= GST_VIDEO_FORMAT_UNKNOWN
;
465 if (!IsEqualGUID(&mt
->formattype
, &FORMAT_VideoInfo
)
466 || mt
->cbFormat
< sizeof(VIDEOINFOHEADER
) || !mt
->pbFormat
)
469 for (i
= 0; i
< ARRAY_SIZE(format_map
); ++i
)
471 if (IsEqualGUID(&mt
->subtype
, format_map
[i
].subtype
))
473 format
= format_map
[i
].format
;
478 if (format
== GST_VIDEO_FORMAT_UNKNOWN
)
479 format
= gst_video_format_from_fourcc(vih
->bmiHeader
.biCompression
);
481 if (format
== GST_VIDEO_FORMAT_UNKNOWN
)
483 FIXME("Unknown video format (subtype %s, compression %#x).\n",
484 debugstr_guid(&mt
->subtype
), vih
->bmiHeader
.biCompression
);
488 gst_video_info_set_format(&info
, format
, vih
->bmiHeader
.biWidth
, vih
->bmiHeader
.biHeight
);
489 if ((caps
= gst_video_info_to_caps(&info
)))
491 /* Clear some fields that shouldn't prevent us from connecting. */
492 for (i
= 0; i
< gst_caps_get_size(caps
); ++i
)
494 gst_structure_remove_fields(gst_caps_get_structure(caps
, i
),
495 "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL
);
501 static GstCaps
*amt_to_gst_caps_audio(const AM_MEDIA_TYPE
*mt
)
503 const WAVEFORMATEX
*wfx
= (WAVEFORMATEX
*)mt
->pbFormat
;
504 GstAudioFormat format
= GST_AUDIO_FORMAT_UNKNOWN
;
507 if (!IsEqualGUID(&mt
->formattype
, &FORMAT_WaveFormatEx
)
508 || mt
->cbFormat
< sizeof(WAVEFORMATEX
) || !mt
->pbFormat
)
511 if (IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_PCM
))
512 format
= gst_audio_format_build_integer(wfx
->wBitsPerSample
!= 8,
513 G_LITTLE_ENDIAN
, wfx
->wBitsPerSample
, wfx
->wBitsPerSample
);
514 else if (IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_IEEE_FLOAT
))
516 if (wfx
->wBitsPerSample
== 32)
517 format
= GST_AUDIO_FORMAT_F32LE
;
518 else if (wfx
->wBitsPerSample
== 64)
519 format
= GST_AUDIO_FORMAT_F64LE
;
522 if (format
== GST_AUDIO_FORMAT_UNKNOWN
)
524 FIXME("Unknown audio format (subtype %s, depth %u).\n",
525 debugstr_guid(&mt
->subtype
), wfx
->wBitsPerSample
);
529 gst_audio_info_set_format(&info
, format
, wfx
->nSamplesPerSec
, wfx
->nChannels
, NULL
);
530 return gst_audio_info_to_caps(&info
);
533 static GstCaps
*amt_to_gst_caps(const AM_MEDIA_TYPE
*mt
)
535 if (IsEqualGUID(&mt
->majortype
, &MEDIATYPE_Video
))
536 return amt_to_gst_caps_video(mt
);
537 else if (IsEqualGUID(&mt
->majortype
, &MEDIATYPE_Audio
))
538 return amt_to_gst_caps_audio(mt
);
540 FIXME("Unknown major type %s.\n", debugstr_guid(&mt
->majortype
));
544 static gboolean
query_sink(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
546 struct parser_source
*pin
= gst_pad_get_element_private(pad
);
548 TRACE("pin %p, type \"%s\".\n", pin
, gst_query_type_get_name(query
->type
));
554 GstCaps
*caps
, *filter
, *temp
;
556 gst_query_parse_caps(query
, &filter
);
558 if (pin
->pin
.pin
.peer
)
559 caps
= amt_to_gst_caps(&pin
->pin
.pin
.mt
);
561 caps
= gst_caps_new_any();
567 temp
= gst_caps_intersect(caps
, filter
);
568 gst_caps_unref(caps
);
572 gst_query_set_caps_result(query
, caps
);
573 gst_caps_unref(caps
);
576 case GST_QUERY_ACCEPT_CAPS
:
582 if (!pin
->pin
.pin
.peer
)
584 gst_query_set_accept_caps_result(query
, TRUE
);
588 gst_query_parse_accept_caps(query
, &caps
);
589 if (!amt_from_gst_caps(caps
, &mt
))
592 if (!IsEqualGUID(&mt
.majortype
, &pin
->pin
.pin
.mt
.majortype
)
593 || !IsEqualGUID(&mt
.subtype
, &pin
->pin
.pin
.mt
.subtype
)
594 || !IsEqualGUID(&mt
.formattype
, &pin
->pin
.pin
.mt
.formattype
))
597 if (IsEqualGUID(&mt
.majortype
, &MEDIATYPE_Video
))
599 const VIDEOINFOHEADER
*req_vih
= (VIDEOINFOHEADER
*)mt
.pbFormat
;
600 const VIDEOINFOHEADER
*our_vih
= (VIDEOINFOHEADER
*)pin
->pin
.pin
.mt
.pbFormat
;
602 if (req_vih
->bmiHeader
.biWidth
!= our_vih
->bmiHeader
.biWidth
603 || req_vih
->bmiHeader
.biHeight
!= our_vih
->bmiHeader
.biHeight
604 || req_vih
->bmiHeader
.biBitCount
!= our_vih
->bmiHeader
.biBitCount
605 || req_vih
->bmiHeader
.biCompression
!= our_vih
->bmiHeader
.biCompression
)
608 else if (IsEqualGUID(&mt
.majortype
, &MEDIATYPE_Audio
))
610 const WAVEFORMATEX
*req_wfx
= (WAVEFORMATEX
*)mt
.pbFormat
;
611 const WAVEFORMATEX
*our_wfx
= (WAVEFORMATEX
*)pin
->pin
.pin
.mt
.pbFormat
;
613 if (req_wfx
->nChannels
!= our_wfx
->nChannels
614 || req_wfx
->nSamplesPerSec
!= our_wfx
->nSamplesPerSec
615 || req_wfx
->wBitsPerSample
!= our_wfx
->wBitsPerSample
)
621 if (!ret
&& WARN_ON(gstreamer
))
623 gchar
*str
= gst_caps_to_string(caps
);
624 WARN("Rejecting caps \"%s\".\n", debugstr_a(str
));
628 gst_query_set_accept_caps_result(query
, ret
);
632 return gst_pad_query_default (pad
, parent
, query
);
636 static gboolean
gst_base_src_perform_seek(struct parser
*This
, GstEvent
*event
)
638 struct wg_parser
*parser
= This
->wg_parser
;
641 GstFormat seek_format
;
643 GstSeekType cur_type
, stop_type
;
648 BOOL thread
= !!parser
->push_thread
;
650 gst_event_parse_seek(event
, &rate
, &seek_format
, &flags
,
651 &cur_type
, &cur
, &stop_type
, &stop
);
653 if (seek_format
!= GST_FORMAT_BYTES
)
655 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(seek_format
));
659 flush
= flags
& GST_SEEK_FLAG_FLUSH
;
660 seqnum
= gst_event_get_seqnum(event
);
662 /* send flush start */
664 tevent
= gst_event_new_flush_start();
665 gst_event_set_seqnum(tevent
, seqnum
);
666 gst_pad_push_event(parser
->my_src
, tevent
);
668 gst_pad_set_active(parser
->my_src
, 1);
671 parser
->next_offset
= parser
->start_offset
= cur
;
673 /* and prepare to continue streaming */
675 tevent
= gst_event_new_flush_stop(TRUE
);
676 gst_event_set_seqnum(tevent
, seqnum
);
677 gst_pad_push_event(parser
->my_src
, tevent
);
679 gst_pad_set_active(parser
->my_src
, 1);
685 static gboolean
event_src(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
687 struct parser
*This
= gst_pad_get_element_private(pad
);
690 GST_LOG("filter %p, type \"%s\".", This
, GST_EVENT_TYPE_NAME(event
));
695 ret
= gst_base_src_perform_seek(This
, event
);
698 case GST_EVENT_FLUSH_START
:
699 case GST_EVENT_FLUSH_STOP
:
701 case GST_EVENT_RECONFIGURE
:
705 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
709 gst_event_unref(event
);
713 static GstFlowReturn
queue_stream_event(struct parser_source
*pin
, const struct parser_event
*event
)
715 struct wg_parser
*parser
= impl_from_strmbase_filter(pin
->pin
.pin
.filter
)->wg_parser
;
717 /* Unlike request_buffer_src() [q.v.], we need to watch for GStreamer
718 * flushes here. The difference is that we can be blocked by the streaming
719 * thread not running (or itself flushing on the DirectShow side).
720 * request_buffer_src() can only be blocked by the upstream source, and that
721 * is solved by flushing the upstream source. */
723 pthread_mutex_lock(&parser
->mutex
);
724 while (!pin
->flushing
&& pin
->event
.type
!= PARSER_EVENT_NONE
)
725 pthread_cond_wait(&pin
->event_empty_cond
, &parser
->mutex
);
728 pthread_mutex_unlock(&parser
->mutex
);
729 GST_DEBUG("Filter is flushing; discarding event.");
730 return GST_FLOW_FLUSHING
;
733 pthread_mutex_unlock(&parser
->mutex
);
734 pthread_cond_signal(&pin
->event_cond
);
735 GST_LOG("Event queued.");
739 static gboolean
event_sink(GstPad
*pad
, GstObject
*parent
, GstEvent
*event
)
741 struct parser_source
*pin
= gst_pad_get_element_private(pad
);
742 struct wg_parser_stream
*stream
= pin
->wg_stream
;
743 struct parser
*filter
= impl_from_strmbase_filter(pin
->pin
.pin
.filter
);
744 struct wg_parser
*parser
= filter
->wg_parser
;
746 GST_LOG("pin %p, type \"%s\".", pin
, GST_EVENT_TYPE_NAME(event
));
750 case GST_EVENT_SEGMENT
:
751 if (pin
->pin
.pin
.peer
)
753 struct parser_event stream_event
;
754 const GstSegment
*segment
;
756 gst_event_parse_segment(event
, &segment
);
758 if (segment
->format
!= GST_FORMAT_TIME
)
760 GST_FIXME("Unhandled format \"%s\".", gst_format_get_name(segment
->format
));
764 gst_segment_copy_into(segment
, stream
->segment
);
766 stream_event
.type
= PARSER_EVENT_SEGMENT
;
767 stream_event
.u
.segment
.position
= segment
->position
/ 100;
768 stream_event
.u
.segment
.stop
= segment
->stop
/ 100;
769 stream_event
.u
.segment
.rate
= segment
->rate
* segment
->applied_rate
;
770 queue_stream_event(pin
, &stream_event
);
775 if (pin
->pin
.pin
.peer
)
777 struct parser_event stream_event
;
779 stream_event
.type
= PARSER_EVENT_EOS
;
780 queue_stream_event(pin
, &stream_event
);
784 pthread_mutex_lock(&parser
->mutex
);
786 pthread_mutex_unlock(&parser
->mutex
);
787 pthread_cond_signal(&parser
->init_cond
);
791 case GST_EVENT_FLUSH_START
:
792 if (pin
->pin
.pin
.peer
)
794 pthread_mutex_lock(&parser
->mutex
);
796 pin
->flushing
= true;
797 pthread_cond_signal(&pin
->event_empty_cond
);
799 switch (pin
->event
.type
)
801 case PARSER_EVENT_NONE
:
802 case PARSER_EVENT_EOS
:
803 case PARSER_EVENT_SEGMENT
:
806 case PARSER_EVENT_BUFFER
:
807 gst_buffer_unref(pin
->event
.u
.buffer
);
810 pin
->event
.type
= PARSER_EVENT_NONE
;
812 pthread_mutex_unlock(&parser
->mutex
);
816 case GST_EVENT_FLUSH_STOP
:
817 gst_segment_init(stream
->segment
, GST_FORMAT_TIME
);
818 if (pin
->pin
.pin
.peer
)
820 pthread_mutex_lock(&parser
->mutex
);
821 pin
->flushing
= false;
822 pthread_mutex_unlock(&parser
->mutex
);
830 gst_event_parse_caps(event
, &caps
);
831 pthread_mutex_lock(&parser
->mutex
);
832 gst_caps_replace(&pin
->caps
, caps
);
833 pthread_mutex_unlock(&parser
->mutex
);
834 pthread_cond_signal(&parser
->init_cond
);
839 GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event
));
841 gst_event_unref(event
);
845 static GstFlowReturn
request_buffer_src(GstPad
*pad
, GstObject
*parent
, guint64 offset
, guint size
, GstBuffer
**buffer
);
847 static void *push_data(void *iface
)
849 struct parser
*This
= iface
;
850 struct wg_parser
*parser
= This
->wg_parser
;
854 GST_DEBUG("Starting push thread.");
856 if (!(buffer
= gst_buffer_new_allocate(NULL
, 16384, NULL
)))
858 GST_ERROR("Failed to allocate memory.");
862 maxlen
= parser
->stop_offset
? parser
->stop_offset
: parser
->file_size
;
868 if (parser
->next_offset
>= maxlen
)
870 len
= min(16384, maxlen
- parser
->next_offset
);
872 if ((ret
= request_buffer_src(parser
->my_src
, NULL
, parser
->next_offset
, len
, &buffer
)) < 0)
874 GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret
));
878 parser
->next_offset
+= len
;
880 buffer
->duration
= buffer
->pts
= -1;
881 if ((ret
= gst_pad_push(parser
->my_src
, buffer
)) < 0)
883 GST_ERROR("Failed to push data, ret %s.", gst_flow_get_name(ret
));
888 gst_buffer_unref(buffer
);
890 gst_pad_push_event(parser
->my_src
, gst_event_new_eos());
892 GST_DEBUG("Stopping push thread.");
897 static GstFlowReturn
got_data_sink(GstPad
*pad
, GstObject
*parent
, GstBuffer
*buffer
)
899 struct parser_source
*pin
= gst_pad_get_element_private(pad
);
900 struct parser_event stream_event
;
903 GST_LOG("pin %p, buffer %p.", pin
, buffer
);
905 if (!pin
->pin
.pin
.peer
)
907 gst_buffer_unref(buffer
);
911 stream_event
.type
= PARSER_EVENT_BUFFER
;
912 stream_event
.u
.buffer
= buffer
;
913 /* Transfer our reference to the buffer to the thread. */
914 if ((ret
= queue_stream_event(pin
, &stream_event
)) != GST_FLOW_OK
)
915 gst_buffer_unref(buffer
);
919 /* Fill and send a single IMediaSample. */
920 static HRESULT
send_sample(struct parser_source
*pin
, IMediaSample
*sample
,
921 GstBuffer
*buf
, GstMapInfo
*info
, gsize offset
, gsize size
, DWORD bytes_per_second
)
923 struct wg_parser_stream
*stream
= pin
->wg_stream
;
927 hr
= IMediaSample_SetActualDataLength(sample
, size
);
929 WARN("SetActualDataLength failed: %08x\n", hr
);
933 IMediaSample_GetPointer(sample
, &ptr
);
935 memcpy(ptr
, &info
->data
[offset
], size
);
937 if (GST_BUFFER_PTS_IS_VALID(buf
)) {
938 REFERENCE_TIME rtStart
;
939 GstClockTime ptsStart
= buf
->pts
;
941 ptsStart
= buf
->pts
+ gst_util_uint64_scale(offset
, GST_SECOND
, bytes_per_second
);
942 rtStart
= gst_segment_to_running_time(stream
->segment
, GST_FORMAT_TIME
, ptsStart
);
946 if (GST_BUFFER_DURATION_IS_VALID(buf
)) {
947 REFERENCE_TIME rtStop
;
948 REFERENCE_TIME tStart
;
949 REFERENCE_TIME tStop
;
950 GstClockTime ptsStop
= buf
->pts
+ buf
->duration
;
951 if (offset
+ size
< info
->size
)
952 ptsStop
= buf
->pts
+ gst_util_uint64_scale(offset
+ size
, GST_SECOND
, bytes_per_second
);
953 tStart
= ptsStart
/ 100;
954 tStop
= ptsStop
/ 100;
955 rtStop
= gst_segment_to_running_time(stream
->segment
, GST_FORMAT_TIME
, ptsStop
);
958 TRACE("Current time on %p: %i to %i ms\n", pin
, (int)(rtStart
/ 10000), (int)(rtStop
/ 10000));
959 IMediaSample_SetTime(sample
, &rtStart
, rtStop
>= 0 ? &rtStop
: NULL
);
960 IMediaSample_SetMediaTime(sample
, &tStart
, &tStop
);
962 IMediaSample_SetTime(sample
, rtStart
>= 0 ? &rtStart
: NULL
, NULL
);
963 IMediaSample_SetMediaTime(sample
, NULL
, NULL
);
966 IMediaSample_SetTime(sample
, NULL
, NULL
);
967 IMediaSample_SetMediaTime(sample
, NULL
, NULL
);
970 IMediaSample_SetDiscontinuity(sample
, !offset
&& GST_BUFFER_FLAG_IS_SET(buf
, GST_BUFFER_FLAG_DISCONT
));
971 IMediaSample_SetPreroll(sample
, GST_BUFFER_FLAG_IS_SET(buf
, GST_BUFFER_FLAG_LIVE
));
972 IMediaSample_SetSyncPoint(sample
, !GST_BUFFER_FLAG_IS_SET(buf
, GST_BUFFER_FLAG_DELTA_UNIT
));
974 if (!pin
->pin
.pin
.peer
)
975 hr
= VFW_E_NOT_CONNECTED
;
977 hr
= IMemInputPin_Receive(pin
->pin
.pMemInputPin
, sample
);
979 TRACE("sending sample returned: %08x\n", hr
);
984 /* Send a single GStreamer buffer (splitting it into multiple IMediaSamples if
986 static void send_buffer(struct parser_source
*pin
, GstBuffer
*buf
)
989 IMediaSample
*sample
;
992 gst_buffer_map(buf
, &info
, GST_MAP_READ
);
994 if (IsEqualGUID(&pin
->pin
.pin
.mt
.formattype
, &FORMAT_WaveFormatEx
)
995 && (IsEqualGUID(&pin
->pin
.pin
.mt
.subtype
, &MEDIASUBTYPE_PCM
)
996 || IsEqualGUID(&pin
->pin
.pin
.mt
.subtype
, &MEDIASUBTYPE_IEEE_FLOAT
)))
998 WAVEFORMATEX
*format
= (WAVEFORMATEX
*)pin
->pin
.pin
.mt
.pbFormat
;
1000 while (offset
< info
.size
)
1004 hr
= BaseOutputPinImpl_GetDeliveryBuffer(&pin
->pin
, &sample
, NULL
, NULL
, 0);
1008 if (hr
!= VFW_E_NOT_CONNECTED
)
1009 ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr
);
1013 advance
= min(IMediaSample_GetSize(sample
), info
.size
- offset
);
1015 hr
= send_sample(pin
, sample
, buf
, &info
, offset
, advance
, format
->nAvgBytesPerSec
);
1017 IMediaSample_Release(sample
);
1027 hr
= BaseOutputPinImpl_GetDeliveryBuffer(&pin
->pin
, &sample
, NULL
, NULL
, 0);
1031 if (hr
!= VFW_E_NOT_CONNECTED
)
1032 ERR("Could not get a delivery buffer (%x), returning GST_FLOW_FLUSHING\n", hr
);
1036 hr
= send_sample(pin
, sample
, buf
, &info
, 0, info
.size
, 0);
1038 IMediaSample_Release(sample
);
1042 gst_buffer_unmap(buf
, &info
);
1044 gst_buffer_unref(buf
);
1047 static bool get_stream_event(struct parser_source
*pin
, struct parser_event
*event
)
1049 struct parser
*filter
= impl_from_strmbase_filter(pin
->pin
.pin
.filter
);
1050 struct wg_parser
*parser
= filter
->wg_parser
;
1052 pthread_mutex_lock(&parser
->mutex
);
1054 while (!parser
->flushing
&& pin
->event
.type
== PARSER_EVENT_NONE
)
1055 pthread_cond_wait(&pin
->event_cond
, &parser
->mutex
);
1057 if (parser
->flushing
)
1059 pthread_mutex_unlock(&parser
->mutex
);
1060 TRACE("Filter is flushing.\n");
1064 *event
= pin
->event
;
1065 pin
->event
.type
= PARSER_EVENT_NONE
;
1067 pthread_mutex_unlock(&parser
->mutex
);
1068 pthread_cond_signal(&pin
->event_empty_cond
);
1073 static DWORD CALLBACK
stream_thread(void *arg
)
1075 struct parser_source
*pin
= arg
;
1076 struct parser
*filter
= impl_from_strmbase_filter(pin
->pin
.pin
.filter
);
1078 TRACE("Starting streaming thread for pin %p.\n", pin
);
1080 while (filter
->streaming
)
1082 struct parser_event event
;
1084 EnterCriticalSection(&pin
->flushing_cs
);
1086 if (!get_stream_event(pin
, &event
))
1088 LeaveCriticalSection(&pin
->flushing_cs
);
1092 TRACE("Got event of type %#x.\n", event
.type
);
1096 case PARSER_EVENT_BUFFER
:
1097 send_buffer(pin
, event
.u
.buffer
);
1100 case PARSER_EVENT_EOS
:
1101 IPin_EndOfStream(pin
->pin
.pin
.peer
);
1104 case PARSER_EVENT_SEGMENT
:
1105 IPin_NewSegment(pin
->pin
.pin
.peer
, event
.u
.segment
.position
,
1106 event
.u
.segment
.stop
, event
.u
.segment
.rate
);
1109 case PARSER_EVENT_NONE
:
1113 LeaveCriticalSection(&pin
->flushing_cs
);
1116 TRACE("Streaming stopped; exiting.\n");
1120 static GstFlowReturn
request_buffer_src(GstPad
*pad
, GstObject
*parent
, guint64 offset
, guint size
, GstBuffer
**buffer
)
1122 struct parser
*filter
= gst_pad_get_element_private(pad
);
1123 struct wg_parser
*parser
= filter
->wg_parser
;
1124 GstBuffer
*new_buffer
= NULL
;
1127 GST_LOG("pad %p, offset %" G_GINT64_MODIFIER
"u, length %u, buffer %p.", pad
, offset
, size
, *buffer
);
1130 *buffer
= new_buffer
= gst_buffer_new_and_alloc(size
);
1132 pthread_mutex_lock(&parser
->mutex
);
1134 assert(!parser
->read_request
.buffer
);
1135 parser
->read_request
.buffer
= *buffer
;
1136 parser
->read_request
.offset
= offset
;
1137 parser
->read_request
.size
= size
;
1138 parser
->read_request
.done
= false;
1139 pthread_cond_signal(&parser
->read_cond
);
1141 /* Note that we don't unblock this wait on GST_EVENT_FLUSH_START. We expect
1142 * the upstream pin to flush if necessary. We should never be blocked on
1143 * read_thread() not running. */
1145 while (!parser
->read_request
.done
)
1146 pthread_cond_wait(&parser
->read_done_cond
, &parser
->mutex
);
1148 ret
= parser
->read_request
.ret
;
1150 pthread_mutex_unlock(&parser
->mutex
);
1152 GST_LOG("Request returned %s.", gst_flow_get_name(ret
));
1154 if (ret
!= GST_FLOW_OK
&& new_buffer
)
1155 gst_buffer_unref(new_buffer
);
1160 static GstFlowReturn
read_buffer(struct parser
*This
, guint64 ofs
, guint len
, GstBuffer
*buffer
)
1165 TRACE("filter %p, offset %s, length %u, buffer %p.\n", This
, wine_dbgstr_longlong(ofs
), len
, buffer
);
1167 if (ofs
== GST_BUFFER_OFFSET_NONE
)
1168 ofs
= This
->next_pull_offset
;
1169 if (ofs
>= This
->file_size
)
1171 WARN("Reading past eof: %s, %u\n", wine_dbgstr_longlong(ofs
), len
);
1172 return GST_FLOW_EOS
;
1174 if (len
+ ofs
> This
->file_size
)
1175 len
= This
->file_size
- ofs
;
1176 This
->next_pull_offset
= ofs
+ len
;
1178 gst_buffer_map(buffer
, &info
, GST_MAP_WRITE
);
1179 hr
= IAsyncReader_SyncRead(This
->reader
, ofs
, len
, info
.data
);
1180 gst_buffer_unmap(buffer
, &info
);
1183 ERR("Failed to read data, hr %#x.\n", hr
);
1184 return GST_FLOW_ERROR
;
1190 static DWORD CALLBACK
read_thread(void *arg
)
1192 struct parser
*filter
= arg
;
1193 struct wg_parser
*parser
= filter
->wg_parser
;
1195 TRACE("Starting read thread for filter %p.\n", filter
);
1197 pthread_mutex_lock(&parser
->mutex
);
1199 while (filter
->sink_connected
)
1201 while (parser
->sink_connected
&& !parser
->read_request
.buffer
)
1202 pthread_cond_wait(&parser
->read_cond
, &parser
->mutex
);
1204 if (!parser
->sink_connected
)
1207 parser
->read_request
.done
= true;
1208 parser
->read_request
.ret
= read_buffer(filter
, parser
->read_request
.offset
,
1209 parser
->read_request
.size
, parser
->read_request
.buffer
);
1210 parser
->read_request
.buffer
= NULL
;
1211 pthread_cond_signal(&parser
->read_done_cond
);
1214 pthread_mutex_unlock(&parser
->mutex
);
1216 TRACE("Streaming stopped; exiting.\n");
1220 static void removed_decoded_pad(GstElement
*bin
, GstPad
*pad
, gpointer user
)
1222 struct parser
*filter
= user
;
1226 GST_LOG("filter %p, bin %p, pad %p.", filter
, bin
, pad
);
1228 for (i
= 0; i
< filter
->source_count
; ++i
)
1230 struct wg_parser_stream
*stream
= filter
->sources
[i
]->wg_stream
;
1232 if (stream
->their_src
== pad
)
1234 if (stream
->post_sink
)
1235 gst_pad_unlink(stream
->their_src
, stream
->post_sink
);
1237 gst_pad_unlink(stream
->their_src
, stream
->my_sink
);
1238 gst_object_unref(stream
->their_src
);
1239 stream
->their_src
= NULL
;
1244 name
= gst_pad_get_name(pad
);
1245 GST_LOG("No pin matching pad \"%s\" found.", name
);
1249 static void init_new_decoded_pad(GstElement
*bin
, GstPad
*pad
, struct parser
*This
)
1251 static const WCHAR formatW
[] = {'S','t','r','e','a','m',' ','%','0','2','u',0};
1252 struct wg_parser
*parser
= This
->wg_parser
;
1253 struct wg_parser_stream
*stream
;
1254 const char *typename
;
1258 struct parser_source
*pin
;
1262 TRACE("%p %p %p\n", This
, bin
, pad
);
1264 sprintfW(nameW
, formatW
, This
->source_count
);
1266 name
= gst_pad_get_name(pad
);
1267 TRACE("Name: %s\n", name
);
1270 caps
= gst_pad_query_caps(pad
, NULL
);
1271 caps
= gst_caps_make_writable(caps
);
1272 arg
= gst_caps_get_structure(caps
, 0);
1273 typename
= gst_structure_get_name(arg
);
1275 if (!(pin
= create_pin(This
, nameW
)))
1277 ERR("Failed to allocate memory.\n");
1280 stream
= pin
->wg_stream
;
1282 if (!strcmp(typename
, "video/x-raw"))
1284 GstElement
*deinterlace
, *vconv
, *flip
, *vconv2
;
1286 /* DirectShow can express interlaced video, but downstream filters can't
1287 * necessarily consume it. In particular, the video renderer can't. */
1288 if (!(deinterlace
= gst_element_factory_make("deinterlace", NULL
)))
1290 ERR("Failed to create deinterlace, are %u-bit GStreamer \"good\" plugins installed?\n",
1291 8 * (int)sizeof(void *));
1295 /* decodebin considers many YUV formats to be "raw", but some quartz
1296 * filters can't handle those. Also, videoflip can't handle all "raw"
1297 * formats either. Add a videoconvert to swap color spaces. */
1298 if (!(vconv
= gst_element_factory_make("videoconvert", NULL
)))
1300 ERR("Failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
1301 8 * (int)sizeof(void *));
1305 /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */
1306 if (!(flip
= gst_element_factory_make("videoflip", NULL
)))
1308 ERR("Failed to create videoflip, are %u-bit GStreamer \"good\" plugins installed?\n",
1309 8 * (int)sizeof(void *));
1313 /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert
1314 * to do the final conversion. */
1315 if (!(vconv2
= gst_element_factory_make("videoconvert", NULL
)))
1317 ERR("Failed to create videoconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
1318 8 * (int)sizeof(void *));
1322 /* The bin takes ownership of these elements. */
1323 gst_bin_add(GST_BIN(parser
->container
), deinterlace
);
1324 gst_element_sync_state_with_parent(deinterlace
);
1325 gst_bin_add(GST_BIN(parser
->container
), vconv
);
1326 gst_element_sync_state_with_parent(vconv
);
1327 gst_bin_add(GST_BIN(parser
->container
), flip
);
1328 gst_element_sync_state_with_parent(flip
);
1329 gst_bin_add(GST_BIN(parser
->container
), vconv2
);
1330 gst_element_sync_state_with_parent(vconv2
);
1332 gst_element_link(deinterlace
, vconv
);
1333 gst_element_link(vconv
, flip
);
1334 gst_element_link(flip
, vconv2
);
1336 stream
->post_sink
= gst_element_get_static_pad(deinterlace
, "sink");
1337 stream
->post_src
= gst_element_get_static_pad(vconv2
, "src");
1338 stream
->flip
= flip
;
1340 else if (!strcmp(typename
, "audio/x-raw"))
1342 GstElement
*convert
;
1344 /* Currently our dsound can't handle 64-bit formats or all
1345 * surround-sound configurations. Native dsound can't always handle
1346 * 64-bit formats either. Add an audioconvert to allow changing bit
1347 * depth and channel count. */
1348 if (!(convert
= gst_element_factory_make("audioconvert", NULL
)))
1350 ERR("Failed to create audioconvert, are %u-bit GStreamer \"base\" plugins installed?\n",
1351 8 * (int)sizeof(void *));
1355 gst_bin_add(GST_BIN(parser
->container
), convert
);
1356 gst_element_sync_state_with_parent(convert
);
1358 stream
->post_sink
= gst_element_get_static_pad(convert
, "sink");
1359 stream
->post_src
= gst_element_get_static_pad(convert
, "src");
1362 if (stream
->post_sink
)
1364 if ((ret
= gst_pad_link(pad
, stream
->post_sink
)) < 0)
1366 ERR("Failed to link decodebin source pad to post-processing elements, error %s.\n",
1367 gst_pad_link_get_name(ret
));
1368 gst_object_unref(stream
->post_sink
);
1369 stream
->post_sink
= NULL
;
1373 if ((ret
= gst_pad_link(stream
->post_src
, stream
->my_sink
)) < 0)
1375 ERR("Failed to link post-processing elements to our sink pad, error %s.\n",
1376 gst_pad_link_get_name(ret
));
1377 gst_object_unref(stream
->post_src
);
1378 stream
->post_src
= NULL
;
1379 gst_object_unref(stream
->post_sink
);
1380 stream
->post_sink
= NULL
;
1384 else if ((ret
= gst_pad_link(pad
, stream
->my_sink
)) < 0)
1386 ERR("Failed to link decodebin source pad to our sink pad, error %s.\n",
1387 gst_pad_link_get_name(ret
));
1391 gst_pad_set_active(stream
->my_sink
, 1);
1392 gst_object_ref(stream
->their_src
= pad
);
1394 gst_caps_unref(caps
);
1397 static void existing_new_pad(GstElement
*bin
, GstPad
*pad
, gpointer user
)
1399 struct parser
*This
= user
;
1401 TRACE("%p %p %p\n", This
, bin
, pad
);
1403 if (gst_pad_is_linked(pad
))
1406 init_new_decoded_pad(bin
, pad
, This
);
1409 static gboolean
query_function(GstPad
*pad
, GstObject
*parent
, GstQuery
*query
)
1411 struct parser
*This
= gst_pad_get_element_private(pad
);
1412 struct wg_parser
*parser
= This
->wg_parser
;
1415 GST_LOG("filter %p, type %s.", This
, GST_QUERY_TYPE_NAME(query
));
1417 switch (GST_QUERY_TYPE(query
)) {
1418 case GST_QUERY_DURATION
:
1419 gst_query_parse_duration(query
, &format
, NULL
);
1420 if (format
== GST_FORMAT_PERCENT
)
1422 gst_query_set_duration(query
, GST_FORMAT_PERCENT
, GST_FORMAT_PERCENT_MAX
);
1425 else if (format
== GST_FORMAT_BYTES
)
1427 gst_query_set_duration(query
, GST_FORMAT_BYTES
, parser
->file_size
);
1431 case GST_QUERY_SEEKING
:
1432 gst_query_parse_seeking (query
, &format
, NULL
, NULL
, NULL
);
1433 if (format
!= GST_FORMAT_BYTES
)
1435 GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format
));
1438 gst_query_set_seeking(query
, GST_FORMAT_BYTES
, 1, 0, parser
->file_size
);
1440 case GST_QUERY_SCHEDULING
:
1441 gst_query_set_scheduling(query
, GST_SCHEDULING_FLAG_SEEKABLE
, 1, -1, 0);
1442 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PUSH
);
1443 gst_query_add_scheduling_mode(query
, GST_PAD_MODE_PULL
);
1446 GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query
));
1451 static gboolean
activate_push(GstPad
*pad
, gboolean activate
)
1453 struct parser
*This
= gst_pad_get_element_private(pad
);
1454 struct wg_parser
*parser
= This
->wg_parser
;
1457 if (parser
->push_thread
) {
1458 pthread_join(parser
->push_thread
, NULL
);
1459 parser
->push_thread
= 0;
1461 if (This
->filter
.state
== State_Stopped
)
1462 parser
->next_offset
= parser
->start_offset
;
1463 } else if (!parser
->push_thread
) {
1466 if ((ret
= pthread_create(&parser
->push_thread
, NULL
, push_data
, This
)))
1468 GST_ERROR("Failed to create push thread: %s", strerror(errno
));
1469 parser
->push_thread
= 0;
1476 static gboolean
activate_mode(GstPad
*pad
, GstObject
*parent
, GstPadMode mode
, gboolean activate
)
1478 struct parser
*filter
= gst_pad_get_element_private(pad
);
1480 GST_DEBUG("%s source pad for filter %p in %s mode.",
1481 activate
? "Activating" : "Deactivating", filter
, gst_pad_mode_get_name(mode
));
1484 case GST_PAD_MODE_PULL
:
1486 case GST_PAD_MODE_PUSH
:
1487 return activate_push(pad
, activate
);
1494 static void no_more_pads(GstElement
*decodebin
, gpointer user
)
1496 struct parser
*filter
= user
;
1497 struct wg_parser
*parser
= filter
->wg_parser
;
1499 GST_DEBUG("filter %p.", filter
);
1501 pthread_mutex_lock(&parser
->mutex
);
1502 parser
->no_more_pads
= true;
1503 pthread_mutex_unlock(&parser
->mutex
);
1504 pthread_cond_signal(&parser
->init_cond
);
1507 static GstAutoplugSelectResult
autoplug_blacklist(GstElement
*bin
, GstPad
*pad
, GstCaps
*caps
, GstElementFactory
*fact
, gpointer user
)
1509 const char *name
= gst_element_factory_get_longname(fact
);
1511 GST_TRACE("Using \"%s\".", name
);
1513 if (strstr(name
, "Player protection"))
1515 GST_WARNING("Blacklisted a/52 decoder because it only works in Totem.");
1516 return GST_AUTOPLUG_SELECT_SKIP
;
1518 if (!strcmp(name
, "Fluendo Hardware Accelerated Video Decoder"))
1520 GST_WARNING("Disabled video acceleration since it breaks in wine.");
1521 return GST_AUTOPLUG_SELECT_SKIP
;
1523 return GST_AUTOPLUG_SELECT_TRY
;
1526 static GstBusSyncReply
watch_bus(GstBus
*bus
, GstMessage
*msg
, gpointer data
)
1528 struct parser
*filter
= data
;
1529 struct wg_parser
*parser
= filter
->wg_parser
;
1531 gchar
*dbg_info
= NULL
;
1533 GST_DEBUG("filter %p, message type %s.", filter
, GST_MESSAGE_TYPE_NAME(msg
));
1537 case GST_MESSAGE_ERROR
:
1538 gst_message_parse_error(msg
, &err
, &dbg_info
);
1539 fprintf(stderr
, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg
->src
), err
->message
);
1540 fprintf(stderr
, "winegstreamer: error: %s: %s\n", GST_OBJECT_NAME(msg
->src
), dbg_info
);
1543 pthread_mutex_lock(&parser
->mutex
);
1544 parser
->error
= true;
1545 pthread_mutex_unlock(&parser
->mutex
);
1546 pthread_cond_signal(&parser
->init_cond
);
1549 case GST_MESSAGE_WARNING
:
1550 gst_message_parse_warning(msg
, &err
, &dbg_info
);
1551 fprintf(stderr
, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg
->src
), err
->message
);
1552 fprintf(stderr
, "winegstreamer: warning: %s: %s\n", GST_OBJECT_NAME(msg
->src
), dbg_info
);
1557 case GST_MESSAGE_DURATION_CHANGED
:
1558 pthread_mutex_lock(&parser
->mutex
);
1559 parser
->has_duration
= true;
1560 pthread_mutex_unlock(&parser
->mutex
);
1561 pthread_cond_signal(&parser
->init_cond
);
1567 gst_message_unref(msg
);
1568 return GST_BUS_DROP
;
1571 static LONGLONG
query_duration(GstPad
*pad
)
1573 gint64 duration
, byte_length
;
1575 if (gst_pad_query_duration(pad
, GST_FORMAT_TIME
, &duration
))
1576 return duration
/ 100;
1578 WARN("Failed to query time duration; trying to convert from byte length.\n");
1580 /* To accurately get a duration for the stream, we want to only consider the
1581 * length of that stream. Hence, query for the pad duration, instead of
1582 * using the file duration. */
1583 if (gst_pad_query_duration(pad
, GST_FORMAT_BYTES
, &byte_length
)
1584 && gst_pad_query_convert(pad
, GST_FORMAT_BYTES
, byte_length
, GST_FORMAT_TIME
, &duration
))
1585 return duration
/ 100;
1587 ERR("Failed to query duration.\n");
1591 static HRESULT
GST_Connect(struct parser
*This
, IPin
*pConnectPin
)
1593 struct wg_parser
*parser
= This
->wg_parser
;
1596 GstStaticPadTemplate src_template
= GST_STATIC_PAD_TEMPLATE(
1600 GST_STATIC_CAPS_ANY
);
1602 IAsyncReader_Length(This
->reader
, &This
->file_size
, &avail
);
1603 parser
->file_size
= This
->file_size
;
1605 This
->sink_connected
= true;
1606 parser
->sink_connected
= true;
1608 This
->read_thread
= CreateThread(NULL
, 0, read_thread
, This
, 0, NULL
);
1612 parser
->bus
= gst_bus_new();
1613 gst_bus_set_sync_handler(parser
->bus
, watch_bus
, This
, NULL
);
1616 parser
->container
= gst_bin_new(NULL
);
1617 gst_element_set_bus(parser
->container
, parser
->bus
);
1619 parser
->my_src
= gst_pad_new_from_static_template(&src_template
, "quartz-src");
1620 gst_pad_set_getrange_function(parser
->my_src
, request_buffer_src
);
1621 gst_pad_set_query_function(parser
->my_src
, query_function
);
1622 gst_pad_set_activatemode_function(parser
->my_src
, activate_mode
);
1623 gst_pad_set_event_function(parser
->my_src
, event_src
);
1624 gst_pad_set_element_private (parser
->my_src
, This
);
1626 parser
->start_offset
= parser
->next_offset
= parser
->stop_offset
= 0;
1627 This
->next_pull_offset
= 0;
1629 if (!This
->init_gst(This
))
1632 pthread_mutex_lock(&parser
->mutex
);
1634 for (i
= 0; i
< This
->source_count
; ++i
)
1636 struct parser_source
*pin
= This
->sources
[i
];
1637 struct wg_parser_stream
*stream
= pin
->wg_stream
;
1639 pin
->seek
.llDuration
= pin
->seek
.llStop
= query_duration(stream
->their_src
);
1640 pin
->seek
.llCurrent
= 0;
1641 while (!pin
->caps
&& !parser
->error
)
1642 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1645 pthread_mutex_unlock(&parser
->mutex
);
1650 pthread_mutex_unlock(&parser
->mutex
);
1652 parser
->next_offset
= 0;
1653 This
->next_pull_offset
= 0;
1657 static inline struct parser_source
*impl_from_IMediaSeeking(IMediaSeeking
*iface
)
1659 return CONTAINING_RECORD(iface
, struct parser_source
, seek
.IMediaSeeking_iface
);
1662 static struct strmbase_pin
*parser_get_pin(struct strmbase_filter
*base
, unsigned int index
)
1664 struct parser
*filter
= impl_from_strmbase_filter(base
);
1666 if (filter
->enum_sink_first
)
1669 return &filter
->sink
.pin
;
1670 else if (index
<= filter
->source_count
)
1671 return &filter
->sources
[index
- 1]->pin
.pin
;
1675 if (index
< filter
->source_count
)
1676 return &filter
->sources
[index
]->pin
.pin
;
1677 else if (index
== filter
->source_count
)
1678 return &filter
->sink
.pin
;
1683 static void wg_parser_destroy(struct wg_parser
*parser
)
1687 gst_bus_set_sync_handler(parser
->bus
, NULL
, NULL
, NULL
);
1688 gst_object_unref(parser
->bus
);
1691 pthread_mutex_destroy(&parser
->mutex
);
1692 pthread_cond_destroy(&parser
->init_cond
);
1693 pthread_cond_destroy(&parser
->read_cond
);
1694 pthread_cond_destroy(&parser
->read_done_cond
);
1699 static void parser_destroy(struct strmbase_filter
*iface
)
1701 struct parser
*filter
= impl_from_strmbase_filter(iface
);
1704 /* Don't need to clean up output pins, disconnecting input pin will do that */
1705 if (filter
->sink
.pin
.peer
)
1707 hr
= IPin_Disconnect(filter
->sink
.pin
.peer
);
1709 hr
= IPin_Disconnect(&filter
->sink
.pin
.IPin_iface
);
1714 IAsyncReader_Release(filter
->reader
);
1715 filter
->reader
= NULL
;
1717 wg_parser_destroy(filter
->wg_parser
);
1719 strmbase_sink_cleanup(&filter
->sink
);
1720 strmbase_filter_cleanup(&filter
->filter
);
1724 static HRESULT
parser_init_stream(struct strmbase_filter
*iface
)
1726 struct parser
*filter
= impl_from_strmbase_filter(iface
);
1727 struct wg_parser
*parser
= filter
->wg_parser
;
1728 GstSeekType stop_type
= GST_SEEK_TYPE_NONE
;
1729 const SourceSeeking
*seeking
;
1732 if (!parser
->container
)
1735 filter
->streaming
= true;
1736 pthread_mutex_lock(&parser
->mutex
);
1737 parser
->flushing
= false;
1738 pthread_mutex_unlock(&parser
->mutex
);
1740 /* DirectShow retains the old seek positions, but resets to them every time
1741 * it transitions from stopped -> paused. */
1743 seeking
= &filter
->sources
[0]->seek
;
1744 if (seeking
->llStop
&& seeking
->llStop
!= seeking
->llDuration
)
1745 stop_type
= GST_SEEK_TYPE_SET
;
1746 gst_pad_push_event(filter
->sources
[0]->wg_stream
->my_sink
, gst_event_new_seek(
1747 seeking
->dRate
, GST_FORMAT_TIME
, GST_SEEK_FLAG_FLUSH
,
1748 GST_SEEK_TYPE_SET
, seeking
->llCurrent
* 100,
1749 stop_type
, seeking
->llStop
* 100));
1751 for (i
= 0; i
< filter
->source_count
; ++i
)
1755 if (!filter
->sources
[i
]->pin
.pin
.peer
)
1758 if (FAILED(hr
= IMemAllocator_Commit(filter
->sources
[i
]->pin
.pAllocator
)))
1759 ERR("Failed to commit allocator, hr %#x.\n", hr
);
1761 filter
->sources
[i
]->thread
= CreateThread(NULL
, 0, stream_thread
, filter
->sources
[i
], 0, NULL
);
1767 static HRESULT
parser_cleanup_stream(struct strmbase_filter
*iface
)
1769 struct parser
*filter
= impl_from_strmbase_filter(iface
);
1770 struct wg_parser
*parser
= filter
->wg_parser
;
1773 if (!parser
->container
)
1776 filter
->streaming
= false;
1777 pthread_mutex_lock(&parser
->mutex
);
1778 parser
->flushing
= true;
1779 pthread_mutex_unlock(&parser
->mutex
);
1781 for (i
= 0; i
< filter
->source_count
; ++i
)
1783 struct parser_source
*pin
= filter
->sources
[i
];
1785 if (!pin
->pin
.pin
.peer
)
1788 pthread_cond_signal(&pin
->event_cond
);
1791 for (i
= 0; i
< filter
->source_count
; ++i
)
1793 struct parser_source
*pin
= filter
->sources
[i
];
1795 if (!pin
->pin
.pin
.peer
)
1798 IMemAllocator_Decommit(pin
->pin
.pAllocator
);
1800 WaitForSingleObject(pin
->thread
, INFINITE
);
1801 CloseHandle(pin
->thread
);
1808 static const struct strmbase_filter_ops filter_ops
=
1810 .filter_get_pin
= parser_get_pin
,
1811 .filter_destroy
= parser_destroy
,
1812 .filter_init_stream
= parser_init_stream
,
1813 .filter_cleanup_stream
= parser_cleanup_stream
,
1816 static inline struct parser
*impl_from_strmbase_sink(struct strmbase_sink
*iface
)
1818 return CONTAINING_RECORD(iface
, struct parser
, sink
);
1821 static HRESULT
sink_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
1823 if (IsEqualGUID(&mt
->majortype
, &MEDIATYPE_Stream
))
1828 static HRESULT
parser_sink_connect(struct strmbase_sink
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*pmt
)
1830 struct parser
*filter
= impl_from_strmbase_sink(iface
);
1835 filter
->reader
= NULL
;
1836 if (FAILED(hr
= IPin_QueryInterface(peer
, &IID_IAsyncReader
, (void **)&filter
->reader
)))
1839 if (FAILED(hr
= GST_Connect(filter
, peer
)))
1844 GST_RemoveOutputPins(filter
);
1845 IAsyncReader_Release(filter
->reader
);
1846 filter
->reader
= NULL
;
1850 static void parser_sink_disconnect(struct strmbase_sink
*iface
)
1852 struct parser
*filter
= impl_from_strmbase_sink(iface
);
1856 GST_RemoveOutputPins(filter
);
1858 IAsyncReader_Release(filter
->reader
);
1859 filter
->reader
= NULL
;
1862 static const struct strmbase_sink_ops sink_ops
=
1864 .base
.pin_query_accept
= sink_query_accept
,
1865 .sink_connect
= parser_sink_connect
,
1866 .sink_disconnect
= parser_sink_disconnect
,
1869 static BOOL
decodebin_parser_init_gst(struct parser
*filter
)
1871 GstElement
*element
= gst_element_factory_make("decodebin", NULL
);
1872 struct wg_parser
*parser
= filter
->wg_parser
;
1877 ERR("Failed to create decodebin; are %u-bit GStreamer \"base\" plugins installed?\n",
1878 8 * (int)sizeof(void*));
1882 gst_bin_add(GST_BIN(parser
->container
), element
);
1884 g_signal_connect(element
, "pad-added", G_CALLBACK(existing_new_pad_wrapper
), filter
);
1885 g_signal_connect(element
, "pad-removed", G_CALLBACK(removed_decoded_pad
), filter
);
1886 g_signal_connect(element
, "autoplug-select", G_CALLBACK(autoplug_blacklist
), filter
);
1887 g_signal_connect(element
, "no-more-pads", G_CALLBACK(no_more_pads
), filter
);
1889 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
1891 pthread_mutex_lock(&parser
->mutex
);
1892 parser
->no_more_pads
= parser
->error
= false;
1893 pthread_mutex_unlock(&parser
->mutex
);
1895 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
1897 ERR("Failed to link pads, error %d.\n", ret
);
1901 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
1902 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
1903 if (ret
== GST_STATE_CHANGE_FAILURE
)
1905 ERR("Failed to play stream.\n");
1909 pthread_mutex_lock(&parser
->mutex
);
1910 while (!parser
->no_more_pads
&& !parser
->error
)
1911 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
1914 pthread_mutex_unlock(&parser
->mutex
);
1917 pthread_mutex_unlock(&parser
->mutex
);
1921 static HRESULT
decodebin_parser_source_query_accept(struct parser_source
*pin
, const AM_MEDIA_TYPE
*mt
)
1923 /* At least make sure we can convert it to GstCaps. */
1924 GstCaps
*caps
= amt_to_gst_caps(mt
);
1928 gst_caps_unref(caps
);
1932 static HRESULT
decodebin_parser_source_get_media_type(struct parser_source
*pin
,
1933 unsigned int index
, AM_MEDIA_TYPE
*mt
)
1935 const GstCaps
*caps
= pin
->caps
;
1936 const GstStructure
*structure
;
1939 static const GstVideoFormat video_formats
[] =
1941 /* Try to prefer YUV formats over RGB ones. Most decoders output in the
1942 * YUV color space, and it's generally much less expensive for
1943 * videoconvert to do YUV -> YUV transformations. */
1944 GST_VIDEO_FORMAT_AYUV
,
1945 GST_VIDEO_FORMAT_I420
,
1946 GST_VIDEO_FORMAT_YV12
,
1947 GST_VIDEO_FORMAT_YUY2
,
1948 GST_VIDEO_FORMAT_UYVY
,
1949 GST_VIDEO_FORMAT_YVYU
,
1950 GST_VIDEO_FORMAT_NV12
,
1951 GST_VIDEO_FORMAT_BGRA
,
1952 GST_VIDEO_FORMAT_BGRx
,
1953 GST_VIDEO_FORMAT_BGR
,
1954 GST_VIDEO_FORMAT_RGB16
,
1955 GST_VIDEO_FORMAT_RGB15
,
1958 assert(caps
); /* We shouldn't be able to get here if caps haven't been set. */
1959 structure
= gst_caps_get_structure(caps
, 0);
1960 type
= gst_structure_get_name(structure
);
1962 memset(mt
, 0, sizeof(AM_MEDIA_TYPE
));
1964 if (amt_from_gst_caps(caps
, mt
))
1971 if (!strcmp(type
, "video/x-raw") && index
< ARRAY_SIZE(video_formats
))
1973 gint width
, height
, fps_n
, fps_d
;
1976 gst_structure_get_int(structure
, "width", &width
);
1977 gst_structure_get_int(structure
, "height", &height
);
1978 gst_video_info_set_format(&info
, video_formats
[index
], width
, height
);
1979 if (gst_structure_get_fraction(structure
, "framerate", &fps_n
, &fps_d
) && fps_n
)
1984 if (!amt_from_gst_video_info(&info
, mt
))
1985 return E_OUTOFMEMORY
;
1988 else if (!strcmp(type
, "audio/x-raw") && !index
)
1993 gst_structure_get_int(structure
, "rate", &rate
);
1994 gst_audio_info_set_format(&info
, GST_AUDIO_FORMAT_S16LE
, rate
, 2, NULL
);
1995 if (!amt_from_gst_audio_info(&info
, mt
))
1996 return E_OUTOFMEMORY
;
2000 return VFW_S_NO_MORE_ITEMS
;
2003 static BOOL
parser_init_gstreamer(void)
2005 if (!init_gstreamer())
2007 GST_DEBUG_CATEGORY_INIT(wine
, "WINE", GST_DEBUG_FG_RED
, "Wine GStreamer support");
2011 static struct wg_parser
*wg_parser_create(void)
2013 struct wg_parser
*parser
;
2015 if (!(parser
= calloc(1, sizeof(*parser
))))
2018 pthread_mutex_init(&parser
->mutex
, NULL
);
2019 pthread_cond_init(&parser
->init_cond
, NULL
);
2020 pthread_cond_init(&parser
->read_cond
, NULL
);
2021 pthread_cond_init(&parser
->read_done_cond
, NULL
);
2022 parser
->flushing
= true;
2024 TRACE("Created winegstreamer parser %p.\n", parser
);
2028 HRESULT
decodebin_parser_create(IUnknown
*outer
, IUnknown
**out
)
2030 struct parser
*object
;
2032 if (!parser_init_gstreamer())
2037 if (!(object
= heap_alloc_zero(sizeof(*object
))))
2038 return E_OUTOFMEMORY
;
2040 if (!(object
->wg_parser
= wg_parser_create()))
2043 return E_OUTOFMEMORY
;
2046 strmbase_filter_init(&object
->filter
, outer
, &CLSID_decodebin_parser
, &filter_ops
);
2047 strmbase_sink_init(&object
->sink
, &object
->filter
, wcsInputPinName
, &sink_ops
, NULL
);
2049 object
->init_gst
= decodebin_parser_init_gst
;
2050 object
->source_query_accept
= decodebin_parser_source_query_accept
;
2051 object
->source_get_media_type
= decodebin_parser_source_get_media_type
;
2053 TRACE("Created GStreamer demuxer %p.\n", object
);
2054 *out
= &object
->filter
.IUnknown_inner
;
2058 static struct parser
*impl_from_IAMStreamSelect(IAMStreamSelect
*iface
)
2060 return CONTAINING_RECORD(iface
, struct parser
, IAMStreamSelect_iface
);
2063 static HRESULT WINAPI
stream_select_QueryInterface(IAMStreamSelect
*iface
, REFIID iid
, void **out
)
2065 struct parser
*filter
= impl_from_IAMStreamSelect(iface
);
2066 return IUnknown_QueryInterface(filter
->filter
.outer_unk
, iid
, out
);
2069 static ULONG WINAPI
stream_select_AddRef(IAMStreamSelect
*iface
)
2071 struct parser
*filter
= impl_from_IAMStreamSelect(iface
);
2072 return IUnknown_AddRef(filter
->filter
.outer_unk
);
2075 static ULONG WINAPI
stream_select_Release(IAMStreamSelect
*iface
)
2077 struct parser
*filter
= impl_from_IAMStreamSelect(iface
);
2078 return IUnknown_Release(filter
->filter
.outer_unk
);
2081 static HRESULT WINAPI
stream_select_Count(IAMStreamSelect
*iface
, DWORD
*count
)
2083 FIXME("iface %p, count %p, stub!\n", iface
, count
);
2087 static HRESULT WINAPI
stream_select_Info(IAMStreamSelect
*iface
, LONG index
,
2088 AM_MEDIA_TYPE
**mt
, DWORD
*flags
, LCID
*lcid
, DWORD
*group
, WCHAR
**name
,
2089 IUnknown
**object
, IUnknown
**unknown
)
2091 FIXME("iface %p, index %d, mt %p, flags %p, lcid %p, group %p, name %p, object %p, unknown %p, stub!\n",
2092 iface
, index
, mt
, flags
, lcid
, group
, name
, object
, unknown
);
2096 static HRESULT WINAPI
stream_select_Enable(IAMStreamSelect
*iface
, LONG index
, DWORD flags
)
2098 FIXME("iface %p, index %d, flags %#x, stub!\n", iface
, index
, flags
);
2102 static const IAMStreamSelectVtbl stream_select_vtbl
=
2104 stream_select_QueryInterface
,
2105 stream_select_AddRef
,
2106 stream_select_Release
,
2107 stream_select_Count
,
2109 stream_select_Enable
,
2112 static HRESULT WINAPI
GST_ChangeCurrent(IMediaSeeking
*iface
)
2114 struct parser_source
*This
= impl_from_IMediaSeeking(iface
);
2115 TRACE("(%p)\n", This
);
2119 static HRESULT WINAPI
GST_ChangeStop(IMediaSeeking
*iface
)
2121 struct parser_source
*This
= impl_from_IMediaSeeking(iface
);
2122 TRACE("(%p)\n", This
);
2126 static HRESULT WINAPI
GST_ChangeRate(IMediaSeeking
*iface
)
2128 struct parser_source
*This
= impl_from_IMediaSeeking(iface
);
2129 struct wg_parser_stream
*stream
= This
->wg_stream
;
2130 GstEvent
*ev
= gst_event_new_seek(This
->seek
.dRate
, GST_FORMAT_TIME
, 0, GST_SEEK_TYPE_NONE
, -1, GST_SEEK_TYPE_NONE
, -1);
2131 TRACE("(%p) New rate %g\n", This
, This
->seek
.dRate
);
2133 gst_pad_push_event(stream
->my_sink
, ev
);
2137 static HRESULT WINAPI
GST_Seeking_QueryInterface(IMediaSeeking
*iface
, REFIID riid
, void **ppv
)
2139 struct parser_source
*This
= impl_from_IMediaSeeking(iface
);
2140 return IPin_QueryInterface(&This
->pin
.pin
.IPin_iface
, riid
, ppv
);
2143 static ULONG WINAPI
GST_Seeking_AddRef(IMediaSeeking
*iface
)
2145 struct parser_source
*This
= impl_from_IMediaSeeking(iface
);
2146 return IPin_AddRef(&This
->pin
.pin
.IPin_iface
);
2149 static ULONG WINAPI
GST_Seeking_Release(IMediaSeeking
*iface
)
2151 struct parser_source
*This
= impl_from_IMediaSeeking(iface
);
2152 return IPin_Release(&This
->pin
.pin
.IPin_iface
);
2155 static HRESULT WINAPI
GST_Seeking_SetPositions(IMediaSeeking
*iface
,
2156 LONGLONG
*current
, DWORD current_flags
, LONGLONG
*stop
, DWORD stop_flags
)
2158 GstSeekType current_type
= GST_SEEK_TYPE_SET
, stop_type
= GST_SEEK_TYPE_SET
;
2159 struct parser_source
*pin
= impl_from_IMediaSeeking(iface
);
2160 struct wg_parser_stream
*stream
= pin
->wg_stream
;
2161 struct parser
*filter
= impl_from_strmbase_filter(pin
->pin
.pin
.filter
);
2162 struct wg_parser
*parser
= filter
->wg_parser
;
2163 GstSeekFlags flags
= 0;
2167 TRACE("pin %p, current %s, current_flags %#x, stop %s, stop_flags %#x.\n",
2168 pin
, current
? debugstr_time(*current
) : "<null>", current_flags
,
2169 stop
? debugstr_time(*stop
) : "<null>", stop_flags
);
2173 if (pin
->pin
.pin
.filter
->state
== State_Stopped
)
2175 SourceSeekingImpl_SetPositions(iface
, current
, current_flags
, stop
, stop_flags
);
2179 if (!(current_flags
& AM_SEEKING_NoFlush
))
2181 pthread_mutex_lock(&parser
->mutex
);
2182 parser
->flushing
= true;
2183 pthread_mutex_unlock(&parser
->mutex
);
2185 for (i
= 0; i
< filter
->source_count
; ++i
)
2187 if (filter
->sources
[i
]->pin
.pin
.peer
)
2189 pthread_cond_signal(&pin
->event_cond
);
2190 IPin_BeginFlush(filter
->sources
[i
]->pin
.pin
.peer
);
2195 IAsyncReader_BeginFlush(filter
->reader
);
2198 /* Acquire the flushing locks. This blocks the streaming threads, and
2199 * ensures the seek is serialized between flushes. */
2200 for (i
= 0; i
< filter
->source_count
; ++i
)
2202 if (filter
->sources
[i
]->pin
.pin
.peer
)
2203 EnterCriticalSection(&pin
->flushing_cs
);
2206 SourceSeekingImpl_SetPositions(iface
, current
, current_flags
, stop
, stop_flags
);
2208 if (current_flags
& AM_SEEKING_SeekToKeyFrame
)
2209 flags
|= GST_SEEK_FLAG_KEY_UNIT
;
2210 if (current_flags
& AM_SEEKING_Segment
)
2211 flags
|= GST_SEEK_FLAG_SEGMENT
;
2212 if (!(current_flags
& AM_SEEKING_NoFlush
))
2213 flags
|= GST_SEEK_FLAG_FLUSH
;
2215 if ((current_flags
& AM_SEEKING_PositioningBitsMask
) == AM_SEEKING_NoPositioning
)
2216 current_type
= GST_SEEK_TYPE_NONE
;
2217 if ((stop_flags
& AM_SEEKING_PositioningBitsMask
) == AM_SEEKING_NoPositioning
)
2218 stop_type
= GST_SEEK_TYPE_NONE
;
2220 if (!gst_pad_push_event(stream
->my_sink
, gst_event_new_seek(pin
->seek
.dRate
, GST_FORMAT_TIME
, flags
,
2221 current_type
, pin
->seek
.llCurrent
* 100, stop_type
, pin
->seek
.llStop
* 100)))
2223 ERR("Failed to seek (current %s, stop %s).\n",
2224 debugstr_time(pin
->seek
.llCurrent
), debugstr_time(pin
->seek
.llStop
));
2228 if (!(current_flags
& AM_SEEKING_NoFlush
))
2230 pthread_mutex_lock(&parser
->mutex
);
2231 parser
->flushing
= false;
2232 pthread_mutex_unlock(&parser
->mutex
);
2234 for (i
= 0; i
< filter
->source_count
; ++i
)
2236 if (filter
->sources
[i
]->pin
.pin
.peer
)
2237 IPin_EndFlush(filter
->sources
[i
]->pin
.pin
.peer
);
2241 IAsyncReader_EndFlush(filter
->reader
);
2244 /* Release the flushing locks. */
2245 for (i
= filter
->source_count
- 1; i
>= 0; --i
)
2247 if (filter
->sources
[i
]->pin
.pin
.peer
)
2248 LeaveCriticalSection(&pin
->flushing_cs
);
2254 static const IMediaSeekingVtbl GST_Seeking_Vtbl
=
2256 GST_Seeking_QueryInterface
,
2258 GST_Seeking_Release
,
2259 SourceSeekingImpl_GetCapabilities
,
2260 SourceSeekingImpl_CheckCapabilities
,
2261 SourceSeekingImpl_IsFormatSupported
,
2262 SourceSeekingImpl_QueryPreferredFormat
,
2263 SourceSeekingImpl_GetTimeFormat
,
2264 SourceSeekingImpl_IsUsingTimeFormat
,
2265 SourceSeekingImpl_SetTimeFormat
,
2266 SourceSeekingImpl_GetDuration
,
2267 SourceSeekingImpl_GetStopPosition
,
2268 SourceSeekingImpl_GetCurrentPosition
,
2269 SourceSeekingImpl_ConvertTimeFormat
,
2270 GST_Seeking_SetPositions
,
2271 SourceSeekingImpl_GetPositions
,
2272 SourceSeekingImpl_GetAvailable
,
2273 SourceSeekingImpl_SetRate
,
2274 SourceSeekingImpl_GetRate
,
2275 SourceSeekingImpl_GetPreroll
2278 static inline struct parser_source
*impl_from_IQualityControl( IQualityControl
*iface
)
2280 return CONTAINING_RECORD(iface
, struct parser_source
, IQualityControl_iface
);
2283 static HRESULT WINAPI
GST_QualityControl_QueryInterface(IQualityControl
*iface
, REFIID riid
, void **ppv
)
2285 struct parser_source
*pin
= impl_from_IQualityControl(iface
);
2286 return IPin_QueryInterface(&pin
->pin
.pin
.IPin_iface
, riid
, ppv
);
2289 static ULONG WINAPI
GST_QualityControl_AddRef(IQualityControl
*iface
)
2291 struct parser_source
*pin
= impl_from_IQualityControl(iface
);
2292 return IPin_AddRef(&pin
->pin
.pin
.IPin_iface
);
2295 static ULONG WINAPI
GST_QualityControl_Release(IQualityControl
*iface
)
2297 struct parser_source
*pin
= impl_from_IQualityControl(iface
);
2298 return IPin_Release(&pin
->pin
.pin
.IPin_iface
);
2301 static HRESULT WINAPI
GST_QualityControl_Notify(IQualityControl
*iface
, IBaseFilter
*sender
, Quality q
)
2303 struct parser_source
*pin
= impl_from_IQualityControl(iface
);
2304 struct wg_parser_stream
*stream
= pin
->wg_stream
;
2305 GstQOSType type
= GST_QOS_TYPE_OVERFLOW
;
2306 GstClockTime timestamp
;
2307 GstClockTimeDiff diff
;
2310 TRACE("pin %p, sender %p, type %s, proportion %u, late %s, timestamp %s.\n",
2311 pin
, sender
, q
.Type
== Famine
? "Famine" : "Flood", q
.Proportion
,
2312 debugstr_time(q
.Late
), debugstr_time(q
.TimeStamp
));
2316 /* GST_QOS_TYPE_OVERFLOW is also used for buffers that arrive on time, but
2317 * DirectShow filters might use Famine, so check that there actually is an
2319 if (q
.Type
== Famine
&& q
.Proportion
< 1000)
2320 type
= GST_QOS_TYPE_UNDERFLOW
;
2322 /* DirectShow filters sometimes pass negative timestamps (Audiosurf uses the
2323 * current time instead of the time of the last buffer). GstClockTime is
2324 * unsigned, so clamp it to 0. */
2325 timestamp
= max(q
.TimeStamp
* 100, 0);
2327 /* The documentation specifies that timestamp + diff must be nonnegative. */
2328 diff
= q
.Late
* 100;
2329 if (diff
< 0 && timestamp
< (GstClockTime
)-diff
)
2332 /* DirectShow "Proportion" describes what percentage of buffers the upstream
2333 * filter should keep (i.e. dropping the rest). If frames are late, the
2334 * proportion will be less than 1. For example, a proportion of 500 means
2335 * that the element should drop half of its frames, essentially because
2336 * frames are taking twice as long as they should to arrive.
2338 * GStreamer "proportion" is the inverse of this; it describes how much
2339 * faster the upstream element should produce frames. I.e. if frames are
2340 * taking twice as long as they should to arrive, we want the frames to be
2341 * decoded twice as fast, and so we pass 2.0 to GStreamer. */
2345 WARN("Ignoring quality message with zero proportion.\n");
2349 if (!(event
= gst_event_new_qos(type
, 1000.0 / q
.Proportion
, diff
, timestamp
)))
2350 ERR("Failed to create QOS event.\n");
2352 gst_pad_push_event(stream
->my_sink
, event
);
2357 static HRESULT WINAPI
GST_QualityControl_SetSink(IQualityControl
*iface
, IQualityControl
*tonotify
)
2359 struct parser_source
*pin
= impl_from_IQualityControl(iface
);
2360 TRACE("(%p)->(%p)\n", pin
, pin
);
2365 static const IQualityControlVtbl GSTOutPin_QualityControl_Vtbl
= {
2366 GST_QualityControl_QueryInterface
,
2367 GST_QualityControl_AddRef
,
2368 GST_QualityControl_Release
,
2369 GST_QualityControl_Notify
,
2370 GST_QualityControl_SetSink
2373 static inline struct parser_source
*impl_source_from_IPin(IPin
*iface
)
2375 return CONTAINING_RECORD(iface
, struct parser_source
, pin
.pin
.IPin_iface
);
2378 static HRESULT
source_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
2380 struct parser_source
*pin
= impl_source_from_IPin(&iface
->IPin_iface
);
2382 if (IsEqualGUID(iid
, &IID_IMediaSeeking
))
2383 *out
= &pin
->seek
.IMediaSeeking_iface
;
2384 else if (IsEqualGUID(iid
, &IID_IQualityControl
))
2385 *out
= &pin
->IQualityControl_iface
;
2387 return E_NOINTERFACE
;
2389 IUnknown_AddRef((IUnknown
*)*out
);
2393 static HRESULT
source_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
2395 struct parser_source
*pin
= impl_source_from_IPin(&iface
->IPin_iface
);
2396 struct parser
*filter
= impl_from_strmbase_filter(iface
->filter
);
2397 return filter
->source_query_accept(pin
, mt
);
2400 static HRESULT
source_get_media_type(struct strmbase_pin
*iface
, unsigned int index
, 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_get_media_type(pin
, index
, mt
);
2407 static HRESULT WINAPI
GSTOutPin_DecideBufferSize(struct strmbase_source
*iface
,
2408 IMemAllocator
*allocator
, ALLOCATOR_PROPERTIES
*props
)
2410 struct parser_source
*pin
= impl_source_from_IPin(&iface
->pin
.IPin_iface
);
2411 struct wg_parser_stream
*stream
= pin
->wg_stream
;
2412 unsigned int buffer_size
= 16384;
2413 ALLOCATOR_PROPERTIES ret_props
;
2415 if (IsEqualGUID(&pin
->pin
.pin
.mt
.formattype
, &FORMAT_VideoInfo
))
2417 VIDEOINFOHEADER
*format
= (VIDEOINFOHEADER
*)pin
->pin
.pin
.mt
.pbFormat
;
2418 buffer_size
= format
->bmiHeader
.biSizeImage
;
2420 gst_util_set_object_arg(G_OBJECT(stream
->flip
), "method",
2421 (format
->bmiHeader
.biCompression
== BI_RGB
2422 || format
->bmiHeader
.biCompression
== BI_BITFIELDS
) ? "vertical-flip" : "none");
2424 else if (IsEqualGUID(&pin
->pin
.pin
.mt
.formattype
, &FORMAT_WaveFormatEx
)
2425 && (IsEqualGUID(&pin
->pin
.pin
.mt
.subtype
, &MEDIASUBTYPE_PCM
)
2426 || IsEqualGUID(&pin
->pin
.pin
.mt
.subtype
, &MEDIASUBTYPE_IEEE_FLOAT
)))
2428 WAVEFORMATEX
*format
= (WAVEFORMATEX
*)pin
->pin
.pin
.mt
.pbFormat
;
2429 buffer_size
= format
->nAvgBytesPerSec
;
2432 gst_pad_push_event(stream
->my_sink
, gst_event_new_reconfigure());
2433 /* We do need to drop any buffers that might have been sent with the old
2434 * caps, but this will be handled in parser_init_stream(). */
2436 props
->cBuffers
= max(props
->cBuffers
, 1);
2437 props
->cbBuffer
= max(props
->cbBuffer
, buffer_size
);
2438 props
->cbAlign
= max(props
->cbAlign
, 1);
2439 return IMemAllocator_SetProperties(allocator
, props
, &ret_props
);
2442 static void free_source_pin(struct parser_source
*pin
)
2444 struct wg_parser_stream
*stream
= pin
->wg_stream
;
2446 if (pin
->pin
.pin
.peer
)
2448 if (SUCCEEDED(IMemAllocator_Decommit(pin
->pin
.pAllocator
)))
2449 IPin_Disconnect(pin
->pin
.pin
.peer
);
2450 IPin_Disconnect(&pin
->pin
.pin
.IPin_iface
);
2453 if (stream
->their_src
)
2455 if (stream
->post_sink
)
2457 gst_pad_unlink(stream
->their_src
, stream
->post_sink
);
2458 gst_pad_unlink(stream
->post_src
, stream
->my_sink
);
2459 gst_object_unref(stream
->post_src
);
2460 gst_object_unref(stream
->post_sink
);
2461 stream
->post_src
= stream
->post_sink
= NULL
;
2464 gst_pad_unlink(stream
->their_src
, stream
->my_sink
);
2465 gst_object_unref(stream
->their_src
);
2467 gst_object_unref(stream
->my_sink
);
2468 gst_segment_free(stream
->segment
);
2470 pthread_cond_destroy(&pin
->event_cond
);
2471 pthread_cond_destroy(&pin
->event_empty_cond
);
2475 pin
->flushing_cs
.DebugInfo
->Spare
[0] = 0;
2476 DeleteCriticalSection(&pin
->flushing_cs
);
2478 strmbase_seeking_cleanup(&pin
->seek
);
2479 strmbase_source_cleanup(&pin
->pin
);
2483 static const struct strmbase_source_ops source_ops
=
2485 .base
.pin_query_interface
= source_query_interface
,
2486 .base
.pin_query_accept
= source_query_accept
,
2487 .base
.pin_get_media_type
= source_get_media_type
,
2488 .pfnAttemptConnection
= BaseOutputPinImpl_AttemptConnection
,
2489 .pfnDecideAllocator
= BaseOutputPinImpl_DecideAllocator
,
2490 .pfnDecideBufferSize
= GSTOutPin_DecideBufferSize
,
2493 static struct parser_source
*create_pin(struct parser
*filter
, const WCHAR
*name
)
2495 struct parser_source
*pin
, **new_array
;
2496 struct wg_parser_stream
*stream
;
2499 if (!(new_array
= heap_realloc(filter
->sources
, (filter
->source_count
+ 1) * sizeof(*new_array
))))
2501 filter
->sources
= new_array
;
2503 if (!(pin
= heap_alloc_zero(sizeof(*pin
))))
2506 if (!(stream
= calloc(1, sizeof(*stream
))))
2511 pin
->wg_stream
= stream
;
2513 strmbase_source_init(&pin
->pin
, &filter
->filter
, name
, &source_ops
);
2514 stream
->segment
= gst_segment_new();
2515 gst_segment_init(stream
->segment
, GST_FORMAT_TIME
);
2516 pin
->IQualityControl_iface
.lpVtbl
= &GSTOutPin_QualityControl_Vtbl
;
2517 strmbase_seeking_init(&pin
->seek
, &GST_Seeking_Vtbl
, GST_ChangeStop
,
2518 GST_ChangeCurrent
, GST_ChangeRate
);
2519 pthread_cond_init(&pin
->event_cond
, NULL
);
2520 pthread_cond_init(&pin
->event_empty_cond
, NULL
);
2521 BaseFilterImpl_IncrementPinVersion(&filter
->filter
);
2523 InitializeCriticalSection(&pin
->flushing_cs
);
2524 pin
->flushing_cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": pin.flushing_cs");
2526 sprintf(pad_name
, "qz_sink_%u", filter
->source_count
);
2527 stream
->my_sink
= gst_pad_new(pad_name
, GST_PAD_SINK
);
2528 gst_pad_set_element_private(stream
->my_sink
, pin
);
2529 gst_pad_set_chain_function(stream
->my_sink
, got_data_sink
);
2530 gst_pad_set_event_function(stream
->my_sink
, event_sink
);
2531 gst_pad_set_query_function(stream
->my_sink
, query_sink_wrapper
);
2533 filter
->sources
[filter
->source_count
++] = pin
;
2537 static HRESULT
GST_RemoveOutputPins(struct parser
*This
)
2539 struct wg_parser
*parser
= This
->wg_parser
;
2542 TRACE("(%p)\n", This
);
2545 if (!parser
->container
)
2548 /* Unblock all of our streams. */
2549 pthread_mutex_lock(&parser
->mutex
);
2550 for (i
= 0; i
< This
->source_count
; ++i
)
2552 This
->sources
[i
]->flushing
= true;
2553 pthread_cond_signal(&This
->sources
[i
]->event_empty_cond
);
2555 pthread_mutex_unlock(&parser
->mutex
);
2557 gst_element_set_state(parser
->container
, GST_STATE_NULL
);
2558 gst_pad_unlink(parser
->my_src
, parser
->their_sink
);
2559 gst_object_unref(parser
->my_src
);
2560 gst_object_unref(parser
->their_sink
);
2561 parser
->my_src
= parser
->their_sink
= NULL
;
2563 /* read_thread() needs to stay alive to service any read requests GStreamer
2564 * sends, so we can only shut it down after GStreamer stops. */
2565 This
->sink_connected
= false;
2566 pthread_mutex_lock(&parser
->mutex
);
2567 parser
->sink_connected
= false;
2568 pthread_mutex_unlock(&parser
->mutex
);
2569 pthread_cond_signal(&parser
->read_cond
);
2570 WaitForSingleObject(This
->read_thread
, INFINITE
);
2571 CloseHandle(This
->read_thread
);
2573 for (i
= 0; i
< This
->source_count
; ++i
)
2574 free_source_pin(This
->sources
[i
]);
2576 This
->source_count
= 0;
2577 heap_free(This
->sources
);
2578 This
->sources
= NULL
;
2579 gst_element_set_bus(parser
->container
, NULL
);
2580 gst_object_unref(parser
->container
);
2581 parser
->container
= NULL
;
2582 BaseFilterImpl_IncrementPinVersion(&This
->filter
);
2586 void perform_cb_gstdemux(struct cb_data
*cbdata
)
2588 switch(cbdata
->type
)
2590 case EXISTING_NEW_PAD
:
2592 struct pad_added_data
*data
= &cbdata
->u
.pad_added_data
;
2593 existing_new_pad(data
->element
, data
->pad
, data
->user
);
2598 struct query_sink_data
*data
= &cbdata
->u
.query_sink_data
;
2599 cbdata
->u
.query_sink_data
.ret
= query_sink(data
->pad
, data
->parent
,
2610 static BOOL
compare_media_types(const AM_MEDIA_TYPE
*a
, const AM_MEDIA_TYPE
*b
)
2612 return IsEqualGUID(&a
->majortype
, &b
->majortype
)
2613 && IsEqualGUID(&a
->subtype
, &b
->subtype
)
2614 && IsEqualGUID(&a
->formattype
, &b
->formattype
)
2615 && a
->cbFormat
== b
->cbFormat
2616 && !memcmp(a
->pbFormat
, b
->pbFormat
, a
->cbFormat
);
2619 static HRESULT
wave_parser_sink_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
2621 if (!IsEqualGUID(&mt
->majortype
, &MEDIATYPE_Stream
))
2623 if (IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_WAVE
))
2625 if (IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_AU
) || IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_AIFF
))
2626 FIXME("AU and AIFF files are not yet supported.\n");
2630 static const struct strmbase_sink_ops wave_parser_sink_ops
=
2632 .base
.pin_query_accept
= wave_parser_sink_query_accept
,
2633 .sink_connect
= parser_sink_connect
,
2634 .sink_disconnect
= parser_sink_disconnect
,
2637 static BOOL
wave_parser_init_gst(struct parser
*filter
)
2639 static const WCHAR source_name
[] = {'o','u','t','p','u','t',0};
2640 struct wg_parser
*parser
= filter
->wg_parser
;
2641 struct wg_parser_stream
*stream
;
2642 struct parser_source
*pin
;
2643 GstElement
*element
;
2646 if (!(element
= gst_element_factory_make("wavparse", NULL
)))
2648 ERR("Failed to create wavparse; are %u-bit GStreamer \"good\" plugins installed?\n",
2649 8 * (int)sizeof(void*));
2653 gst_bin_add(GST_BIN(parser
->container
), element
);
2655 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
2656 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
2658 ERR("Failed to link sink pads, error %d.\n", ret
);
2662 if (!(pin
= create_pin(filter
, source_name
)))
2664 stream
= pin
->wg_stream
;
2665 stream
->their_src
= gst_element_get_static_pad(element
, "src");
2666 gst_object_ref(stream
->their_src
);
2667 if ((ret
= gst_pad_link(stream
->their_src
, stream
->my_sink
)) < 0)
2669 ERR("Failed to link source pads, error %d.\n", ret
);
2673 gst_pad_set_active(stream
->my_sink
, 1);
2674 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
2675 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
2676 if (ret
== GST_STATE_CHANGE_FAILURE
)
2678 ERR("Failed to play stream.\n");
2685 static HRESULT
wave_parser_source_query_accept(struct parser_source
*pin
, const AM_MEDIA_TYPE
*mt
)
2687 AM_MEDIA_TYPE pad_mt
;
2690 if (!amt_from_gst_caps(pin
->caps
, &pad_mt
))
2691 return E_OUTOFMEMORY
;
2692 hr
= compare_media_types(mt
, &pad_mt
) ? S_OK
: S_FALSE
;
2693 FreeMediaType(&pad_mt
);
2697 static HRESULT
wave_parser_source_get_media_type(struct parser_source
*pin
,
2698 unsigned int index
, AM_MEDIA_TYPE
*mt
)
2701 return VFW_S_NO_MORE_ITEMS
;
2702 if (!amt_from_gst_caps(pin
->caps
, mt
))
2703 return E_OUTOFMEMORY
;
2707 HRESULT
wave_parser_create(IUnknown
*outer
, IUnknown
**out
)
2709 static const WCHAR sink_name
[] = {'i','n','p','u','t',' ','p','i','n',0};
2710 struct parser
*object
;
2712 if (!parser_init_gstreamer())
2717 if (!(object
= heap_alloc_zero(sizeof(*object
))))
2718 return E_OUTOFMEMORY
;
2720 if (!(object
->wg_parser
= wg_parser_create()))
2723 return E_OUTOFMEMORY
;
2726 strmbase_filter_init(&object
->filter
, outer
, &CLSID_WAVEParser
, &filter_ops
);
2727 strmbase_sink_init(&object
->sink
, &object
->filter
, sink_name
, &wave_parser_sink_ops
, NULL
);
2728 object
->init_gst
= wave_parser_init_gst
;
2729 object
->source_query_accept
= wave_parser_source_query_accept
;
2730 object
->source_get_media_type
= wave_parser_source_get_media_type
;
2732 TRACE("Created WAVE parser %p.\n", object
);
2733 *out
= &object
->filter
.IUnknown_inner
;
2737 static HRESULT
avi_splitter_sink_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
2739 if (IsEqualGUID(&mt
->majortype
, &MEDIATYPE_Stream
)
2740 && IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_Avi
))
2745 static const struct strmbase_sink_ops avi_splitter_sink_ops
=
2747 .base
.pin_query_accept
= avi_splitter_sink_query_accept
,
2748 .sink_connect
= parser_sink_connect
,
2749 .sink_disconnect
= parser_sink_disconnect
,
2752 static BOOL
avi_splitter_init_gst(struct parser
*filter
)
2754 GstElement
*element
= gst_element_factory_make("avidemux", NULL
);
2755 struct wg_parser
*parser
= filter
->wg_parser
;
2760 ERR("Failed to create avidemux; are %u-bit GStreamer \"good\" plugins installed?\n",
2761 8 * (int)sizeof(void*));
2765 gst_bin_add(GST_BIN(parser
->container
), element
);
2767 g_signal_connect(element
, "pad-added", G_CALLBACK(existing_new_pad_wrapper
), filter
);
2768 g_signal_connect(element
, "pad-removed", G_CALLBACK(removed_decoded_pad
), filter
);
2769 g_signal_connect(element
, "no-more-pads", G_CALLBACK(no_more_pads
), filter
);
2771 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
2773 pthread_mutex_lock(&parser
->mutex
);
2774 parser
->no_more_pads
= parser
->error
= false;
2775 pthread_mutex_unlock(&parser
->mutex
);
2777 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
2779 ERR("Failed to link pads, error %d.\n", ret
);
2783 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
2784 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
2785 if (ret
== GST_STATE_CHANGE_FAILURE
)
2787 ERR("Failed to play stream.\n");
2791 pthread_mutex_lock(&parser
->mutex
);
2792 while (!parser
->no_more_pads
&& !parser
->error
)
2793 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
2796 pthread_mutex_unlock(&parser
->mutex
);
2799 pthread_mutex_unlock(&parser
->mutex
);
2803 static HRESULT
avi_splitter_source_query_accept(struct parser_source
*pin
, const AM_MEDIA_TYPE
*mt
)
2805 AM_MEDIA_TYPE pad_mt
;
2808 if (!amt_from_gst_caps(pin
->caps
, &pad_mt
))
2809 return E_OUTOFMEMORY
;
2810 hr
= compare_media_types(mt
, &pad_mt
) ? S_OK
: S_FALSE
;
2811 FreeMediaType(&pad_mt
);
2815 static HRESULT
avi_splitter_source_get_media_type(struct parser_source
*pin
,
2816 unsigned int index
, AM_MEDIA_TYPE
*mt
)
2819 return VFW_S_NO_MORE_ITEMS
;
2820 if (!amt_from_gst_caps(pin
->caps
, mt
))
2821 return E_OUTOFMEMORY
;
2825 HRESULT
avi_splitter_create(IUnknown
*outer
, IUnknown
**out
)
2827 static const WCHAR sink_name
[] = {'i','n','p','u','t',' ','p','i','n',0};
2828 struct parser
*object
;
2830 if (!parser_init_gstreamer())
2835 if (!(object
= heap_alloc_zero(sizeof(*object
))))
2836 return E_OUTOFMEMORY
;
2838 if (!(object
->wg_parser
= wg_parser_create()))
2841 return E_OUTOFMEMORY
;
2844 strmbase_filter_init(&object
->filter
, outer
, &CLSID_AviSplitter
, &filter_ops
);
2845 strmbase_sink_init(&object
->sink
, &object
->filter
, sink_name
, &avi_splitter_sink_ops
, NULL
);
2846 object
->init_gst
= avi_splitter_init_gst
;
2847 object
->source_query_accept
= avi_splitter_source_query_accept
;
2848 object
->source_get_media_type
= avi_splitter_source_get_media_type
;
2850 TRACE("Created AVI splitter %p.\n", object
);
2851 *out
= &object
->filter
.IUnknown_inner
;
2855 static HRESULT
mpeg_splitter_sink_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*mt
)
2857 if (!IsEqualGUID(&mt
->majortype
, &MEDIATYPE_Stream
))
2859 if (IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_MPEG1Audio
))
2861 if (IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_MPEG1Video
)
2862 || IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_MPEG1System
)
2863 || IsEqualGUID(&mt
->subtype
, &MEDIASUBTYPE_MPEG1VideoCD
))
2864 FIXME("Unsupported subtype %s.\n", wine_dbgstr_guid(&mt
->subtype
));
2868 static const struct strmbase_sink_ops mpeg_splitter_sink_ops
=
2870 .base
.pin_query_accept
= mpeg_splitter_sink_query_accept
,
2871 .sink_connect
= parser_sink_connect
,
2872 .sink_disconnect
= parser_sink_disconnect
,
2875 static BOOL
mpeg_splitter_init_gst(struct parser
*filter
)
2877 static const WCHAR source_name
[] = {'A','u','d','i','o',0};
2878 struct wg_parser
*parser
= filter
->wg_parser
;
2879 struct wg_parser_stream
*stream
;
2880 struct parser_source
*pin
;
2881 GstElement
*element
;
2884 if (!(element
= gst_element_factory_make("mpegaudioparse", NULL
)))
2886 ERR("Failed to create mpegaudioparse; are %u-bit GStreamer \"good\" plugins installed?\n",
2887 8 * (int)sizeof(void*));
2891 gst_bin_add(GST_BIN(parser
->container
), element
);
2893 parser
->their_sink
= gst_element_get_static_pad(element
, "sink");
2894 if ((ret
= gst_pad_link(parser
->my_src
, parser
->their_sink
)) < 0)
2896 ERR("Failed to link sink pads, error %d.\n", ret
);
2900 if (!(pin
= create_pin(filter
, source_name
)))
2902 stream
= pin
->wg_stream
;
2903 gst_object_ref(stream
->their_src
= gst_element_get_static_pad(element
, "src"));
2904 if ((ret
= gst_pad_link(stream
->their_src
, stream
->my_sink
)) < 0)
2906 ERR("Failed to link source pads, error %d.\n", ret
);
2910 gst_pad_set_active(stream
->my_sink
, 1);
2911 gst_element_set_state(parser
->container
, GST_STATE_PAUSED
);
2912 ret
= gst_element_get_state(parser
->container
, NULL
, NULL
, -1);
2913 if (ret
== GST_STATE_CHANGE_FAILURE
)
2915 ERR("Failed to play stream.\n");
2919 pthread_mutex_lock(&parser
->mutex
);
2920 while (!parser
->has_duration
&& !parser
->error
&& !pin
->eos
)
2921 pthread_cond_wait(&parser
->init_cond
, &parser
->mutex
);
2924 pthread_mutex_unlock(&parser
->mutex
);
2927 pthread_mutex_unlock(&parser
->mutex
);
2931 static HRESULT
mpeg_splitter_source_query_accept(struct parser_source
*pin
, const AM_MEDIA_TYPE
*mt
)
2933 AM_MEDIA_TYPE pad_mt
;
2936 if (!amt_from_gst_caps(pin
->caps
, &pad_mt
))
2937 return E_OUTOFMEMORY
;
2938 hr
= compare_media_types(mt
, &pad_mt
) ? S_OK
: S_FALSE
;
2939 FreeMediaType(&pad_mt
);
2943 static HRESULT
mpeg_splitter_source_get_media_type(struct parser_source
*pin
,
2944 unsigned int index
, AM_MEDIA_TYPE
*mt
)
2947 return VFW_S_NO_MORE_ITEMS
;
2948 if (!amt_from_gst_caps(pin
->caps
, mt
))
2949 return E_OUTOFMEMORY
;
2953 static HRESULT
mpeg_splitter_query_interface(struct strmbase_filter
*iface
, REFIID iid
, void **out
)
2955 struct parser
*filter
= impl_from_strmbase_filter(iface
);
2957 if (IsEqualGUID(iid
, &IID_IAMStreamSelect
))
2959 *out
= &filter
->IAMStreamSelect_iface
;
2960 IUnknown_AddRef((IUnknown
*)*out
);
2964 return E_NOINTERFACE
;
2967 static const struct strmbase_filter_ops mpeg_splitter_ops
=
2969 .filter_query_interface
= mpeg_splitter_query_interface
,
2970 .filter_get_pin
= parser_get_pin
,
2971 .filter_destroy
= parser_destroy
,
2972 .filter_init_stream
= parser_init_stream
,
2973 .filter_cleanup_stream
= parser_cleanup_stream
,
2976 HRESULT
mpeg_splitter_create(IUnknown
*outer
, IUnknown
**out
)
2978 static const WCHAR sink_name
[] = {'I','n','p','u','t',0};
2979 struct parser
*object
;
2981 if (!parser_init_gstreamer())
2986 if (!(object
= heap_alloc_zero(sizeof(*object
))))
2987 return E_OUTOFMEMORY
;
2989 if (!(object
->wg_parser
= wg_parser_create()))
2992 return E_OUTOFMEMORY
;
2995 strmbase_filter_init(&object
->filter
, outer
, &CLSID_MPEG1Splitter
, &mpeg_splitter_ops
);
2996 strmbase_sink_init(&object
->sink
, &object
->filter
, sink_name
, &mpeg_splitter_sink_ops
, NULL
);
2997 object
->IAMStreamSelect_iface
.lpVtbl
= &stream_select_vtbl
;
2999 object
->init_gst
= mpeg_splitter_init_gst
;
3000 object
->source_query_accept
= mpeg_splitter_source_query_accept
;
3001 object
->source_get_media_type
= mpeg_splitter_source_get_media_type
;
3002 object
->enum_sink_first
= TRUE
;
3004 TRACE("Created MPEG-1 splitter %p.\n", object
);
3005 *out
= &object
->filter
.IUnknown_inner
;