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