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