ddraw: Don't interpret end padding as dwCaps2 for x64.
[wine] / dlls / winegstreamer / gstdemux.c
1 /*
2  * GStreamer splitter + decoder, adapted from parser.c
3  *
4  * Copyright 2010 Maarten Lankhorst for CodeWeavers
5  * Copyright 2010 Aric Stewart for CodeWeavers
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include "config.h"
23 #include <gst/app/gstappsink.h>
24 #include <gst/app/gstappsrc.h>
25 #include <gst/app/gstappbuffer.h>
26 #include <gst/gstutils.h>
27
28 #include "gst_private.h"
29 #include "gst_guids.h"
30
31 #include "vfwmsgs.h"
32 #include "amvideo.h"
33
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
36
37 #include <assert.h>
38
39 #include "dvdmedia.h"
40 #include "mmreg.h"
41 #include "ks.h"
42 #include "initguid.h"
43 #include "ksmedia.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(gstreamer);
46
47 typedef struct GSTOutPin GSTOutPin;
48 typedef struct GSTInPin {
49     BasePin pin;
50     IAsyncReader *pReader;
51     IMemAllocator *pAlloc;
52 } GSTInPin;
53
54 typedef struct GSTImpl {
55     BaseFilter filter;
56
57     GSTInPin pInputPin;
58     GSTOutPin **ppPins;
59     LONG cStreams;
60
61     LONGLONG filesize;
62
63     BOOL discont, initial;
64     GstElement *gstfilter;
65     GstPad *my_src, *their_sink;
66     GstBus *bus;
67     guint64 start, nextofs, nextpullofs, stop;
68     ALLOCATOR_PROPERTIES props;
69     HANDLE event, changed_ofs;
70
71     HANDLE push_thread;
72 } GSTImpl;
73
74 struct GSTOutPin {
75     BaseOutputPin pin;
76
77     GstPad *their_src;
78     GstPad *my_sink;
79     int isaud, isvid;
80     AM_MEDIA_TYPE * pmt;
81     HANDLE caps_event;
82     GstSegment *segment;
83     QualityControlImpl qcimpl;
84     SourceSeeking seek;
85 };
86
87 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
88 static const IMediaSeekingVtbl GST_Seeking_Vtbl;
89 static const IPinVtbl GST_OutputPin_Vtbl;
90 static const IPinVtbl GST_InputPin_Vtbl;
91 static const IBaseFilterVtbl GST_Vtbl;
92 static const IQualityControlVtbl GSTOutPin_QualityControl_Vtbl;
93
94 static HRESULT GST_AddPin(GSTImpl *This, const PIN_INFO *piOutput, const AM_MEDIA_TYPE *amt);
95 static HRESULT GST_RemoveOutputPins(GSTImpl *This);
96 static HRESULT WINAPI GST_ChangeCurrent(IMediaSeeking *iface);
97 static HRESULT WINAPI GST_ChangeStop(IMediaSeeking *iface);
98 static HRESULT WINAPI GST_ChangeRate(IMediaSeeking *iface);
99
100 static int amt_from_gst_caps_audio(GstCaps *caps, AM_MEDIA_TYPE *amt) {
101     WAVEFORMATEXTENSIBLE *wfe;
102     WAVEFORMATEX *wfx;
103     GstStructure *arg;
104     gint32 depth = 0, bpp = 0;
105     const char *typename;
106     arg = gst_caps_get_structure(caps, 0);
107     typename = gst_structure_get_name(arg);
108     if (!typename)
109         return 0;
110
111     wfe = CoTaskMemAlloc(sizeof(*wfe));
112     wfx = (WAVEFORMATEX*)wfe;
113     amt->majortype = MEDIATYPE_Audio;
114     amt->subtype = MEDIASUBTYPE_PCM;
115     amt->formattype = FORMAT_WaveFormatEx;
116     amt->pbFormat = (BYTE*)wfe;
117     amt->cbFormat = sizeof(*wfe);
118     amt->bFixedSizeSamples = 0;
119     amt->bTemporalCompression = 1;
120     amt->lSampleSize = 0;
121     amt->pUnk = NULL;
122
123     wfx->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
124     if (!gst_structure_get_int(arg, "channels", (INT*)&wfx->nChannels))
125         return 0;
126     if (!gst_structure_get_int(arg, "rate", (INT*)&wfx->nSamplesPerSec))
127         return 0;
128     gst_structure_get_int(arg, "width", &depth);
129     gst_structure_get_int(arg, "depth", &bpp);
130     if (!depth || depth > 32 || depth % 8)
131         depth = bpp;
132     else if (!bpp)
133         bpp = depth;
134     wfe->Samples.wValidBitsPerSample = depth;
135     wfx->wBitsPerSample = bpp;
136     wfx->cbSize = sizeof(*wfe)-sizeof(*wfx);
137     switch (wfx->nChannels) {
138         case 1: wfe->dwChannelMask = KSAUDIO_SPEAKER_MONO; break;
139         case 2: wfe->dwChannelMask = KSAUDIO_SPEAKER_STEREO; break;
140         case 4: wfe->dwChannelMask = KSAUDIO_SPEAKER_SURROUND; break;
141         case 5: wfe->dwChannelMask = (KSAUDIO_SPEAKER_5POINT1 & ~SPEAKER_LOW_FREQUENCY); break;
142         case 6: wfe->dwChannelMask = KSAUDIO_SPEAKER_5POINT1; break;
143         case 8: wfe->dwChannelMask = KSAUDIO_SPEAKER_7POINT1; break;
144         default:
145         wfe->dwChannelMask = 0;
146     }
147     if (!strcmp(typename, "audio/x-raw-float")) {
148         wfe->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
149         wfx->wBitsPerSample = wfe->Samples.wValidBitsPerSample = 32;
150     } else
151         wfe->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
152     wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample/8;
153     wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
154     return 1;
155 }
156
157 static int amt_from_gst_caps_video(GstCaps *caps, AM_MEDIA_TYPE *amt) {
158     VIDEOINFOHEADER *vih = CoTaskMemAlloc(sizeof(*vih));
159     BITMAPINFOHEADER *bih = &vih->bmiHeader;
160     GstStructure *arg;
161     gint32 width = 0, height = 0, nom = 0, denom = 0;
162     const char *typename;
163     arg = gst_caps_get_structure(caps, 0);
164     typename = gst_structure_get_name(arg);
165     if (!typename)
166         return 0;
167     if (!gst_structure_get_int(arg, "width", &width) ||
168         !gst_structure_get_int(arg, "height", &height) ||
169         !gst_structure_get_fraction(arg, "framerate", &nom, &denom))
170         return 0;
171     amt->formattype = FORMAT_VideoInfo;
172     amt->pbFormat = (BYTE*)vih;
173     amt->cbFormat = sizeof(*vih);
174     amt->bFixedSizeSamples = amt->bTemporalCompression = 1;
175     amt->lSampleSize = 0;
176     amt->pUnk = NULL;
177     ZeroMemory(vih, sizeof(*vih));
178     amt->majortype = MEDIATYPE_Video;
179     if (!strcmp(typename, "video/x-raw-rgb")) {
180         if (!gst_structure_get_int(arg, "bpp", (INT*)&bih->biBitCount))
181             return 0;
182         switch (bih->biBitCount) {
183             case 16: amt->subtype = MEDIASUBTYPE_RGB555; break;
184             case 24: amt->subtype = MEDIASUBTYPE_RGB24; break;
185             case 32: amt->subtype = MEDIASUBTYPE_RGB32; break;
186             default:
187                 FIXME("Unknown bpp %u\n", bih->biBitCount);
188                 return 0;
189         }
190         bih->biCompression = BI_RGB;
191     } else {
192         amt->subtype = MEDIATYPE_Video;
193         if (!gst_structure_get_fourcc(arg, "format", &amt->subtype.Data1))
194             return 0;
195         switch (amt->subtype.Data1) {
196             case mmioFOURCC('I','4','2','0'):
197             case mmioFOURCC('Y','V','1','2'):
198             case mmioFOURCC('N','V','1','2'):
199             case mmioFOURCC('N','V','2','1'):
200                 bih->biBitCount = 12; break;
201             case mmioFOURCC('Y','U','Y','2'):
202             case mmioFOURCC('Y','V','Y','U'):
203                 bih->biBitCount = 16; break;
204         }
205         bih->biCompression = amt->subtype.Data1;
206     }
207     bih->biSizeImage = width * height * bih->biBitCount / 8;
208     vih->AvgTimePerFrame = 10000000;
209     vih->AvgTimePerFrame *= denom;
210     vih->AvgTimePerFrame /= nom;
211     vih->rcSource.left = 0;
212     vih->rcSource.right = width;
213     vih->rcSource.top = height;
214     vih->rcSource.bottom = 0;
215     vih->rcTarget = vih->rcSource;
216     bih->biSize = sizeof(*bih);
217     bih->biWidth = width;
218     bih->biHeight = height;
219     bih->biPlanes = 1;
220     return 1;
221 }
222
223 static gboolean accept_caps_sink(GstPad *pad, GstCaps *caps) {
224     GSTOutPin *pin = gst_pad_get_element_private(pad);
225     AM_MEDIA_TYPE amt;
226     GstStructure *arg;
227     const char *typename;
228     int ret;
229     arg = gst_caps_get_structure(caps, 0);
230     typename = gst_structure_get_name(arg);
231     if (!strcmp(typename, "audio/x-raw-int") ||
232         !strcmp(typename, "audio/x-raw-float")) {
233         if (!pin->isaud) {
234             ERR("Setting audio caps on non-audio pad?\n");
235             return 0;
236         }
237         ret = amt_from_gst_caps_audio(caps, &amt);
238         FreeMediaType(&amt);
239         TRACE("+%i\n", ret);
240         return ret;
241     } else if (!strcmp(typename, "video/x-raw-rgb")
242                || !strcmp(typename, "video/x-raw-yuv")) {
243         if (!pin->isvid) {
244             ERR("Setting video caps on non-video pad?\n");
245             return 0;
246         }
247         ret = amt_from_gst_caps_video(caps, &amt);
248         FreeMediaType(&amt);
249         TRACE("-%i\n", ret);
250         return ret;
251     } else {
252         FIXME("Unhandled type \"%s\"\n", typename);
253         return 0;
254     }
255 }
256
257 static gboolean setcaps_sink(GstPad *pad, GstCaps *caps) {
258     GSTOutPin *pin = gst_pad_get_element_private(pad);
259     GSTImpl *This = (GSTImpl *)pin->pin.pin.pinInfo.pFilter;
260     AM_MEDIA_TYPE amt;
261     GstStructure *arg;
262     const char *typename;
263     int ret;
264     arg = gst_caps_get_structure(caps, 0);
265     typename = gst_structure_get_name(arg);
266     if (!strcmp(typename, "audio/x-raw-int") ||
267         !strcmp(typename, "audio/x-raw-float")) {
268         if (!pin->isaud) {
269             ERR("Setting audio caps on non-audio pad?\n");
270             return 0;
271         }
272         ret = amt_from_gst_caps_audio(caps, &amt);
273     } else if (!strcmp(typename, "video/x-raw-rgb")
274                || !strcmp(typename, "video/x-raw-yuv")) {
275         if (!pin->isvid) {
276             ERR("Setting video caps on non-video pad?\n");
277             return 0;
278         }
279         ret = amt_from_gst_caps_video(caps, &amt);
280         if (ret)
281             This->props.cbBuffer = max(This->props.cbBuffer, ((VIDEOINFOHEADER*)amt.pbFormat)->bmiHeader.biSizeImage);
282     } else {
283         FIXME("Unhandled type \"%s\"\n", typename);
284         return 0;
285     }
286     TRACE("Linking returned %i for %s\n", ret, typename);
287     if (!ret)
288         return 0;
289     FreeMediaType(pin->pmt);
290     *pin->pmt = amt;
291     return 1;
292 }
293
294 static gboolean gst_base_src_perform_seek(GSTImpl *This, GstEvent *event)
295 {
296     gboolean res = TRUE;
297     gdouble rate;
298     GstFormat seek_format;
299     GstSeekFlags flags;
300     GstSeekType cur_type, stop_type;
301     gint64 cur, stop;
302     gboolean flush;
303     guint32 seqnum;
304     GstEvent *tevent;
305     BOOL thread = !!This->push_thread;
306
307     gst_event_parse_seek(event, &rate, &seek_format, &flags,
308                          &cur_type, &cur, &stop_type, &stop);
309
310     if (seek_format != GST_FORMAT_BYTES) {
311         FIXME("Not handling other format %i\n", seek_format);
312         return 0;
313     }
314
315     flush = flags & GST_SEEK_FLAG_FLUSH;
316     seqnum = gst_event_get_seqnum(event);
317
318     /* send flush start */
319     if (flush) {
320         tevent = gst_event_new_flush_start();
321         gst_event_set_seqnum(tevent, seqnum);
322         gst_pad_push_event(This->my_src, tevent);
323         if (This->pInputPin.pReader)
324             IAsyncReader_BeginFlush(This->pInputPin.pReader);
325         if (thread)
326             gst_pad_activate_push(This->my_src, 0);
327     }
328
329     This->nextofs = This->start = cur;
330
331     /* and prepare to continue streaming */
332     if (flush) {
333         tevent = gst_event_new_flush_stop();
334         gst_event_set_seqnum(tevent, seqnum);
335         gst_pad_push_event(This->my_src, tevent);
336         if (This->pInputPin.pReader)
337             IAsyncReader_EndFlush(This->pInputPin.pReader);
338         if (thread)
339             gst_pad_activate_push(This->my_src, 1);
340     }
341
342     return res;
343 }
344
345 static gboolean event_src(GstPad *pad, GstEvent *event) {
346     GSTImpl *This = gst_pad_get_element_private(pad);
347     switch (event->type) {
348         case GST_EVENT_SEEK:
349             return gst_base_src_perform_seek(This, event);
350         case GST_EVENT_FLUSH_START:
351             EnterCriticalSection(&This->filter.csFilter);
352             if (This->pInputPin.pReader)
353                 IAsyncReader_BeginFlush(This->pInputPin.pReader);
354             LeaveCriticalSection(&This->filter.csFilter);
355             break;
356         case GST_EVENT_FLUSH_STOP:
357             EnterCriticalSection(&This->filter.csFilter);
358             if (This->pInputPin.pReader)
359                 IAsyncReader_EndFlush(This->pInputPin.pReader);
360             LeaveCriticalSection(&This->filter.csFilter);
361             break;
362         default:
363             FIXME("%p (%u) stub\n", event, event->type);
364         case GST_EVENT_TAG:
365         case GST_EVENT_QOS:
366             return gst_pad_event_default(pad, event);
367     }
368     return 1;
369 }
370
371 static gboolean event_sink(GstPad *pad, GstEvent *event) {
372     GSTOutPin *pin = gst_pad_get_element_private(pad);
373     switch (event->type) {
374         case GST_EVENT_NEWSEGMENT: {
375             gboolean update;
376             gdouble rate, applied_rate;
377             GstFormat format;
378             gint64 start, stop, pos;
379             gst_event_parse_new_segment_full(event, &update, &rate, &applied_rate, &format, &start, &stop, &pos);
380             if (format != GST_FORMAT_TIME) {
381                 FIXME("Ignoring new segment because of format %i\n", format);
382                 return 1;
383             }
384             gst_segment_set_newsegment_full(pin->segment, update, rate, applied_rate, format, start, stop, pos);
385             pos /= 100;
386             if (stop > 0)
387                 stop /= 100;
388             if (pin->pin.pin.pConnectedTo)
389                 IPin_NewSegment(pin->pin.pin.pConnectedTo, pos, stop, rate*applied_rate);
390             return 1;
391         }
392         case GST_EVENT_EOS:
393             if (pin->pin.pin.pConnectedTo)
394                 IPin_EndOfStream(pin->pin.pin.pConnectedTo);
395             return 1;
396         case GST_EVENT_FLUSH_START:
397             if (pin->pin.pin.pConnectedTo)
398                 IPin_BeginFlush(pin->pin.pin.pConnectedTo);
399             return 1;
400         case GST_EVENT_FLUSH_STOP:
401             gst_segment_init(pin->segment, GST_FORMAT_TIME);
402             if (pin->pin.pin.pConnectedTo)
403                 IPin_EndFlush(pin->pin.pin.pConnectedTo);
404             return 1;
405         default:
406             FIXME("%p stub %s\n", event, gst_event_type_get_name(event->type));
407             return gst_pad_event_default(pad, event);
408     }
409 }
410
411 static void release_sample(void *data) {
412     ULONG ret;
413     ret = IMediaSample_Release((IMediaSample *)data);
414     TRACE("Releasing %p returns %u\n", data, ret);
415 }
416
417 static DWORD CALLBACK push_data(LPVOID iface) {
418     LONGLONG maxlen, curlen;
419     GSTImpl *This = iface;
420     IMediaSample *buf;
421     DWORD_PTR user;
422     HRESULT hr;
423
424     if (!This->stop)
425         IAsyncReader_Length(This->pInputPin.pReader, &maxlen, &curlen);
426     else
427         maxlen = This->stop;
428     TRACE("Starting..\n");
429     for (;;) {
430         REFERENCE_TIME tStart, tStop;
431         ULONG len;
432         GstBuffer *gstbuf;
433         BYTE *data;
434         int ret;
435
436         hr = IMemAllocator_GetBuffer(This->pInputPin.pAlloc, &buf, NULL, NULL, 0);
437         if (FAILED(hr))
438             break;
439
440         if (This->nextofs >= maxlen)
441             break;
442         len = IMediaSample_GetSize(buf);
443         if (This->nextofs + len > maxlen)
444             len = maxlen - This->nextofs;
445
446         tStart = MEDIATIME_FROM_BYTES(This->nextofs);
447         tStop = tStart + MEDIATIME_FROM_BYTES(len);
448         IMediaSample_SetTime(buf, &tStart, &tStop);
449
450         hr = IAsyncReader_Request(This->pInputPin.pReader, buf, 0);
451         if (FAILED(hr)) {
452             IMediaSample_Release(buf);
453             break;
454         }
455         This->nextofs += len;
456         hr = IAsyncReader_WaitForNext(This->pInputPin.pReader, -1, &buf, &user);
457         if (FAILED(hr) || !buf) {
458             if (buf)
459                 IMediaSample_Release(buf);
460             break;
461         }
462
463         IMediaSample_GetPointer(buf, &data);
464         gstbuf = gst_app_buffer_new(data, IMediaSample_GetActualDataLength(buf), release_sample, buf);
465         if (!gstbuf) {
466             IMediaSample_Release(buf);
467             break;
468         }
469         gstbuf->duration = gstbuf->timestamp = -1;
470         ret = gst_pad_push(This->my_src, gstbuf);
471         if (ret >= 0)
472             hr = S_OK;
473         else
474             ERR("Sending returned: %i\n", ret);
475         if (ret == GST_FLOW_ERROR)
476             hr = E_FAIL;
477         else if (ret == GST_FLOW_WRONG_STATE)
478             hr = VFW_E_WRONG_STATE;
479         else if (ret == GST_FLOW_RESEND)
480             hr = S_FALSE;
481         if (hr != S_OK)
482             break;
483     }
484
485     gst_pad_push_event(This->my_src, gst_event_new_eos());
486
487     TRACE("Almost stopping.. %08x\n", hr);
488     do {
489         IAsyncReader_WaitForNext(This->pInputPin.pReader, 0, &buf, &user);
490         if (buf)
491             IMediaSample_Release(buf);
492     } while (buf);
493
494     TRACE("Stopping.. %08x\n", hr);
495     return 0;
496 }
497
498 static HRESULT WINAPI GST_OutPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt) {
499     GSTOutPin *pin = (GSTOutPin*)iface;
500     FIXME("stub %p\n", pin);
501     return S_OK;
502 }
503
504 static GstFlowReturn got_data_sink(GstPad *pad, GstBuffer *buf) {
505     GSTOutPin *pin = gst_pad_get_element_private(pad);
506     GSTImpl *This = (GSTImpl *)pin->pin.pin.pinInfo.pFilter;
507     IMediaSample *sample;
508     HRESULT hr;
509     BOOL freeSamp = FALSE;
510
511     if (This->initial) {
512         gst_buffer_unref(buf);
513         FIXME("Triggering %p %p\n", pad, pin->caps_event);
514         SetEvent(pin->caps_event);
515         return GST_FLOW_NOT_LINKED;
516     }
517
518     if (GST_IS_APP_BUFFER(buf)) {
519         sample = GST_APP_BUFFER(buf)->priv;
520         TRACE("Pushing buffer\n");
521     } else if (buf->parent && GST_IS_APP_BUFFER(buf->parent)) {
522         sample = GST_APP_BUFFER(buf->parent)->priv;
523         TRACE("Pushing sub-buffer\n");
524     } else {
525         BYTE *ptr = NULL;
526         hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0);
527         freeSamp = TRUE;
528         if (hr == VFW_E_NOT_CONNECTED) {
529             gst_buffer_unref(buf);
530             return GST_FLOW_NOT_LINKED;
531         }
532         if (FAILED(hr)) {
533             gst_buffer_unref(buf);
534             ERR("Didn't get a GST_APP_BUFFER, and could not get a delivery buffer (%x), returning GST_FLOW_WRONG_STATE\n", hr);
535             return GST_FLOW_WRONG_STATE;
536         }
537         FIXME("Did not get a GST_APP_BUFFER, creating a sample\n");
538         IMediaSample_GetPointer(sample, &ptr);
539         memcpy(ptr, GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
540     }
541     IMediaSample_SetActualDataLength(sample, GST_BUFFER_SIZE(buf));
542
543     if (GST_BUFFER_TIMESTAMP_IS_VALID(buf)) {
544         REFERENCE_TIME rtStart = gst_segment_to_running_time(pin->segment, GST_FORMAT_TIME, buf->timestamp);
545         if (rtStart >= 0)
546             rtStart /= 100;
547
548         if (GST_BUFFER_DURATION_IS_VALID(buf)) {
549             REFERENCE_TIME tStart = buf->timestamp / 100;
550             REFERENCE_TIME tStop = (buf->timestamp + buf->duration) / 100;
551             REFERENCE_TIME rtStop;
552             rtStop = gst_segment_to_running_time(pin->segment, GST_FORMAT_TIME, buf->timestamp + buf->duration);
553             if (rtStop >= 0)
554                 rtStop /= 100;
555             TRACE("Current time on %p: %i to %i ms\n", pin, (int)(rtStart / 10000), (int)(rtStop / 10000));
556             IMediaSample_SetTime(sample, &rtStart, rtStop >= 0 ? &rtStop : NULL);
557             IMediaSample_SetMediaTime(sample, &tStart, &tStop);
558         } else {
559             IMediaSample_SetTime(sample, rtStart >= 0 ? &rtStart : NULL, NULL);
560             IMediaSample_SetMediaTime(sample, NULL, NULL);
561         }
562     } else {
563         IMediaSample_SetTime(sample, NULL, NULL);
564         IMediaSample_SetMediaTime(sample, NULL, NULL);
565     }
566
567     IMediaSample_SetDiscontinuity(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DISCONT));
568     IMediaSample_SetPreroll(sample, GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_PREROLL));
569     IMediaSample_SetSyncPoint(sample, !GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLAG_DELTA_UNIT));
570
571     if (!pin->pin.pin.pConnectedTo)
572         hr = VFW_E_NOT_CONNECTED;
573     else
574         hr = IMemInputPin_Receive(pin->pin.pMemInputPin, sample);
575     TRACE("sending sample: %08x\n", hr);
576     gst_buffer_unref(buf);
577     if (freeSamp)
578         IMediaSample_Release(sample);
579     if (hr == VFW_E_NOT_CONNECTED)
580         return GST_FLOW_NOT_LINKED;
581     else if (FAILED(hr))
582         return GST_FLOW_WRONG_STATE;
583     if (hr != S_OK)
584         return GST_FLOW_RESEND;
585     return GST_FLOW_OK;
586 }
587
588 static GstFlowReturn request_buffer_sink(GstPad *pad, guint64 ofs, guint size, GstCaps *caps, GstBuffer **buf) {
589     GSTOutPin *pin = gst_pad_get_element_private(pad);
590     GSTImpl *This = (GSTImpl *)pin->pin.pin.pinInfo.pFilter;
591     IMediaSample *sample;
592     BYTE *ptr;
593     HRESULT hr;
594
595     TRACE("Requesting buffer\n");
596     if (This->initial) {
597         int ret;
598         ret = setcaps_sink(pad, caps);
599         if (!ret)
600             return GST_FLOW_NOT_NEGOTIATED;
601         *buf = gst_buffer_new_and_alloc(size);
602         return GST_FLOW_OK;
603     }
604
605     if (caps && caps != GST_PAD_CAPS(pad))
606         if (!setcaps_sink(pad, caps))
607             return GST_FLOW_NOT_NEGOTIATED;
608
609     hr = BaseOutputPinImpl_GetDeliveryBuffer(&pin->pin, &sample, NULL, NULL, 0);
610     if (hr == VFW_E_NOT_CONNECTED)
611         return GST_FLOW_NOT_LINKED;
612     if (FAILED(hr)) {
613         ERR("Could not get output buffer: %08x\n", hr);
614         *buf = NULL;
615         return GST_FLOW_WRONG_STATE;
616     }
617     IMediaSample_SetActualDataLength(sample, size);
618     IMediaSample_GetPointer(sample, &ptr);
619     *buf = gst_app_buffer_new(ptr, size, release_sample, sample);
620     if (!*buf) {
621         IMediaSample_Release(sample);
622         ERR("Out of memory\n");
623         return GST_FLOW_ERROR;
624     }
625     gst_buffer_set_caps(*buf, caps);
626     return GST_FLOW_OK;
627 }
628
629 static GstFlowReturn request_buffer_src(GstPad *pad, guint64 ofs, guint len, GstBuffer **buf) {
630     GSTImpl *This = gst_pad_get_element_private(pad);
631     int ret;
632
633     *buf = NULL;
634     TRACE("Requesting %s %u\n", wine_dbgstr_longlong(ofs), len);
635     if (ofs == (guint64)-1)
636         ofs = This->nextpullofs;
637     if (ofs >= This->filesize) {
638         WARN("Reading past eof: %s, %u\n", wine_dbgstr_longlong(ofs), len);
639         return GST_FLOW_UNEXPECTED;
640     }
641     if (len + ofs > This->filesize)
642         len = This->filesize - ofs;
643     This->nextpullofs = ofs + len;
644
645     ret = gst_pad_alloc_buffer(This->my_src, ofs, len, NULL, buf);
646     if (ret >= 0) {
647         HRESULT hr;
648         hr = IAsyncReader_SyncRead(This->pInputPin.pReader, ofs, len, GST_BUFFER_DATA(*buf));
649         if (FAILED(hr)) {
650             ERR("Returned %08x\n", hr);
651             return GST_FLOW_ERROR;
652         }
653     }
654     return ret;
655 }
656
657 static DWORD CALLBACK push_data_init(LPVOID iface) {
658     GSTImpl *This = iface;
659     DWORD64 ofs = 0;
660
661     TRACE("Starting..\n");
662     for (;;) {
663         GstBuffer *buf;
664         GstFlowReturn ret = request_buffer_src(This->my_src, ofs, 4096, &buf);
665         if (ret < 0) {
666             ERR("Obtaining buffer returned: %i\n", ret);
667             break;
668         }
669         ret = gst_pad_push(This->my_src, buf);
670         ofs += 4096;
671         if (ret)
672             TRACE("Sending returned: %i\n", ret);
673         if (ret < 0)
674             break;
675     }
676     TRACE("Stopping..\n");
677     return 0;
678 }
679
680 static void removed_decoded_pad(GstElement *bin, GstPad *pad, GSTImpl *This) {
681     int x;
682     GSTOutPin *pin;
683
684     EnterCriticalSection(&This->filter.csFilter);
685     for (x = 0; x < This->cStreams; ++x) {
686         if (This->ppPins[x]->their_src == pad)
687             break;
688     }
689     if (x == This->cStreams)
690         goto out;
691     pin = This->ppPins[x];
692     gst_pad_unlink(pin->their_src, pin->my_sink);
693     gst_object_unref(pin->their_src);
694     pin->their_src = NULL;
695 out:
696     TRACE("Removed %i/%i\n", x, This->cStreams);
697     LeaveCriticalSection(&This->filter.csFilter);
698 }
699
700 static void init_new_decoded_pad(GstElement *bin, GstPad *pad, gboolean last, GSTImpl *This) {
701     HRESULT hr;
702     PIN_INFO piOutput;
703     const char *typename;
704     char *name;
705     AM_MEDIA_TYPE amt = { };
706     GstCaps *caps;
707     GstStructure *arg;
708     GstPad *mypad;
709     GSTOutPin *pin;
710     int ret;
711     int isvid = 0, isaud = 0;
712
713     piOutput.dir = PINDIR_OUTPUT;
714     piOutput.pFilter = (IBaseFilter *)This;
715     name = gst_pad_get_name(pad);
716     MultiByteToWideChar(CP_UNIXCP, 0, name, -1, piOutput.achName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]) - 1);
717     TRACE("Name: %s\n", name);
718     g_free(name);
719     piOutput.achName[sizeof(piOutput.achName) / sizeof(piOutput.achName[0]) - 1] = 0;
720
721     caps = gst_pad_get_caps_reffed(pad);
722     arg = gst_caps_get_structure(caps, 0);
723     typename = gst_structure_get_name(arg);
724
725     mypad = gst_pad_new(NULL, GST_PAD_SINK);
726     gst_pad_set_chain_function(mypad, got_data_sink);
727     gst_pad_set_event_function(mypad, event_sink);
728     gst_pad_set_bufferalloc_function(mypad, request_buffer_sink);
729     gst_pad_set_acceptcaps_function(mypad, accept_caps_sink);
730     gst_pad_set_acceptcaps_function(mypad, setcaps_sink);
731
732     if (!strcmp(typename, "audio/x-raw-int") ||
733         !strcmp(typename, "audio/x-raw-float")) {
734         isaud = 1;
735     } else if (!strcmp(typename, "video/x-raw-rgb")
736                || !strcmp(typename, "video/x-raw-yuv")) {
737         isvid = 1;
738     } else {
739         FIXME("Unknown type \'%s\'\n", typename);
740         return;
741     }
742     GST_PAD_CAPS(mypad) = GST_CAPS_ANY;
743     hr = GST_AddPin(This, &piOutput, &amt);
744     if (FAILED(hr)) {
745         ERR("%08x\n", hr);
746         return;
747     }
748     pin = This->ppPins[This->cStreams - 1];
749     gst_pad_set_element_private(mypad, pin);
750     pin->my_sink = mypad;
751     pin->isaud = isaud;
752     pin->isvid = isvid;
753
754     gst_segment_init(pin->segment, GST_FORMAT_TIME);
755     ret = gst_pad_link(pad, mypad);
756     gst_pad_activate_push(mypad, 1);
757     FIXME("Linking: %i\n", ret);
758     if (ret >= 0) {
759         pin->their_src = pad;
760         gst_object_ref(pin->their_src);
761     }
762 }
763
764 static void existing_new_pad(GstElement *bin, GstPad *pad, gboolean last, GSTImpl *This) {
765     int x;
766
767     if (gst_pad_is_linked(pad))
768         return;
769
770     /* Still holding our own lock */
771     if (This->initial) {
772         init_new_decoded_pad(bin, pad, last, This);
773         return;
774     }
775
776     EnterCriticalSection(&This->filter.csFilter);
777     for (x = 0; x < This->cStreams; ++x) {
778         GSTOutPin *pin = This->ppPins[x];
779         if (!pin->their_src) {
780             gst_segment_init(pin->segment, GST_FORMAT_TIME);
781             if (gst_pad_link(pad, pin->my_sink) >= 0) {
782                 pin->their_src = pad;
783                 gst_object_ref(pin->their_src);
784                 TRACE("Relinked\n");
785                 LeaveCriticalSection(&This->filter.csFilter);
786                 return;
787             }
788         }
789     }
790     init_new_decoded_pad(bin, pad, last, This);
791     LeaveCriticalSection(&This->filter.csFilter);
792 }
793
794 static gboolean check_get_range(GstPad *pad) {
795     return 1;
796 }
797
798 static gboolean query_function(GstPad *pad, GstQuery *query) {
799     GSTImpl *This = gst_pad_get_element_private(pad);
800     GstFormat format;
801     int ret;
802     LONGLONG duration;
803
804     switch (GST_QUERY_TYPE(query)) {
805         case GST_QUERY_DURATION:
806             gst_query_parse_duration (query, &format, NULL);
807             if (format == GST_FORMAT_PERCENT) {
808                 gst_query_set_duration (query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX);
809                 return 1;
810             }
811             ret = gst_pad_query_convert (pad, GST_FORMAT_BYTES, This->filesize, &format, &duration);
812             gst_query_set_duration(query, format, duration);
813             return ret;
814         case GST_QUERY_SEEKING:
815             gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
816             TRACE("Seeking %i %i\n", format, GST_FORMAT_BYTES);
817             if (format != GST_FORMAT_BYTES)
818                 return 0;
819             gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, This->filesize);
820             return 1;
821         default:
822             FIXME("Unhandled query type %i\n", GST_QUERY_TYPE(query));
823         case GST_QUERY_URI:
824         case GST_QUERY_CONVERT:
825             return 0;
826     }
827 }
828
829 static gboolean activate_push(GstPad *pad, gboolean activate) {
830     GSTImpl *This = gst_pad_get_element_private(pad);
831     EnterCriticalSection(&This->filter.csFilter);
832     if (!activate) {
833         TRACE("Deactivating\n");
834         if (!This->initial)
835             IAsyncReader_BeginFlush(This->pInputPin.pReader);
836         if (This->push_thread) {
837             WaitForSingleObject(This->push_thread, -1);
838             CloseHandle(This->push_thread);
839             This->push_thread = NULL;
840         }
841         if (!This->initial)
842             IAsyncReader_EndFlush(This->pInputPin.pReader);
843         if (This->filter.state == State_Stopped)
844             This->nextofs = This->start;
845     } else if (!This->push_thread) {
846         TRACE("Activating\n");
847         if (This->initial)
848             This->push_thread = CreateThread(NULL, 0, push_data_init, This, 0, NULL);
849         else
850             This->push_thread = CreateThread(NULL, 0, push_data, This, 0, NULL);
851     }
852     LeaveCriticalSection(&This->filter.csFilter);
853     return 1;
854 }
855
856 static void no_more_pads(GstElement *decodebin, GSTImpl *This) {
857     FIXME("Done\n");
858     SetEvent(This->event);
859 }
860
861 typedef enum {
862   GST_AUTOPLUG_SELECT_TRY,
863   GST_AUTOPLUG_SELECT_EXPOSE,
864   GST_AUTOPLUG_SELECT_SKIP
865 } GstAutoplugSelectResult;
866
867 static GstAutoplugSelectResult autoplug_blacklist(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *fact, GSTImpl *This) {
868     const char *name = gst_element_factory_get_longname(fact);
869
870     if (strstr(name, "Player protection")) {
871         WARN("Blacklisted a/52 decoder because it only works in Totem\n");
872         return GST_AUTOPLUG_SELECT_SKIP;
873     }
874     if (!strcmp(name, "Fluendo Hardware Accelerated Video Decoder")) {
875         WARN("Disabled video acceleration since it breaks in wine\n");
876         return GST_AUTOPLUG_SELECT_SKIP;
877     }
878     TRACE("using \"%s\"\n", name);
879     return GST_AUTOPLUG_SELECT_TRY;
880 }
881
882 static GstBusSyncReply watch_bus(GstBus *bus, GstMessage *msg, gpointer data) {
883     GSTImpl *This = data;
884     GError *err = NULL;
885     gchar *dbg_info = NULL;
886     if (GST_MESSAGE_TYPE(msg) & GST_MESSAGE_ERROR) {
887         gst_message_parse_error(msg, &err, &dbg_info);
888         FIXME("%s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
889         WARN("%s\n", dbg_info);
890         SetEvent(This->event);
891     } else if (GST_MESSAGE_TYPE(msg) & GST_MESSAGE_WARNING) {
892         gst_message_parse_warning(msg, &err, &dbg_info);
893         WARN("%s: %s\n", GST_OBJECT_NAME(msg->src), err->message);
894         WARN("%s\n", dbg_info);
895     }
896     if (err)
897         g_error_free(err);
898     g_free(dbg_info);
899     return GST_BUS_DROP;
900 }
901
902 static void unknown_type(GstElement *bin, GstPad *pad, GstCaps *caps, GSTImpl *This) {
903     gchar *strcaps = gst_caps_to_string(caps);
904     FIXME("Could not find a filter for caps: %s\n", strcaps);
905     g_free(strcaps);
906 }
907
908 static HRESULT GST_Connect(GSTInPin *pPin, IPin *pConnectPin, ALLOCATOR_PROPERTIES *props) {
909     GSTImpl *This = (GSTImpl*)pPin->pin.pinInfo.pFilter;
910     HRESULT hr;
911     int ret, i;
912     LONGLONG avail, duration;
913     GstFormat format = GST_FORMAT_TIME;
914     GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE(
915         "quartz_src",
916         GST_PAD_SRC,
917         GST_PAD_ALWAYS,
918         GST_STATIC_CAPS_ANY);
919
920     TRACE("%p %p %p\n", pPin, pConnectPin, props);
921     This->props = *props;
922     IAsyncReader_Length(pPin->pReader, &This->filesize, &avail);
923
924     if (!This->bus) {
925         This->bus = gst_bus_new();
926         gst_bus_set_sync_handler(This->bus, watch_bus, This);
927     }
928
929     This->gstfilter = gst_element_factory_make("decodebin2", NULL);
930     if (!This->gstfilter) {
931         FIXME("Could not make source filter, are gstreamer-plugins-* installed for %u bits?\n",
932               8 * (int)sizeof(void*));
933         return E_FAIL;
934     }
935     gst_element_set_bus(This->gstfilter, This->bus);
936     g_signal_connect(This->gstfilter, "new-decoded-pad", G_CALLBACK(existing_new_pad), This);
937     g_signal_connect(This->gstfilter, "pad-removed", G_CALLBACK(removed_decoded_pad), This);
938     g_signal_connect(This->gstfilter, "autoplug-select", G_CALLBACK(autoplug_blacklist), This);
939     g_signal_connect(This->gstfilter, "unknown-type", G_CALLBACK(unknown_type), This);
940
941     This->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src");
942     gst_pad_set_getrange_function(This->my_src, request_buffer_src);
943     gst_pad_set_checkgetrange_function(This->my_src, check_get_range);
944     gst_pad_set_query_function(This->my_src, query_function);
945     gst_pad_set_activatepush_function(This->my_src, activate_push);
946     gst_pad_set_event_function(This->my_src, event_src);
947     gst_pad_set_element_private (This->my_src, This);
948     This->their_sink = gst_element_get_static_pad(This->gstfilter, "sink");
949
950     g_signal_connect(This->gstfilter, "no-more-pads", G_CALLBACK(no_more_pads), This);
951     ret = gst_pad_link(This->my_src, This->their_sink);
952     gst_object_unref(This->their_sink);
953     if (ret < 0) {
954         ERR("Returns: %i\n", ret);
955         return E_FAIL;
956     }
957     This->start = This->nextofs = This->nextpullofs = This->stop = 0;
958
959     /* Add initial pins */
960     This->initial = This->discont = 1;
961     ResetEvent(This->event);
962     gst_element_set_state(This->gstfilter, GST_STATE_PLAYING);
963     gst_pad_set_active(This->my_src, 1);
964     WaitForSingleObject(This->event, -1);
965     gst_element_get_state(This->gstfilter, NULL, NULL, -1);
966
967     if (ret < 0) {
968         WARN("Ret: %i\n", ret);
969         hr = E_FAIL;
970     } else if (!This->cStreams) {
971         FIXME("Gstreamer could not find any streams\n");
972         hr = E_FAIL;
973     } else {
974         gst_pad_query_duration(This->ppPins[0]->their_src, &format, &duration);
975         for (i = 0; i < This->cStreams; ++i) {
976             This->ppPins[i]->seek.llDuration = This->ppPins[i]->seek.llStop = duration / 100;
977             This->ppPins[i]->seek.llCurrent = 0;
978             if (!This->ppPins[i]->seek.llDuration)
979                 This->ppPins[i]->seek.dwCapabilities = 0;
980             WaitForSingleObject(This->ppPins[i]->caps_event, -1);
981         }
982         hr = S_OK;
983     }
984     *props = This->props;
985     gst_element_set_state(This->gstfilter, GST_STATE_READY);
986     gst_element_get_state(This->gstfilter, NULL, NULL, -1);
987     if (This->push_thread)
988         gst_pad_activate_push(This->my_src, 0);
989
990     This->initial = 0;
991     This->nextofs = This->nextpullofs = 0;
992     return hr;
993 }
994
995 static inline GSTOutPin *impl_from_IMediaSeeking( IMediaSeeking *iface ) {
996     return (GSTOutPin *)((char*)iface - FIELD_OFFSET(GSTOutPin, seek.lpVtbl));
997 }
998
999 static IPin* WINAPI GST_GetPin(BaseFilter *iface, int pos)
1000 {
1001     GSTImpl *This = (GSTImpl *)iface;
1002     TRACE("Asking for pos %x\n", pos);
1003
1004     if (pos > This->cStreams || pos < 0)
1005         return NULL;
1006     if (!pos)
1007     {
1008         IPin_AddRef((IPin*)&This->pInputPin);
1009         return (IPin*)&This->pInputPin;
1010     }
1011     else
1012     {
1013         IPin_AddRef((IPin*)This->ppPins[pos - 1]);
1014         return (IPin*)This->ppPins[pos - 1];
1015     }
1016 }
1017
1018 static LONG WINAPI GST_GetPinCount(BaseFilter *iface)
1019 {
1020     GSTImpl *This = (GSTImpl *)iface;
1021     return (This->cStreams + 1);
1022 }
1023
1024 static const BaseFilterFuncTable BaseFuncTable = {
1025     GST_GetPin,
1026     GST_GetPinCount
1027 };
1028
1029 IUnknown * CALLBACK Gstreamer_Splitter_create(IUnknown *punkout, HRESULT *phr) {
1030     IUnknown *obj = NULL;
1031     PIN_INFO *piInput;
1032     GSTImpl *This;
1033
1034     if (!Gstreamer_init())
1035     {
1036         *phr = E_FAIL;
1037         return NULL;
1038     }
1039
1040     This = CoTaskMemAlloc(sizeof(*This));
1041     obj = (IUnknown*)This;
1042     if (!This)
1043     {
1044         *phr = E_OUTOFMEMORY;
1045         return NULL;
1046     }
1047
1048     BaseFilter_Init(&This->filter, &GST_Vtbl, &CLSID_Gstreamer_Splitter, (DWORD_PTR)(__FILE__ ": GSTImpl.csFilter"), &BaseFuncTable);
1049
1050     This->cStreams = 0;
1051     This->ppPins = NULL;
1052     This->push_thread = NULL;
1053     This->event = CreateEventW(NULL, 0, 0, NULL);
1054     This->bus = NULL;
1055
1056     piInput = &This->pInputPin.pin.pinInfo;
1057     piInput->dir = PINDIR_INPUT;
1058     piInput->pFilter = (IBaseFilter *)This;
1059     lstrcpynW(piInput->achName, wcsInputPinName, sizeof(piInput->achName) / sizeof(piInput->achName[0]));
1060     This->pInputPin.pin.lpVtbl = &GST_InputPin_Vtbl;
1061     This->pInputPin.pin.refCount = 1;
1062     This->pInputPin.pin.pConnectedTo = NULL;
1063     This->pInputPin.pin.pCritSec = &This->filter.csFilter;
1064     ZeroMemory(&This->pInputPin.pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
1065     *phr = S_OK;
1066     return obj;
1067 }
1068
1069 static void GST_Destroy(GSTImpl *This) {
1070     IPin *connected = NULL;
1071     ULONG pinref;
1072
1073     TRACE("Destroying\n");
1074
1075     CloseHandle(This->event);
1076
1077     /* Don't need to clean up output pins, disconnecting input pin will do that */
1078     IPin_ConnectedTo((IPin *)&This->pInputPin, &connected);
1079     if (connected) {
1080         assert(IPin_Disconnect(connected) == S_OK);
1081         IPin_Release(connected);
1082         assert(IPin_Disconnect((IPin *)&This->pInputPin) == S_OK);
1083     }
1084     pinref = IPin_Release((IPin *)&This->pInputPin);
1085     if (pinref) {
1086         /* Valgrind could find this, if I kill it here */
1087         ERR("pinref should be null, is %u, destroying anyway\n", pinref);
1088         assert((LONG)pinref > 0);
1089
1090         while (pinref)
1091             pinref = IPin_Release((IPin *)&This->pInputPin);
1092     }
1093     if (This->bus) {
1094         gst_bus_set_sync_handler(This->bus, NULL, NULL);
1095         gst_object_unref(This->bus);
1096     }
1097     CoTaskMemFree(This);
1098 }
1099
1100 static HRESULT WINAPI GST_QueryInterface(IBaseFilter *iface, REFIID riid, LPVOID *ppv) {
1101     GSTImpl *This = (GSTImpl *)iface;
1102     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1103
1104     *ppv = NULL;
1105
1106     if (IsEqualIID(riid, &IID_IUnknown))
1107         *ppv = This;
1108     else if (IsEqualIID(riid, &IID_IPersist))
1109         *ppv = This;
1110     else if (IsEqualIID(riid, &IID_IMediaFilter))
1111         *ppv = This;
1112     else if (IsEqualIID(riid, &IID_IBaseFilter))
1113         *ppv = This;
1114
1115     if (*ppv) {
1116         IUnknown_AddRef((IUnknown *)(*ppv));
1117         return S_OK;
1118     }
1119
1120     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow) &&
1121         !IsEqualIID(riid, &IID_IAMFilterMiscFlags))
1122         FIXME("No interface for %s!\n", debugstr_guid(riid));
1123
1124     return E_NOINTERFACE;
1125 }
1126
1127 static ULONG WINAPI GST_Release(IBaseFilter *iface) {
1128     GSTImpl *This = (GSTImpl *)iface;
1129     ULONG refCount = BaseFilterImpl_Release(iface);
1130
1131     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
1132
1133     if (!refCount)
1134         GST_Destroy(This);
1135
1136     return refCount;
1137 }
1138
1139 static HRESULT WINAPI GST_Stop(IBaseFilter *iface) {
1140     GSTImpl *This = (GSTImpl *)iface;
1141
1142     TRACE("()\n");
1143
1144     if (This->gstfilter)
1145         gst_element_set_state(This->gstfilter, GST_STATE_READY);
1146     return S_OK;
1147 }
1148
1149 static HRESULT WINAPI GST_Pause(IBaseFilter *iface) {
1150     HRESULT hr = S_OK;
1151     GSTImpl *This = (GSTImpl *)iface;
1152     GstState now;
1153     GstStateChangeReturn ret;
1154     TRACE("()\n");
1155
1156     if (!This->gstfilter)
1157         return VFW_E_NOT_CONNECTED;
1158
1159     gst_element_get_state(This->gstfilter, &now, NULL, -1);
1160     if (now == GST_STATE_PAUSED)
1161         return S_OK;
1162     if (now != GST_STATE_PLAYING)
1163         hr = IBaseFilter_Run(iface, -1);
1164     if (FAILED(hr))
1165         return hr;
1166     ret = gst_element_set_state(This->gstfilter, GST_STATE_PAUSED);
1167     if (ret == GST_STATE_CHANGE_ASYNC)
1168         hr = S_FALSE;
1169     return hr;
1170 }
1171
1172 static HRESULT WINAPI GST_Run(IBaseFilter *iface, REFERENCE_TIME tStart) {
1173     HRESULT hr = S_OK;
1174     GSTImpl *This = (GSTImpl *)iface;
1175     ULONG i;
1176     GstState now;
1177     HRESULT hr_any = VFW_E_NOT_CONNECTED;
1178
1179     TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
1180
1181     if (!This->gstfilter)
1182         return VFW_E_NOT_CONNECTED;
1183
1184     EnterCriticalSection(&This->filter.csFilter);
1185     This->filter.rtStreamStart = tStart;
1186     LeaveCriticalSection(&This->filter.csFilter);
1187
1188     gst_element_get_state(This->gstfilter, &now, NULL, -1);
1189     if (now == GST_STATE_PLAYING)
1190         return S_OK;
1191     if (now == GST_STATE_PAUSED) {
1192         GstStateChangeReturn ret;
1193         ret = gst_element_set_state(This->gstfilter, GST_STATE_PLAYING);
1194         if (ret == GST_STATE_CHANGE_ASYNC)
1195             return S_FALSE;
1196         return S_OK;
1197     }
1198
1199     EnterCriticalSection(&This->filter.csFilter);
1200     gst_pad_set_blocked(This->my_src, 0);
1201     gst_pad_set_blocked(This->their_sink, 0);
1202     gst_element_set_state(This->gstfilter, GST_STATE_PLAYING);
1203     This->filter.rtStreamStart = tStart;
1204
1205     for (i = 0; i < This->cStreams; i++) {
1206         hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->ppPins[i]);
1207         if (SUCCEEDED(hr)) {
1208             gst_pad_set_blocked(This->ppPins[i]->my_sink, 0);
1209             if (This->ppPins[i]->their_src)
1210                 gst_pad_set_blocked(This->ppPins[i]->their_src, 0);
1211             hr_any = hr;
1212         }
1213     }
1214     hr = hr_any;
1215     if (SUCCEEDED(hr))
1216         gst_pad_set_active(This->my_src, 1);
1217     LeaveCriticalSection(&This->filter.csFilter);
1218
1219     return hr;
1220 }
1221
1222 static HRESULT WINAPI GST_GetState(IBaseFilter *iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) {
1223     GSTImpl *This = (GSTImpl *)iface;
1224     HRESULT hr = S_OK;
1225     GstState now, pending;
1226     GstStateChangeReturn ret;
1227
1228     TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState);
1229
1230     if (!This->gstfilter) {
1231         *pState = State_Stopped;
1232         return S_OK;
1233     }
1234
1235     ret = gst_element_get_state(This->gstfilter, &now, &pending, dwMilliSecsTimeout == INFINITE ? -1 : dwMilliSecsTimeout * 1000);
1236
1237     if (ret == GST_STATE_CHANGE_ASYNC)
1238         hr = VFW_S_STATE_INTERMEDIATE;
1239     else
1240         pending = now;
1241
1242     switch (pending) {
1243         case GST_STATE_PAUSED: *pState = State_Paused; return hr;
1244         case GST_STATE_PLAYING: *pState = State_Running; return hr;
1245         default: *pState = State_Stopped; return hr;
1246     }
1247 }
1248
1249 static HRESULT WINAPI GST_FindPin(IBaseFilter *iface, LPCWSTR Id, IPin **ppPin) {
1250     FIXME("(%p)->(%s,%p) stub\n", iface, debugstr_w(Id), ppPin);
1251     return E_NOTIMPL;
1252 }
1253
1254 static const IBaseFilterVtbl GST_Vtbl = {
1255     GST_QueryInterface,
1256     BaseFilterImpl_AddRef,
1257     GST_Release,
1258     BaseFilterImpl_GetClassID,
1259     GST_Stop,
1260     GST_Pause,
1261     GST_Run,
1262     GST_GetState,
1263     BaseFilterImpl_SetSyncSource,
1264     BaseFilterImpl_GetSyncSource,
1265     BaseFilterImpl_EnumPins,
1266     GST_FindPin,
1267     BaseFilterImpl_QueryFilterInfo,
1268     BaseFilterImpl_JoinFilterGraph,
1269     BaseFilterImpl_QueryVendorInfo
1270 };
1271
1272 static HRESULT WINAPI GST_ChangeCurrent(IMediaSeeking *iface) {
1273     return S_OK;
1274 }
1275
1276 static HRESULT WINAPI GST_ChangeStop(IMediaSeeking *iface) {
1277     return S_OK;
1278 }
1279
1280 static HRESULT WINAPI GST_ChangeRate(IMediaSeeking *iface) {
1281     GSTOutPin *This = impl_from_IMediaSeeking(iface);
1282     GstEvent *ev = gst_event_new_seek(This->seek.dRate, GST_FORMAT_TIME, 0, GST_SEEK_TYPE_NONE, -1, GST_SEEK_TYPE_NONE, -1);
1283     TRACE("(%p) New rate %g\n", iface, This->seek.dRate);
1284     gst_pad_push_event(This->my_sink, ev);
1285     return S_OK;
1286 }
1287
1288 static HRESULT WINAPI GST_Seeking_QueryInterface(IMediaSeeking *iface, REFIID riid, void **ppv) {
1289     GSTOutPin *This = impl_from_IMediaSeeking(iface);
1290     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
1291 }
1292
1293 static ULONG WINAPI GST_Seeking_AddRef(IMediaSeeking *iface) {
1294     GSTOutPin *This = impl_from_IMediaSeeking(iface);
1295     return IUnknown_AddRef((IUnknown *)This);
1296 }
1297
1298 static ULONG WINAPI GST_Seeking_Release(IMediaSeeking *iface) {
1299     GSTOutPin *This = impl_from_IMediaSeeking(iface);
1300     return IUnknown_Release((IUnknown *)This);
1301 }
1302
1303 static HRESULT WINAPI GST_Seeking_GetCurrentPosition(IMediaSeeking *iface, REFERENCE_TIME *pos) {
1304     GSTOutPin *This = impl_from_IMediaSeeking(iface);
1305     GstFormat format = GST_FORMAT_TIME;
1306
1307     if (!pos)
1308         return E_POINTER;
1309
1310     if (!This->their_src) {
1311         *pos = This->seek.llCurrent;
1312         TRACE("Cached value\n");
1313         if (This->seek.llDuration)
1314             return S_OK;
1315         else
1316             return E_NOTIMPL;
1317     }
1318
1319     if (!gst_pad_query_position(This->their_src, &format, pos)) {
1320         WARN("Could not query position\n");
1321         return E_NOTIMPL;
1322     }
1323     *pos /= 100;
1324     This->seek.llCurrent = *pos;
1325     return S_OK;
1326 }
1327
1328 static GstSeekType type_from_flags(DWORD flags) {
1329     switch (flags & AM_SEEKING_PositioningBitsMask) {
1330     case AM_SEEKING_NoPositioning: return GST_SEEK_TYPE_NONE;
1331     case AM_SEEKING_AbsolutePositioning: return GST_SEEK_TYPE_SET;
1332     case AM_SEEKING_RelativePositioning: return GST_SEEK_TYPE_CUR;
1333     case AM_SEEKING_IncrementalPositioning: return GST_SEEK_TYPE_END;
1334     }
1335     return GST_SEEK_TYPE_NONE;
1336 }
1337
1338
1339 static HRESULT WINAPI GST_Seeking_SetPositions(IMediaSeeking *iface, REFERENCE_TIME *pCur, DWORD curflags, REFERENCE_TIME *pStop, DWORD stopflags) {
1340     HRESULT hr;
1341     GSTOutPin *This = impl_from_IMediaSeeking(iface);
1342     GstSeekFlags f = 0;
1343     GstSeekType curtype, stoptype;
1344     GstEvent *e;
1345
1346     if (!This->seek.llDuration)
1347         return E_NOTIMPL;
1348
1349     hr = SourceSeekingImpl_SetPositions(iface, pCur, curflags, pStop, stopflags);
1350     if (!This->their_src)
1351         return hr;
1352
1353     curtype = type_from_flags(curflags);
1354     stoptype = type_from_flags(stopflags);
1355     if (curflags & AM_SEEKING_SeekToKeyFrame)
1356         f |= GST_SEEK_FLAG_KEY_UNIT;
1357     if (curflags & AM_SEEKING_Segment)
1358         f |= GST_SEEK_FLAG_SEGMENT;
1359     if (!(curflags & AM_SEEKING_NoFlush))
1360         f |= GST_SEEK_FLAG_FLUSH;
1361
1362     e = gst_event_new_seek(This->seek.dRate, GST_FORMAT_TIME, f, curtype, pCur ? *pCur * 100 : -1, stoptype, pStop ? *pStop * 100 : -1);
1363     if (gst_pad_push_event(This->my_sink, e))
1364         return S_OK;
1365     else
1366         return E_NOTIMPL;
1367 }
1368
1369 static const IMediaSeekingVtbl GST_Seeking_Vtbl =
1370 {
1371     GST_Seeking_QueryInterface,
1372     GST_Seeking_AddRef,
1373     GST_Seeking_Release,
1374     SourceSeekingImpl_GetCapabilities,
1375     SourceSeekingImpl_CheckCapabilities,
1376     SourceSeekingImpl_IsFormatSupported,
1377     SourceSeekingImpl_QueryPreferredFormat,
1378     SourceSeekingImpl_GetTimeFormat,
1379     SourceSeekingImpl_IsUsingTimeFormat,
1380     SourceSeekingImpl_SetTimeFormat,
1381     SourceSeekingImpl_GetDuration,
1382     SourceSeekingImpl_GetStopPosition,
1383     GST_Seeking_GetCurrentPosition,
1384     SourceSeekingImpl_ConvertTimeFormat,
1385     GST_Seeking_SetPositions,
1386     SourceSeekingImpl_GetPositions,
1387     SourceSeekingImpl_GetAvailable,
1388     SourceSeekingImpl_SetRate,
1389     SourceSeekingImpl_GetRate,
1390     SourceSeekingImpl_GetPreroll
1391 };
1392
1393 static HRESULT WINAPI GST_QualityControl_Notify(IQualityControl *iface, IBaseFilter *sender, Quality qm) {
1394     QualityControlImpl *This = (QualityControlImpl*)iface;
1395     GSTOutPin *pin = (GSTOutPin*)This->self;
1396     REFERENCE_TIME late = qm.Late;
1397     if (qm.Late < 0 && -qm.Late > qm.TimeStamp)
1398         late = -qm.TimeStamp;
1399     gst_pad_push_event(pin->my_sink, gst_event_new_qos(1000./qm.Proportion, late*100, qm.TimeStamp*100));
1400     return S_OK;
1401 }
1402
1403 static const IQualityControlVtbl GSTOutPin_QualityControl_Vtbl = {
1404     QualityControlImpl_QueryInterface,
1405     QualityControlImpl_AddRef,
1406     QualityControlImpl_Release,
1407     GST_QualityControl_Notify,
1408     QualityControlImpl_SetSink
1409 };
1410
1411 static HRESULT WINAPI GSTOutPin_QueryInterface(IPin *iface, REFIID riid, void **ppv) {
1412     GSTOutPin *This = (GSTOutPin *)iface;
1413
1414     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1415
1416     *ppv = NULL;
1417
1418     if (IsEqualIID(riid, &IID_IUnknown))
1419         *ppv = iface;
1420     else if (IsEqualIID(riid, &IID_IPin))
1421         *ppv = iface;
1422     else if (IsEqualIID(riid, &IID_IMediaSeeking))
1423         *ppv = &This->seek;
1424     else if (IsEqualIID(riid, &IID_IQualityControl))
1425         *ppv = &This->qcimpl;
1426
1427     if (*ppv) {
1428         IUnknown_AddRef((IUnknown *)(*ppv));
1429         return S_OK;
1430     }
1431     FIXME("No interface for %s!\n", debugstr_guid(riid));
1432     return E_NOINTERFACE;
1433 }
1434
1435 static ULONG WINAPI GSTOutPin_Release(IPin *iface) {
1436     GSTOutPin *This = (GSTOutPin *)iface;
1437     ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
1438     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
1439
1440     if (!refCount) {
1441         if (This->their_src)
1442             gst_pad_unlink(This->their_src, This->my_sink);
1443         gst_object_unref(This->my_sink);
1444         CloseHandle(This->caps_event);
1445         DeleteMediaType(This->pmt);
1446         FreeMediaType(&This->pin.pin.mtCurrent);
1447         gst_segment_free(This->segment);
1448         CoTaskMemFree(This);
1449         return 0;
1450     }
1451     return refCount;
1452 }
1453
1454 static HRESULT WINAPI GSTOutPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
1455 {
1456     GSTOutPin *This = (GSTOutPin *)iface;
1457
1458     if (iPosition < 0)
1459         return E_INVALIDARG;
1460     if (iPosition > 0)
1461         return VFW_S_NO_MORE_ITEMS;
1462     CopyMediaType(pmt, This->pmt);
1463     return S_OK;
1464 }
1465
1466 static HRESULT WINAPI GSTOutPin_DecideBufferSize(BaseOutputPin *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
1467 {
1468     /* Unused */
1469     return S_OK;
1470 }
1471
1472 static HRESULT WINAPI GSTOutPin_DecideAllocator(BaseOutputPin *iface, IMemInputPin *pPin, IMemAllocator **pAlloc)
1473 {
1474     HRESULT hr;
1475     GSTOutPin *This = (GSTOutPin *)iface;
1476     GSTImpl *GSTfilter = (GSTImpl*)This->pin.pin.pinInfo.pFilter;
1477
1478     pAlloc = NULL;
1479     if (GSTfilter->pInputPin.pAlloc)
1480         hr = IMemInputPin_NotifyAllocator(pPin, GSTfilter->pInputPin.pAlloc, FALSE);
1481     else
1482         hr = VFW_E_NO_ALLOCATOR;
1483
1484     return hr;
1485 }
1486
1487 static HRESULT WINAPI GSTOutPin_BreakConnect(BaseOutputPin *This)
1488 {
1489     HRESULT hr;
1490
1491     TRACE("(%p)->()\n", This);
1492
1493     EnterCriticalSection(This->pin.pCritSec);
1494     if (!This->pin.pConnectedTo || !This->pMemInputPin)
1495         hr = VFW_E_NOT_CONNECTED;
1496     else
1497     {
1498         hr = IPin_Disconnect(This->pin.pConnectedTo);
1499         IPin_Disconnect((IPin *)This);
1500     }
1501     LeaveCriticalSection(This->pin.pCritSec);
1502
1503     return hr;
1504 }
1505
1506 static const IPinVtbl GST_OutputPin_Vtbl = {
1507     GSTOutPin_QueryInterface,
1508     BasePinImpl_AddRef,
1509     GSTOutPin_Release,
1510     BaseOutputPinImpl_Connect,
1511     BaseOutputPinImpl_ReceiveConnection,
1512     BaseOutputPinImpl_Disconnect,
1513     BasePinImpl_ConnectedTo,
1514     BasePinImpl_ConnectionMediaType,
1515     BasePinImpl_QueryPinInfo,
1516     BasePinImpl_QueryDirection,
1517     BasePinImpl_QueryId,
1518     GST_OutPin_QueryAccept,
1519     BasePinImpl_EnumMediaTypes,
1520     BasePinImpl_QueryInternalConnections,
1521     BaseOutputPinImpl_EndOfStream,
1522     BaseOutputPinImpl_BeginFlush,
1523     BaseOutputPinImpl_EndFlush,
1524     BasePinImpl_NewSegment
1525 };
1526
1527 static const BasePinFuncTable output_BaseFuncTable = {
1528     NULL,
1529     BaseOutputPinImpl_AttemptConnection,
1530     BasePinImpl_GetMediaTypeVersion,
1531     GSTOutPin_GetMediaType
1532 };
1533
1534 static const BaseOutputPinFuncTable output_BaseOutputFuncTable = {
1535     GSTOutPin_DecideBufferSize,
1536     GSTOutPin_DecideAllocator,
1537     GSTOutPin_BreakConnect
1538 };
1539
1540 static HRESULT GST_AddPin(GSTImpl *This, const PIN_INFO *piOutput, const AM_MEDIA_TYPE *amt) {
1541     HRESULT hr;
1542     This->ppPins = CoTaskMemRealloc(This->ppPins, (This->cStreams + 1) * sizeof(IPin *));
1543
1544     hr = BaseOutputPin_Construct(&GST_OutputPin_Vtbl, sizeof(GSTOutPin), piOutput, &output_BaseFuncTable, &output_BaseOutputFuncTable, &This->filter.csFilter, (IPin**)(This->ppPins + This->cStreams));
1545     if (SUCCEEDED(hr)) {
1546         GSTOutPin *pin = This->ppPins[This->cStreams];
1547         pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
1548         CopyMediaType(pin->pmt, amt);
1549         pin->pin.pin.pinInfo.pFilter = (LPVOID)This;
1550         pin->caps_event = CreateEventW(NULL, 0, 0, NULL);
1551         pin->segment = gst_segment_new();
1552         This->cStreams++;
1553         QualityControlImpl_init(&pin->qcimpl, NULL, (IBaseFilter*)pin);
1554         pin->qcimpl.lpVtbl = &GSTOutPin_QualityControl_Vtbl;
1555         SourceSeeking_Init(&pin->seek, &GST_Seeking_Vtbl, GST_ChangeStop, GST_ChangeCurrent, GST_ChangeRate, &This->filter.csFilter);
1556         BaseFilterImpl_IncrementPinVersion((BaseFilter*)This);
1557     } else
1558         ERR("Failed with error %x\n", hr);
1559     return hr;
1560 }
1561
1562 static HRESULT GST_RemoveOutputPins(GSTImpl *This) {
1563     HRESULT hr;
1564     ULONG i;
1565     GSTOutPin **ppOldPins = This->ppPins;
1566     TRACE("(%p)\n", This);
1567
1568     if (!This->gstfilter)
1569         return S_OK;
1570     gst_element_set_bus(This->gstfilter, NULL);
1571     gst_element_set_state(This->gstfilter, GST_STATE_NULL);
1572     gst_pad_unlink(This->my_src, This->their_sink);
1573     if (This->push_thread)
1574         gst_pad_activate_push(This->my_src, 0);
1575     gst_object_unref(This->my_src);
1576     This->my_src = This->their_sink = NULL;
1577
1578     for (i = 0; i < This->cStreams; i++) {
1579         hr = BaseOutputPinImpl_BreakConnect(&ppOldPins[i]->pin);
1580         TRACE("Disconnect: %08x\n", hr);
1581         IPin_Release((IPin*)ppOldPins[i]);
1582     }
1583     This->cStreams = 0;
1584     This->ppPins = NULL;
1585     gst_object_unref(This->gstfilter);
1586     This->gstfilter = NULL;
1587     BaseFilterImpl_IncrementPinVersion((BaseFilter*)This);
1588     CoTaskMemFree(ppOldPins);
1589     return S_OK;
1590 }
1591
1592 static ULONG WINAPI GSTInPin_Release(IPin *iface) {
1593     GSTInPin *This = (GSTInPin*)iface;
1594     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
1595
1596     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
1597     if (!refCount) {
1598         FreeMediaType(&This->pin.mtCurrent);
1599         if (This->pAlloc)
1600             IMemAllocator_Release(This->pAlloc);
1601         This->pAlloc = NULL;
1602         This->pin.lpVtbl = NULL;
1603         return 0;
1604     } else
1605         return refCount;
1606 }
1607
1608 static HRESULT WINAPI GSTInPin_ReceiveConnection(IPin *iface, IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) {
1609     PIN_DIRECTION pindirReceive;
1610     HRESULT hr = S_OK;
1611     GSTInPin *This = (GSTInPin*)iface;
1612
1613     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
1614     dump_AM_MEDIA_TYPE(pmt);
1615
1616     EnterCriticalSection(This->pin.pCritSec);
1617     if (!This->pin.pConnectedTo) {
1618         ALLOCATOR_PROPERTIES props;
1619
1620         props.cBuffers = 8;
1621         props.cbBuffer = 16384;
1622         props.cbAlign = 1;
1623         props.cbPrefix = 0;
1624
1625         if (SUCCEEDED(hr) && IPin_QueryAccept(iface, pmt) != S_OK)
1626             hr = VFW_E_TYPE_NOT_ACCEPTED;
1627         if (SUCCEEDED(hr)) {
1628             IPin_QueryDirection(pReceivePin, &pindirReceive);
1629             if (pindirReceive != PINDIR_OUTPUT) {
1630                 ERR("Can't connect from non-output pin\n");
1631                 hr = VFW_E_INVALID_DIRECTION;
1632             }
1633         }
1634
1635         This->pReader = NULL;
1636         This->pAlloc = NULL;
1637         if (SUCCEEDED(hr))
1638             hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader);
1639         if (SUCCEEDED(hr))
1640             hr = GST_Connect(This, pReceivePin, &props);
1641         if (SUCCEEDED(hr))
1642             hr = IAsyncReader_RequestAllocator(This->pReader, NULL, &props, &This->pAlloc);
1643         if (SUCCEEDED(hr)) {
1644             CopyMediaType(&This->pin.mtCurrent, pmt);
1645             This->pin.pConnectedTo = pReceivePin;
1646             IPin_AddRef(pReceivePin);
1647             hr = IMemAllocator_Commit(This->pAlloc);
1648         } else {
1649             GST_RemoveOutputPins((GSTImpl *)This->pin.pinInfo.pFilter);
1650             if (This->pReader)
1651                 IAsyncReader_Release(This->pReader);
1652             This->pReader = NULL;
1653             if (This->pAlloc)
1654                 IMemAllocator_Release(This->pAlloc);
1655             This->pAlloc = NULL;
1656         }
1657         TRACE("Size: %i\n", props.cbBuffer);
1658     } else
1659         hr = VFW_E_ALREADY_CONNECTED;
1660     LeaveCriticalSection(This->pin.pCritSec);
1661     return hr;
1662 }
1663
1664 static HRESULT WINAPI GSTInPin_Disconnect(IPin *iface) {
1665     HRESULT hr;
1666     GSTInPin *This = (GSTInPin*)iface;
1667     FILTER_STATE state;
1668     TRACE("()\n");
1669
1670     hr = IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
1671     EnterCriticalSection(This->pin.pCritSec);
1672     if (This->pin.pConnectedTo) {
1673         GSTImpl *Parser = (GSTImpl *)This->pin.pinInfo.pFilter;
1674
1675         if (SUCCEEDED(hr) && state == State_Stopped) {
1676             IMemAllocator_Decommit(This->pAlloc);
1677             IPin_Disconnect(This->pin.pConnectedTo);
1678             This->pin.pConnectedTo = NULL;
1679             hr = GST_RemoveOutputPins(Parser);
1680         } else
1681             hr = VFW_E_NOT_STOPPED;
1682     } else
1683         hr = S_FALSE;
1684     LeaveCriticalSection(This->pin.pCritSec);
1685     return hr;
1686 }
1687
1688 static HRESULT WINAPI GSTInPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt) {
1689     GSTInPin *This = (GSTInPin*)iface;
1690
1691     TRACE("(%p)->(%p)\n", This, pmt);
1692     dump_AM_MEDIA_TYPE(pmt);
1693
1694     if (IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream))
1695         return S_OK;
1696     return S_FALSE;
1697 }
1698
1699 static HRESULT WINAPI GSTInPin_EndOfStream(IPin *iface) {
1700     GSTInPin *pin = (GSTInPin*)iface;
1701     GSTImpl *This = (GSTImpl*)pin->pin.pinInfo.pFilter;
1702
1703     FIXME("Propagate message on %p\n", This);
1704     return S_OK;
1705 }
1706
1707 static HRESULT WINAPI GSTInPin_BeginFlush(IPin *iface) {
1708     GSTInPin *pin = (GSTInPin*)iface;
1709     GSTImpl *This = (GSTImpl*)pin->pin.pinInfo.pFilter;
1710
1711     FIXME("Propagate message on %p\n", This);
1712     return S_OK;
1713 }
1714
1715 static HRESULT WINAPI GSTInPin_EndFlush(IPin *iface) {
1716     GSTInPin *pin = (GSTInPin*)iface;
1717     GSTImpl *This = (GSTImpl*)pin->pin.pinInfo.pFilter;
1718
1719     FIXME("Propagate message on %p\n", This);
1720     return S_OK;
1721 }
1722
1723 static HRESULT WINAPI GSTInPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) {
1724     GSTInPin *pin = (GSTInPin*)iface;
1725     GSTImpl *This = (GSTImpl*)pin->pin.pinInfo.pFilter;
1726
1727     BasePinImpl_NewSegment(iface, tStart, tStop, dRate);
1728     FIXME("Propagate message on %p\n", This);
1729     return S_OK;
1730 }
1731
1732 static HRESULT WINAPI GSTInPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
1733 {
1734     GSTInPin *This = (GSTInPin*)iface;
1735
1736     TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
1737
1738     *ppv = NULL;
1739
1740     if (IsEqualIID(riid, &IID_IUnknown))
1741         *ppv = iface;
1742     else if (IsEqualIID(riid, &IID_IPin))
1743         *ppv = iface;
1744     else if (IsEqualIID(riid, &IID_IMediaSeeking))
1745     {
1746         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
1747     }
1748
1749     if (*ppv)
1750     {
1751         IUnknown_AddRef((IUnknown *)(*ppv));
1752         return S_OK;
1753     }
1754
1755     FIXME("No interface for %s!\n", debugstr_guid(riid));
1756
1757     return E_NOINTERFACE;
1758 }
1759
1760 static HRESULT WINAPI GSTInPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum)
1761 {
1762     BasePin *This = (BasePin *)iface;
1763
1764     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
1765
1766     return EnumMediaTypes_Construct(This, BasePinImpl_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum);
1767 }
1768
1769 static const IPinVtbl GST_InputPin_Vtbl = {
1770     GSTInPin_QueryInterface,
1771     BasePinImpl_AddRef,
1772     GSTInPin_Release,
1773     BaseInputPinImpl_Connect,
1774     GSTInPin_ReceiveConnection,
1775     GSTInPin_Disconnect,
1776     BasePinImpl_ConnectedTo,
1777     BasePinImpl_ConnectionMediaType,
1778     BasePinImpl_QueryPinInfo,
1779     BasePinImpl_QueryDirection,
1780     BasePinImpl_QueryId,
1781     GSTInPin_QueryAccept,
1782     GSTInPin_EnumMediaTypes,
1783     BasePinImpl_QueryInternalConnections,
1784     GSTInPin_EndOfStream,
1785     GSTInPin_BeginFlush,
1786     GSTInPin_EndFlush,
1787     GSTInPin_NewSegment
1788 };