Release 1.5.29.
[wine] / dlls / qedit / samplegrabber.c
1 /*              DirectShow Sample Grabber object (QEDIT.DLL)
2  *
3  * Copyright 2009 Paul Chitescu
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <assert.h>
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29
30 #include "qedit_private.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(qedit);
34
35 static const WCHAR vendor_name[] = { 'W', 'i', 'n', 'e', 0 };
36 static const WCHAR pin_in_name[] = { 'I', 'n', 0 };
37 static const WCHAR pin_out_name[] = { 'O', 'u', 't', 0 };
38
39 static IEnumPins *pinsenum_create(IBaseFilter *filter, IPin **pins, ULONG pinCount);
40 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype);
41
42 /* Fixed pins enumerator, holds filter referenced */
43 typedef struct _PE_Impl {
44     IEnumPins pe;
45     IBaseFilter *filter;
46     LONG refCount;
47     ULONG numPins;
48     ULONG index;
49     IPin *pins[0];
50 } PE_Impl;
51
52
53 /* IEnumPins interface implementation */
54
55 /* IUnknown */
56 static ULONG WINAPI
57 Fixed_IEnumPins_AddRef(IEnumPins *iface)
58 {
59     PE_Impl *This = (PE_Impl *)iface;
60     ULONG refCount = InterlockedIncrement(&This->refCount);
61     TRACE("(%p) new ref = %u\n", This, refCount);
62     return refCount;
63 }
64
65 /* IUnknown */
66 static ULONG WINAPI
67 Fixed_IEnumPins_Release(IEnumPins *iface)
68 {
69     PE_Impl *This = (PE_Impl *)iface;
70     ULONG refCount = InterlockedDecrement(&This->refCount);
71     TRACE("(%p) new ref = %u\n", This, refCount);
72     if (refCount == 0)
73     {
74         IBaseFilter_Release(This->filter);
75         CoTaskMemFree(This);
76         return 0;
77     }
78     return refCount;
79 }
80
81 /* IUnknown */
82 static HRESULT WINAPI
83 Fixed_IEnumPins_QueryInterface(IEnumPins *iface, REFIID riid, void **ppvObject)
84 {
85     PE_Impl *This = (PE_Impl *)iface;
86     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
87
88     if (IsEqualIID(riid, &IID_IUnknown) ||
89         IsEqualIID(riid, &IID_IEnumPins)) {
90         Fixed_IEnumPins_AddRef(iface);
91         *ppvObject = This->pins;
92         return S_OK;
93     }
94     *ppvObject = NULL;
95     WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
96     return E_NOINTERFACE;
97 }
98
99 /* IEnumPins */
100 static HRESULT WINAPI
101 Fixed_IEnumPins_Next(IEnumPins *iface, ULONG nPins, IPin **pins, ULONG *fetched)
102 {
103     PE_Impl *This = (PE_Impl *)iface;
104     ULONG count = 0;
105     TRACE("(%p)->(%u, %p, %p) index = %u\n", This, nPins, pins, fetched, This->index);
106     if (!nPins)
107         return E_INVALIDARG;
108     if (!pins || ((nPins != 1) && !fetched))
109         return E_POINTER;
110     while ((count < nPins) && (This->index < This->numPins)) {
111         IPin *pin = This->pins[This->index++];
112         IPin_AddRef(pin);
113         pins[count++] = pin;
114     }
115     if (fetched)
116         *fetched = count;
117     return (count == nPins) ? S_OK : S_FALSE;
118 }
119
120 /* IEnumPins */
121 static HRESULT WINAPI
122 Fixed_IEnumPins_Skip(IEnumPins *iface, ULONG nPins)
123 {
124     PE_Impl *This = (PE_Impl *)iface;
125     TRACE("(%p)->(%u) index = %u\n", This, nPins, This->index);
126     nPins += This->index;
127     if (nPins >= This->numPins) {
128         This->index = This->numPins;
129         return S_FALSE;
130     }
131     This->index = nPins;
132     return S_OK;
133 }
134
135 /* IEnumPins */
136 static HRESULT WINAPI
137 Fixed_IEnumPins_Reset(IEnumPins *iface)
138 {
139     PE_Impl *This = (PE_Impl *)iface;
140     TRACE("(%p)->() index = %u\n", This, This->index);
141     This->index = 0;
142     return S_OK;
143 }
144
145 /* IEnumPins */
146 static HRESULT WINAPI
147 Fixed_IEnumPins_Clone(IEnumPins *iface, IEnumPins **pins)
148 {
149     PE_Impl *This = (PE_Impl *)iface;
150     TRACE("(%p)->(%p) index = %u\n", This, pins, This->index);
151     if (!pins)
152         return E_POINTER;
153     *pins = pinsenum_create(This->filter, This->pins, This->numPins);
154     if (!*pins)
155         return E_OUTOFMEMORY;
156     ((PE_Impl *)*pins)->index = This->index;
157     return S_OK;
158 }
159
160
161 /* Virtual tables and constructor */
162
163 static const IEnumPinsVtbl IEnumPins_VTable =
164 {
165     Fixed_IEnumPins_QueryInterface,
166     Fixed_IEnumPins_AddRef,
167     Fixed_IEnumPins_Release,
168     Fixed_IEnumPins_Next,
169     Fixed_IEnumPins_Skip,
170     Fixed_IEnumPins_Reset,
171     Fixed_IEnumPins_Clone,
172 };
173
174 static IEnumPins *pinsenum_create(IBaseFilter *filter, IPin **pins, ULONG pinCount)
175 {
176     ULONG len = sizeof(PE_Impl) + (pinCount * sizeof(IPin *));
177     PE_Impl *obj = CoTaskMemAlloc(len);
178     if (obj) {
179         ULONG i;
180         ZeroMemory(obj, len);
181         obj->pe.lpVtbl = &IEnumPins_VTable;
182         obj->refCount = 1;
183         obj->filter = filter;
184         obj->numPins = pinCount;
185         obj->index = 0;
186         for (i=0; i<pinCount; i++)
187             obj->pins[i] = pins[i];
188         IBaseFilter_AddRef(filter);
189     }
190     return &obj->pe;
191 }
192
193
194 /* Single media type enumerator */
195 typedef struct _ME_Impl {
196     IEnumMediaTypes me;
197     LONG refCount;
198     BOOL past;
199     AM_MEDIA_TYPE mtype;
200 } ME_Impl;
201
202
203 /* IEnumMediaTypes interface implementation */
204
205 /* IUnknown */
206 static ULONG WINAPI
207 Single_IEnumMediaTypes_AddRef(IEnumMediaTypes *iface)
208 {
209     ME_Impl *This = (ME_Impl *)iface;
210     ULONG refCount = InterlockedIncrement(&This->refCount);
211     TRACE("(%p) new ref = %u\n", This, refCount);
212     return refCount;
213 }
214
215 /* IUnknown */
216 static ULONG WINAPI
217 Single_IEnumMediaTypes_Release(IEnumMediaTypes *iface)
218 {
219     ME_Impl *This = (ME_Impl *)iface;
220     ULONG refCount = InterlockedDecrement(&This->refCount);
221     TRACE("(%p) new ref = %u\n", This, refCount);
222     if (refCount == 0)
223     {
224         if (This->mtype.pbFormat)
225             CoTaskMemFree(This->mtype.pbFormat);
226         CoTaskMemFree(This);
227         return 0;
228     }
229     return refCount;
230 }
231
232 /* IUnknown */
233 static HRESULT WINAPI
234 Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes *iface, REFIID riid, void **ppvObject)
235 {
236     ME_Impl *This = (ME_Impl *)iface;
237     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
238
239     if (IsEqualIID(riid, &IID_IUnknown) ||
240         IsEqualIID(riid, &IID_IEnumMediaTypes)) {
241         Single_IEnumMediaTypes_AddRef(iface);
242         *ppvObject = &(This->me);
243         return S_OK;
244     }
245     *ppvObject = NULL;
246     WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
247     return E_NOINTERFACE;
248 }
249
250 /* IEnumMediaTypes */
251 static HRESULT WINAPI
252 Single_IEnumMediaTypes_Next(IEnumMediaTypes *iface, ULONG nTypes, AM_MEDIA_TYPE **types, ULONG *fetched)
253 {
254     ME_Impl *This = (ME_Impl *)iface;
255     ULONG count = 0;
256     TRACE("(%p)->(%u, %p, %p)\n", This, nTypes, types, fetched);
257     if (!nTypes)
258         return E_INVALIDARG;
259     if (!types || ((nTypes != 1) && !fetched))
260         return E_POINTER;
261     if (!This->past && !IsEqualGUID(&This->mtype.majortype,&GUID_NULL)) {
262         AM_MEDIA_TYPE *mtype = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
263         *mtype = This->mtype;
264         if (mtype->cbFormat) {
265             mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
266             CopyMemory(mtype->pbFormat, This->mtype.pbFormat, mtype->cbFormat);
267         }
268         *types = mtype;
269         This->past = TRUE;
270         count = 1;
271     }
272     if (fetched)
273         *fetched = count;
274     return (count == nTypes) ? S_OK : S_FALSE;
275 }
276
277 /* IEnumMediaTypes */
278 static HRESULT WINAPI
279 Single_IEnumMediaTypes_Skip(IEnumMediaTypes *iface, ULONG nTypes)
280 {
281     ME_Impl *This = (ME_Impl *)iface;
282     TRACE("(%p)->(%u)\n", This, nTypes);
283     if (nTypes)
284         This->past = TRUE;
285     return This->past ? S_FALSE : S_OK;
286 }
287
288 /* IEnumMediaTypes */
289 static HRESULT WINAPI
290 Single_IEnumMediaTypes_Reset(IEnumMediaTypes *iface)
291 {
292     ME_Impl *This = (ME_Impl *)iface;
293     TRACE("(%p)->()\n", This);
294     This->past = FALSE;
295     return S_OK;
296 }
297
298 /* IEnumMediaTypes */
299 static HRESULT WINAPI
300 Single_IEnumMediaTypes_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **me)
301 {
302     ME_Impl *This = (ME_Impl *)iface;
303     TRACE("(%p)->(%p)\n", This, me);
304     if (!me)
305         return E_POINTER;
306     *me = mediaenum_create(&This->mtype);
307     if (!*me)
308         return E_OUTOFMEMORY;
309     ((ME_Impl *)*me)->past = This->past;
310     return S_OK;
311 }
312
313
314 /* Virtual tables and constructor */
315
316 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable =
317 {
318     Single_IEnumMediaTypes_QueryInterface,
319     Single_IEnumMediaTypes_AddRef,
320     Single_IEnumMediaTypes_Release,
321     Single_IEnumMediaTypes_Next,
322     Single_IEnumMediaTypes_Skip,
323     Single_IEnumMediaTypes_Reset,
324     Single_IEnumMediaTypes_Clone,
325 };
326
327 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype)
328 {
329     ME_Impl *obj = CoTaskMemAlloc(sizeof(ME_Impl));
330     if (obj) {
331         ZeroMemory(obj, sizeof(ME_Impl));
332         obj->me.lpVtbl = &IEnumMediaTypes_VTable;
333         obj->refCount = 1;
334         obj->past = FALSE;
335         if (mtype) {
336             obj->mtype = *mtype;
337             obj->mtype.pUnk = NULL;
338             if (mtype->cbFormat) {
339                 obj->mtype.pbFormat = CoTaskMemAlloc(mtype->cbFormat);
340                 CopyMemory(obj->mtype.pbFormat, mtype->pbFormat, mtype->cbFormat);
341             }
342             else
343                 obj->mtype.pbFormat = NULL;
344         }
345         else
346             obj->mtype.majortype = GUID_NULL;
347     }
348     return &obj->me;
349 }
350
351
352 /* Sample Grabber pin implementation */
353 typedef struct _SG_Pin {
354     IPin IPin_iface;
355     PIN_DIRECTION dir;
356     WCHAR const *name;
357     struct _SG_Impl *sg;
358     IPin *pair;
359 } SG_Pin;
360
361 static inline SG_Pin *impl_from_IPin(IPin *iface)
362 {
363     return CONTAINING_RECORD(iface, SG_Pin, IPin_iface);
364 }
365
366 /* Sample Grabber filter implementation */
367 typedef struct _SG_Impl {
368     IUnknown IUnknown_inner;
369     IBaseFilter IBaseFilter_iface;
370     ISampleGrabber ISampleGrabber_iface;
371     IMemInputPin IMemInputPin_iface;
372     /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
373     IUnknown* seekthru_unk;
374     /* TODO: IQualityControl */
375     IUnknown *outer_unk;
376     LONG ref;
377     CRITICAL_SECTION critSect;
378     FILTER_INFO info;
379     FILTER_STATE state;
380     AM_MEDIA_TYPE mtype;
381     SG_Pin pin_in;
382     SG_Pin pin_out;
383     IMemAllocator *allocator;
384     IReferenceClock *refClock;
385     IMemInputPin *memOutput;
386     ISampleGrabberCB *grabberIface;
387     LONG grabberMethod;
388     LONG oneShot;
389     LONG bufferLen;
390     void* bufferData;
391 } SG_Impl;
392
393 enum {
394     OneShot_None,
395     OneShot_Wait,
396     OneShot_Past,
397 };
398
399 static inline SG_Impl *impl_from_IUnknown(IUnknown *iface)
400 {
401     return CONTAINING_RECORD(iface, SG_Impl, IUnknown_inner);
402 }
403
404 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
405 {
406     return CONTAINING_RECORD(iface, SG_Impl, IBaseFilter_iface);
407 }
408
409 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
410 {
411     return CONTAINING_RECORD(iface, SG_Impl, ISampleGrabber_iface);
412 }
413
414 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface)
415 {
416     return CONTAINING_RECORD(iface, SG_Impl, IMemInputPin_iface);
417 }
418
419
420 /* Cleanup at end of life */
421 static void SampleGrabber_cleanup(SG_Impl *This)
422 {
423     TRACE("(%p)\n", This);
424     if (This->info.pGraph)
425         WARN("(%p) still joined to filter graph %p\n", This, This->info.pGraph);
426     if (This->allocator)
427         IMemAllocator_Release(This->allocator);
428     if (This->refClock)
429         IReferenceClock_Release(This->refClock);
430     if (This->memOutput)
431         IMemInputPin_Release(This->memOutput);
432     if (This->grabberIface)
433         ISampleGrabberCB_Release(This->grabberIface);
434     if (This->mtype.pbFormat)
435         CoTaskMemFree(This->mtype.pbFormat);
436     if (This->bufferData)
437         CoTaskMemFree(This->bufferData);
438     if(This->seekthru_unk)
439         IUnknown_Release(This->seekthru_unk);
440     This->critSect.DebugInfo->Spare[0] = 0;
441     DeleteCriticalSection(&This->critSect);
442 }
443
444 /* SampleGrabber inner IUnknown */
445 static HRESULT WINAPI SampleGrabber_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
446 {
447     SG_Impl *This = impl_from_IUnknown(iface);
448
449     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
450
451     *ppv = NULL;
452     if (IsEqualIID(riid, &IID_IUnknown))
453         *ppv = &This->IUnknown_inner;
454     else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IMediaFilter) ||
455         IsEqualIID(riid, &IID_IBaseFilter))
456         *ppv = &This->IBaseFilter_iface;
457     else if (IsEqualIID(riid, &IID_ISampleGrabber))
458         *ppv = &This->ISampleGrabber_iface;
459     else if (IsEqualIID(riid, &IID_IMemInputPin))
460         *ppv = &This->IMemInputPin_iface;
461     else if (IsEqualIID(riid, &IID_IMediaPosition))
462         return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
463     else if (IsEqualIID(riid, &IID_IMediaSeeking))
464         return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
465     else if (IsEqualIID(riid, &IID_IQualityControl))
466         FIXME("IQualityControl not implemented\n");
467     else
468         WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
469
470     if (!*ppv)
471         return E_NOINTERFACE;
472
473     IUnknown_AddRef((IUnknown*)*ppv);
474     return S_OK;
475 }
476
477 static ULONG WINAPI SampleGrabber_AddRef(IUnknown *iface)
478 {
479     SG_Impl *This = impl_from_IUnknown(iface);
480     ULONG ref = InterlockedIncrement(&This->ref);
481
482     TRACE("(%p) new ref = %u\n", This, ref);
483
484     return ref;
485 }
486
487 static ULONG WINAPI SampleGrabber_Release(IUnknown *iface)
488 {
489     SG_Impl *This = impl_from_IUnknown(iface);
490     ULONG ref = InterlockedDecrement(&This->ref);
491
492     TRACE("(%p) new ref = %u\n", This, ref);
493
494     if (ref == 0)
495     {
496         SampleGrabber_cleanup(This);
497         CoTaskMemFree(This);
498         return 0;
499     }
500     return ref;
501 }
502
503 static const IUnknownVtbl samplegrabber_vtbl =
504 {
505     SampleGrabber_QueryInterface,
506     SampleGrabber_AddRef,
507     SampleGrabber_Release,
508 };
509
510 /* Helper that buffers data and/or calls installed sample callbacks */
511 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
512 {
513     double time = 0.0;
514     REFERENCE_TIME tStart, tEnd;
515     if (This->bufferLen >= 0) {
516         BYTE *data = 0;
517         LONG size = IMediaSample_GetActualDataLength(sample);
518         if (size >= 0 && SUCCEEDED(IMediaSample_GetPointer(sample, &data))) {
519             if (!data)
520                 size = 0;
521             EnterCriticalSection(&This->critSect);
522             if (This->bufferLen != size) {
523                 if (This->bufferData)
524                     CoTaskMemFree(This->bufferData);
525                 This->bufferData = size ? CoTaskMemAlloc(size) : NULL;
526                 This->bufferLen = size;
527             }
528             if (size)
529                 CopyMemory(This->bufferData, data, size);
530             LeaveCriticalSection(&This->critSect);
531         }
532     }
533     if (!This->grabberIface)
534         return;
535     if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
536         time = 1e-7 * tStart;
537     switch (This->grabberMethod) {
538         case 0:
539             {
540                 ULONG ref = IMediaSample_AddRef(sample);
541                 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
542                 ref = IMediaSample_Release(sample) + 1 - ref;
543                 if (ref)
544                 {
545                     ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref);
546                     /* ugly as hell but some apps are sooo buggy */
547                     while (ref--)
548                         IMediaSample_Release(sample);
549                 }
550             }
551             break;
552         case 1:
553             {
554                 BYTE *data = 0;
555                 LONG size = IMediaSample_GetActualDataLength(sample);
556                 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
557                     ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
558             }
559             break;
560         case -1:
561             break;
562         default:
563             FIXME("unsupported method %d\n", This->grabberMethod);
564             /* do not bother us again */
565             This->grabberMethod = -1;
566     }
567 }
568
569
570 /* SampleGrabber implementation of IBaseFilter interface */
571
572 /* IUnknown */
573 static HRESULT WINAPI
574 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)
575 {
576     SG_Impl *This = impl_from_IBaseFilter(iface);
577     return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
578 }
579
580 /* IUnknown */
581 static ULONG WINAPI
582 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
583 {
584     SG_Impl *This = impl_from_IBaseFilter(iface);
585     return IUnknown_AddRef(This->outer_unk);
586 }
587
588 /* IUnknown */
589 static ULONG WINAPI
590 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
591 {
592     SG_Impl *This = impl_from_IBaseFilter(iface);
593     return IUnknown_Release(This->outer_unk);
594 }
595
596 /* IPersist */
597 static HRESULT WINAPI
598 SampleGrabber_IBaseFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID)
599 {
600     TRACE("(%p)\n", pClassID);
601     if (!pClassID)
602         return E_POINTER;
603     *pClassID = CLSID_SampleGrabber;
604     return S_OK;
605 }
606
607 /* IMediaFilter */
608 static HRESULT WINAPI
609 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
610 {
611     SG_Impl *This = impl_from_IBaseFilter(iface);
612     TRACE("(%p)\n", This);
613     This->state = State_Stopped;
614     return S_OK;
615 }
616
617 /* IMediaFilter */
618 static HRESULT WINAPI
619 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
620 {
621     SG_Impl *This = impl_from_IBaseFilter(iface);
622     TRACE("(%p)\n", This);
623     This->state = State_Paused;
624     return S_OK;
625 }
626
627 /* IMediaFilter */
628 static HRESULT WINAPI
629 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
630 {
631     SG_Impl *This = impl_from_IBaseFilter(iface);
632     TRACE("(%p)\n", This);
633     This->state = State_Running;
634     return S_OK;
635 }
636
637 /* IMediaFilter */
638 static HRESULT WINAPI
639 SampleGrabber_IBaseFilter_GetState(IBaseFilter *iface, DWORD msTout, FILTER_STATE *state)
640 {
641     SG_Impl *This = impl_from_IBaseFilter(iface);
642     TRACE("(%p)->(%u, %p)\n", This, msTout, state);
643     if (!state)
644         return E_POINTER;
645     *state = This->state;
646     return S_OK;
647 }
648
649 /* IMediaFilter */
650 static HRESULT WINAPI
651 SampleGrabber_IBaseFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
652 {
653     SG_Impl *This = impl_from_IBaseFilter(iface);
654     TRACE("(%p)->(%p)\n", This, clock);
655     if (clock != This->refClock)
656     {
657         if (clock)
658             IReferenceClock_AddRef(clock);
659         if (This->refClock)
660             IReferenceClock_Release(This->refClock);
661         This->refClock = clock;
662     }
663     return S_OK;
664 }
665
666 /* IMediaFilter */
667 static HRESULT WINAPI
668 SampleGrabber_IBaseFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock)
669 {
670     SG_Impl *This = impl_from_IBaseFilter(iface);
671     TRACE("(%p)->(%p)\n", This, clock);
672     if (!clock)
673         return E_POINTER;
674     if (This->refClock)
675         IReferenceClock_AddRef(This->refClock);
676     *clock = This->refClock;
677     return S_OK;
678 }
679
680 /* IBaseFilter */
681 static HRESULT WINAPI
682 SampleGrabber_IBaseFilter_EnumPins(IBaseFilter *iface, IEnumPins **pins)
683 {
684     SG_Impl *This = impl_from_IBaseFilter(iface);
685     IPin *pin[2];
686     TRACE("(%p)->(%p)\n", This, pins);
687     if (!pins)
688         return E_POINTER;
689     pin[0] = &This->pin_in.IPin_iface;
690     pin[1] = &This->pin_out.IPin_iface;
691     *pins = pinsenum_create(iface, pin, 2);
692     return *pins ? S_OK : E_OUTOFMEMORY;
693 }
694
695 /* IBaseFilter */
696 static HRESULT WINAPI
697 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
698 {
699     SG_Impl *This = impl_from_IBaseFilter(iface);
700     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin);
701     if (!id || !pin)
702         return E_POINTER;
703     if (!lstrcmpiW(id,pin_in_name))
704     {
705         *pin = &This->pin_in.IPin_iface;
706         IPin_AddRef(*pin);
707         return S_OK;
708     }
709     else if (!lstrcmpiW(id,pin_out_name))
710     {
711         *pin = &This->pin_out.IPin_iface;
712         IPin_AddRef(*pin);
713         return S_OK;
714     }
715     *pin = NULL;
716     return VFW_E_NOT_FOUND;
717 }
718
719 /* IBaseFilter */
720 static HRESULT WINAPI
721 SampleGrabber_IBaseFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info)
722 {
723     SG_Impl *This = impl_from_IBaseFilter(iface);
724     TRACE("(%p)->(%p)\n", This, info);
725     if (!info)
726         return E_POINTER;
727     if (This->info.pGraph)
728         IFilterGraph_AddRef(This->info.pGraph);
729     *info = This->info;
730     return S_OK;
731 }
732
733 /* IBaseFilter */
734 static HRESULT WINAPI
735 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
736 {
737     SG_Impl *This = impl_from_IBaseFilter(iface);
738     TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
739     This->info.pGraph = graph;
740     if (name)
741         lstrcpynW(This->info.achName,name,MAX_FILTER_NAME);
742     This->oneShot = OneShot_None;
743     return S_OK;
744 }
745
746 /* IBaseFilter */
747 static HRESULT WINAPI
748 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
749 {
750     TRACE("(%p)\n", vendor);
751     if (!vendor)
752         return E_POINTER;
753     *vendor = CoTaskMemAlloc(sizeof(vendor_name));
754     CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
755     return S_OK;
756 }
757
758
759 /* SampleGrabber implementation of ISampleGrabber interface */
760
761 /* IUnknown */
762 static HRESULT WINAPI
763 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv)
764 {
765     SG_Impl *This = impl_from_ISampleGrabber(iface);
766     return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
767 }
768
769 /* IUnknown */
770 static ULONG WINAPI
771 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
772 {
773     SG_Impl *This = impl_from_ISampleGrabber(iface);
774     return IUnknown_AddRef(This->outer_unk);
775 }
776
777 /* IUnknown */
778 static ULONG WINAPI
779 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
780 {
781     SG_Impl *This = impl_from_ISampleGrabber(iface);
782     return IUnknown_Release(This->outer_unk);
783 }
784
785 /* ISampleGrabber */
786 static HRESULT WINAPI
787 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
788 {
789     SG_Impl *This = impl_from_ISampleGrabber(iface);
790     TRACE("(%p)->(%u)\n", This, oneShot);
791     This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
792     return S_OK;
793 }
794
795 /* ISampleGrabber */
796 static HRESULT WINAPI
797 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
798 {
799     SG_Impl *This = impl_from_ISampleGrabber(iface);
800     TRACE("(%p)->(%p)\n", This, type);
801     if (!type)
802         return E_POINTER;
803     TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
804         debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
805         type->lSampleSize,
806         debugstr_guid(&type->formattype), type->cbFormat);
807     if (This->mtype.pbFormat)
808         CoTaskMemFree(This->mtype.pbFormat);
809     This->mtype = *type;
810     This->mtype.pUnk = NULL;
811     if (type->cbFormat) {
812         This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
813         CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat);
814     }
815     else
816         This->mtype.pbFormat = NULL;
817     return S_OK;
818 }
819
820 /* ISampleGrabber */
821 static HRESULT WINAPI
822 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
823 {
824     SG_Impl *This = impl_from_ISampleGrabber(iface);
825     TRACE("(%p)->(%p)\n", This, type);
826     if (!type)
827         return E_POINTER;
828     if (!This->pin_in.pair)
829         return VFW_E_NOT_CONNECTED;
830     *type = This->mtype;
831     if (type->cbFormat) {
832         type->pbFormat = CoTaskMemAlloc(type->cbFormat);
833         CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat);
834     }
835     return S_OK;
836 }
837
838 /* ISampleGrabber */
839 static HRESULT WINAPI
840 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
841 {
842     SG_Impl *This = impl_from_ISampleGrabber(iface);
843     TRACE("(%p)->(%u)\n", This, bufferEm);
844     EnterCriticalSection(&This->critSect);
845     if (bufferEm) {
846         if (This->bufferLen < 0)
847             This->bufferLen = 0;
848     }
849     else
850         This->bufferLen = -1;
851     LeaveCriticalSection(&This->critSect);
852     return S_OK;
853 }
854
855 /* ISampleGrabber */
856 static HRESULT WINAPI
857 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
858 {
859     SG_Impl *This = impl_from_ISampleGrabber(iface);
860     HRESULT ret = S_OK;
861     TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer);
862     if (!bufSize)
863         return E_POINTER;
864     EnterCriticalSection(&This->critSect);
865     if (!This->pin_in.pair)
866         ret = VFW_E_NOT_CONNECTED;
867     else if (This->bufferLen < 0)
868         ret = E_INVALIDARG;
869     else if (This->bufferLen == 0)
870         ret = VFW_E_WRONG_STATE;
871     else {
872         if (buffer) {
873             if (*bufSize >= This->bufferLen)
874                 CopyMemory(buffer, This->bufferData, This->bufferLen);
875             else
876                 ret = E_OUTOFMEMORY;
877         }
878         *bufSize = This->bufferLen;
879     }
880     LeaveCriticalSection(&This->critSect);
881     return ret;
882 }
883
884 /* ISampleGrabber */
885 static HRESULT WINAPI
886 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
887 {
888     /* MS doesn't implement it either, no one should call it */
889     WARN("(%p): not implemented\n", sample);
890     return E_NOTIMPL;
891 }
892
893 /* ISampleGrabber */
894 static HRESULT WINAPI
895 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
896 {
897     SG_Impl *This = impl_from_ISampleGrabber(iface);
898     TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
899     if (This->grabberIface)
900         ISampleGrabberCB_Release(This->grabberIface);
901     This->grabberIface = cb;
902     This->grabberMethod = whichMethod;
903     if (cb)
904         ISampleGrabberCB_AddRef(cb);
905     return S_OK;
906 }
907
908
909 /* SampleGrabber implementation of IMemInputPin interface */
910
911 /* IUnknown */
912 static HRESULT WINAPI
913 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv)
914 {
915     SG_Impl *This = impl_from_IMemInputPin(iface);
916     return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
917 }
918
919 /* IUnknown */
920 static ULONG WINAPI
921 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
922 {
923     SG_Impl *This = impl_from_IMemInputPin(iface);
924     return IUnknown_AddRef(This->outer_unk);
925 }
926
927 /* IUnknown */
928 static ULONG WINAPI
929 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
930 {
931     SG_Impl *This = impl_from_IMemInputPin(iface);
932     return IUnknown_Release(This->outer_unk);
933 }
934
935 /* IMemInputPin */
936 static HRESULT WINAPI
937 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
938 {
939     SG_Impl *This = impl_from_IMemInputPin(iface);
940     TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
941     if (!allocator)
942         return E_POINTER;
943     *allocator = This->allocator;
944     if (!*allocator)
945         return VFW_E_NO_ALLOCATOR;
946     IMemAllocator_AddRef(*allocator);
947     return S_OK;
948 }
949
950 /* IMemInputPin */
951 static HRESULT WINAPI
952 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
953 {
954     SG_Impl *This = impl_from_IMemInputPin(iface);
955     TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
956     if (This->allocator == allocator)
957         return S_OK;
958     if (This->allocator)
959         IMemAllocator_Release(This->allocator);
960     This->allocator = allocator;
961     if (allocator)
962         IMemAllocator_AddRef(allocator);
963     return S_OK;
964 }
965
966 /* IMemInputPin */
967 static HRESULT WINAPI
968 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
969 {
970     SG_Impl *This = impl_from_IMemInputPin(iface);
971     FIXME("(%p)->(%p): semi-stub\n", This, props);
972     if (!props)
973         return E_POINTER;
974     return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL;
975 }
976
977 /* IMemInputPin */
978 static HRESULT WINAPI
979 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
980 {
981     SG_Impl *This = impl_from_IMemInputPin(iface);
982     HRESULT hr;
983     TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface);
984     if (!sample)
985         return E_POINTER;
986     if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
987         return S_FALSE;
988     SampleGrabber_callback(This, sample);
989     hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK;
990     if (This->oneShot == OneShot_Wait) {
991         This->oneShot = OneShot_Past;
992         hr = S_FALSE;
993         if (This->pin_out.pair)
994             IPin_EndOfStream(This->pin_out.pair);
995     }
996     return hr;
997 }
998
999 /* IMemInputPin */
1000 static HRESULT WINAPI
1001 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
1002 {
1003     SG_Impl *This = impl_from_IMemInputPin(iface);
1004     LONG idx;
1005     TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface);
1006     if (!samples || !nProcessed)
1007         return E_POINTER;
1008     if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
1009         return S_FALSE;
1010     for (idx = 0; idx < nSamples; idx++)
1011         SampleGrabber_callback(This, samples[idx]);
1012     return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK;
1013 }
1014
1015 /* IMemInputPin */
1016 static HRESULT WINAPI
1017 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
1018 {
1019     SG_Impl *This = impl_from_IMemInputPin(iface);
1020     TRACE("(%p)\n", This);
1021     return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK;
1022 }
1023
1024
1025 /* SampleGrabber member pin implementation */
1026
1027 /* IUnknown */
1028 static ULONG WINAPI
1029 SampleGrabber_IPin_AddRef(IPin *iface)
1030 {
1031     SG_Pin *This = impl_from_IPin(iface);
1032     return ISampleGrabber_AddRef(&This->sg->ISampleGrabber_iface);
1033 }
1034
1035 /* IUnknown */
1036 static ULONG WINAPI
1037 SampleGrabber_IPin_Release(IPin *iface)
1038 {
1039     SG_Pin *This = impl_from_IPin(iface);
1040     return ISampleGrabber_Release(&This->sg->ISampleGrabber_iface);
1041 }
1042
1043 /* IUnknown */
1044 static HRESULT WINAPI
1045 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
1046 {
1047     SG_Pin *This = impl_from_IPin(iface);
1048     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1049
1050     *ppv = NULL;
1051     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
1052         *ppv = iface;
1053     else if (IsEqualIID(riid, &IID_IMemInputPin))
1054         *ppv = &This->sg->IMemInputPin_iface;
1055     else if (IsEqualIID(riid, &IID_IMediaSeeking))
1056         return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
1057     else if (IsEqualIID(riid, &IID_IMediaPosition))
1058         return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
1059     else {
1060         WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
1061         return E_NOINTERFACE;
1062     }
1063
1064     IUnknown_AddRef((IUnknown*)*ppv);
1065     return S_OK;
1066 }
1067
1068 /* IPin - input pin */
1069 static HRESULT WINAPI
1070 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype)
1071 {
1072     WARN("(%p, %p): unexpected\n", receiver, mtype);
1073     return E_UNEXPECTED;
1074 }
1075
1076 /* IPin - output pin */
1077 static HRESULT WINAPI
1078 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type)
1079 {
1080     SG_Pin *This = impl_from_IPin(iface);
1081     HRESULT hr;
1082
1083     TRACE("(%p)->(%p, %p)\n", This, receiver, type);
1084     if (!receiver)
1085         return E_POINTER;
1086     if (This->pair)
1087         return VFW_E_ALREADY_CONNECTED;
1088     if (This->sg->state != State_Stopped)
1089         return VFW_E_NOT_STOPPED;
1090     if (type) {
1091         TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1092             debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1093             type->lSampleSize,
1094             debugstr_guid(&type->formattype), type->cbFormat);
1095         if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1096             !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1097             return VFW_E_TYPE_NOT_ACCEPTED;
1098         if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1099             !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1100             return VFW_E_TYPE_NOT_ACCEPTED;
1101         if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1102             !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1103             !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1104             return VFW_E_TYPE_NOT_ACCEPTED;
1105     }
1106     else
1107         type = &This->sg->mtype;
1108     if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
1109         !IsEqualGUID(&type->formattype, &GUID_NULL) &&
1110         !type->pbFormat)
1111         return VFW_E_TYPE_NOT_ACCEPTED;
1112     hr = IPin_ReceiveConnection(receiver, &This->IPin_iface, type);
1113     if (FAILED(hr))
1114         return hr;
1115     This->pair = receiver;
1116     if (This->sg->memOutput) {
1117         IMemInputPin_Release(This->sg->memOutput);
1118         This->sg->memOutput = NULL;
1119     }
1120     IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput));
1121     TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput);
1122     return S_OK;
1123 }
1124
1125 /* IPin - input pin */
1126 static HRESULT WINAPI
1127 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type)
1128 {
1129     SG_Pin *This = impl_from_IPin(iface);
1130
1131     TRACE("(%p)->(%p, %p)\n", This, connector, type);
1132     if (!connector)
1133         return E_POINTER;
1134     if (This->pair)
1135         return VFW_E_ALREADY_CONNECTED;
1136     if (This->sg->state != State_Stopped)
1137         return VFW_E_NOT_STOPPED;
1138     if (type) {
1139         TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1140             debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1141             type->lSampleSize,
1142             debugstr_guid(&type->formattype), type->cbFormat);
1143         if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
1144             !IsEqualGUID(&type->formattype, &GUID_NULL) &&
1145             !type->pbFormat)
1146             return VFW_E_INVALIDMEDIATYPE;
1147         if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1148             !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1149             return VFW_E_TYPE_NOT_ACCEPTED;
1150         if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1151             !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1152             return VFW_E_TYPE_NOT_ACCEPTED;
1153         if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1154             !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1155             !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1156             return VFW_E_TYPE_NOT_ACCEPTED;
1157         if (This->sg->mtype.pbFormat)
1158             CoTaskMemFree(This->sg->mtype.pbFormat);
1159         This->sg->mtype = *type;
1160         This->sg->mtype.pUnk = NULL;
1161         if (type->cbFormat) {
1162             This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
1163             CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat);
1164         }
1165         else
1166             This->sg->mtype.pbFormat = NULL;
1167     }
1168     This->pair = connector;
1169     TRACE("(%p) Accepted IPin %p\n", This, connector);
1170     return S_OK;
1171 }
1172
1173 /* IPin - output pin */
1174 static HRESULT WINAPI
1175 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype)
1176 {
1177     WARN("(%p, %p): unexpected\n", connector, mtype);
1178     return E_UNEXPECTED;
1179 }
1180
1181 /* IPin - input pin */
1182 static HRESULT WINAPI
1183 SampleGrabber_In_IPin_Disconnect(IPin *iface)
1184 {
1185     SG_Pin *This = impl_from_IPin(iface);
1186
1187     TRACE("(%p)->() pair = %p\n", This, This->pair);
1188     if (This->sg->state != State_Stopped)
1189         return VFW_E_NOT_STOPPED;
1190     if (This->pair) {
1191         This->pair = NULL;
1192         return S_OK;
1193     }
1194     return S_FALSE;
1195 }
1196
1197 /* IPin - output pin */
1198 static HRESULT WINAPI
1199 SampleGrabber_Out_IPin_Disconnect(IPin *iface)
1200 {
1201     SG_Pin *This = impl_from_IPin(iface);
1202
1203     TRACE("(%p)->() pair = %p\n", This, This->pair);
1204     if (This->sg->state != State_Stopped)
1205         return VFW_E_NOT_STOPPED;
1206     if (This->pair) {
1207         This->pair = NULL;
1208         if (This->sg->memOutput) {
1209             IMemInputPin_Release(This->sg->memOutput);
1210             This->sg->memOutput = NULL;
1211         }
1212         return S_OK;
1213     }
1214     return S_FALSE;
1215 }
1216
1217 /* IPin */
1218 static HRESULT WINAPI
1219 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin)
1220 {
1221     SG_Pin *This = impl_from_IPin(iface);
1222
1223     TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair);
1224     if (!pin)
1225         return E_POINTER;
1226     *pin = This->pair;
1227     if (*pin) {
1228         IPin_AddRef(*pin);
1229         return S_OK;
1230     }
1231     return VFW_E_NOT_CONNECTED;
1232 }
1233
1234 /* IPin */
1235 static HRESULT WINAPI
1236 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype)
1237 {
1238     SG_Pin *This = impl_from_IPin(iface);
1239
1240     TRACE("(%p)->(%p)\n", This, mtype);
1241     if (!mtype)
1242         return E_POINTER;
1243     if (!This->pair)
1244         return VFW_E_NOT_CONNECTED;
1245     *mtype = This->sg->mtype;
1246     if (mtype->cbFormat) {
1247         mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
1248         CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat);
1249     }
1250     return S_OK;
1251 }
1252
1253 /* IPin */
1254 static HRESULT WINAPI
1255 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info)
1256 {
1257     SG_Pin *This = impl_from_IPin(iface);
1258
1259     TRACE("(%p)->(%p)\n", This, info);
1260     if (!info)
1261         return E_POINTER;
1262     IBaseFilter_AddRef(&This->sg->IBaseFilter_iface);
1263     info->pFilter = &This->sg->IBaseFilter_iface;
1264     info->dir = This->dir;
1265     lstrcpynW(info->achName,This->name,MAX_PIN_NAME);
1266     return S_OK;
1267 }
1268
1269 /* IPin */
1270 static HRESULT WINAPI
1271 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1272 {
1273     SG_Pin *This = impl_from_IPin(iface);
1274
1275     TRACE("(%p)->(%p)\n", This, dir);
1276     if (!dir)
1277         return E_POINTER;
1278     *dir = This->dir;
1279     return S_OK;
1280 }
1281
1282 /* IPin */
1283 static HRESULT WINAPI
1284 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id)
1285 {
1286     SG_Pin *This = impl_from_IPin(iface);
1287
1288     int len;
1289     TRACE("(%p)->(%p)\n", This, id);
1290     if (!id)
1291         return E_POINTER;
1292     len = sizeof(WCHAR)*(1+lstrlenW(This->name));
1293     *id = CoTaskMemAlloc(len);
1294     CopyMemory(*id, This->name, len);
1295     return S_OK;
1296 }
1297
1298 /* IPin */
1299 static HRESULT WINAPI
1300 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype)
1301 {
1302     TRACE("(%p)\n", mtype);
1303     return S_OK;
1304 }
1305
1306 /* IPin */
1307 static HRESULT WINAPI
1308 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes)
1309 {
1310     SG_Pin *This = impl_from_IPin(iface);
1311
1312     TRACE("(%p)->(%p)\n", This, mtypes);
1313     if (!mtypes)
1314         return E_POINTER;
1315     *mtypes = mediaenum_create(This->sg->pin_in.pair ? &This->sg->mtype : NULL);
1316     return *mtypes ? S_OK : E_OUTOFMEMORY;
1317 }
1318
1319 /* IPin - input pin */
1320 static HRESULT WINAPI
1321 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1322 {
1323     SG_Pin *This = impl_from_IPin(iface);
1324
1325     TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0));
1326     if (!nPins)
1327         return E_POINTER;
1328     if (*nPins) {
1329         if (!pins)
1330             return E_POINTER;
1331         IPin_AddRef(&This->sg->pin_out.IPin_iface);
1332         *pins = &This->sg->pin_out.IPin_iface;
1333         *nPins = 1;
1334         return S_OK;
1335     }
1336     *nPins = 1;
1337     return S_FALSE;
1338 }
1339
1340 /* IPin - output pin */
1341 static HRESULT WINAPI
1342 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1343 {
1344     WARN("(%p, %p): unexpected\n", pins, nPins);
1345     if (nPins)
1346         *nPins = 0;
1347     return E_NOTIMPL;
1348 }
1349
1350 /* IPin */
1351 static HRESULT WINAPI
1352 SampleGrabber_IPin_EndOfStream(IPin *iface)
1353 {
1354     FIXME(": stub\n");
1355     return S_OK;
1356 }
1357
1358 /* IPin */
1359 static HRESULT WINAPI
1360 SampleGrabber_IPin_BeginFlush(IPin *iface)
1361 {
1362     FIXME(": stub\n");
1363     return S_OK;
1364 }
1365
1366 /* IPin */
1367 static HRESULT WINAPI
1368 SampleGrabber_IPin_EndFlush(IPin *iface)
1369 {
1370     FIXME(": stub\n");
1371     return S_OK;
1372 }
1373
1374 /* IPin */
1375 static HRESULT WINAPI
1376 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate)
1377 {
1378     FIXME(": stub\n");
1379     return S_OK;
1380 }
1381
1382
1383 /* SampleGrabber vtables and constructor */
1384
1385 static const IBaseFilterVtbl IBaseFilter_VTable =
1386 {
1387     SampleGrabber_IBaseFilter_QueryInterface,
1388     SampleGrabber_IBaseFilter_AddRef,
1389     SampleGrabber_IBaseFilter_Release,
1390     SampleGrabber_IBaseFilter_GetClassID,
1391     SampleGrabber_IBaseFilter_Stop,
1392     SampleGrabber_IBaseFilter_Pause,
1393     SampleGrabber_IBaseFilter_Run,
1394     SampleGrabber_IBaseFilter_GetState,
1395     SampleGrabber_IBaseFilter_SetSyncSource,
1396     SampleGrabber_IBaseFilter_GetSyncSource,
1397     SampleGrabber_IBaseFilter_EnumPins,
1398     SampleGrabber_IBaseFilter_FindPin,
1399     SampleGrabber_IBaseFilter_QueryFilterInfo,
1400     SampleGrabber_IBaseFilter_JoinFilterGraph,
1401     SampleGrabber_IBaseFilter_QueryVendorInfo,
1402 };
1403
1404 static const ISampleGrabberVtbl ISampleGrabber_VTable =
1405 {
1406     SampleGrabber_ISampleGrabber_QueryInterface,
1407     SampleGrabber_ISampleGrabber_AddRef,
1408     SampleGrabber_ISampleGrabber_Release,
1409     SampleGrabber_ISampleGrabber_SetOneShot,
1410     SampleGrabber_ISampleGrabber_SetMediaType,
1411     SampleGrabber_ISampleGrabber_GetConnectedMediaType,
1412     SampleGrabber_ISampleGrabber_SetBufferSamples,
1413     SampleGrabber_ISampleGrabber_GetCurrentBuffer,
1414     SampleGrabber_ISampleGrabber_GetCurrentSample,
1415     SampleGrabber_ISampleGrabber_SetCallback,
1416 };
1417
1418 static const IMemInputPinVtbl IMemInputPin_VTable =
1419 {
1420     SampleGrabber_IMemInputPin_QueryInterface,
1421     SampleGrabber_IMemInputPin_AddRef,
1422     SampleGrabber_IMemInputPin_Release,
1423     SampleGrabber_IMemInputPin_GetAllocator,
1424     SampleGrabber_IMemInputPin_NotifyAllocator,
1425     SampleGrabber_IMemInputPin_GetAllocatorRequirements,
1426     SampleGrabber_IMemInputPin_Receive,
1427     SampleGrabber_IMemInputPin_ReceiveMultiple,
1428     SampleGrabber_IMemInputPin_ReceiveCanBlock,
1429 };
1430
1431 static const IPinVtbl IPin_In_VTable =
1432 {
1433     SampleGrabber_IPin_QueryInterface,
1434     SampleGrabber_IPin_AddRef,
1435     SampleGrabber_IPin_Release,
1436     SampleGrabber_In_IPin_Connect,
1437     SampleGrabber_In_IPin_ReceiveConnection,
1438     SampleGrabber_In_IPin_Disconnect,
1439     SampleGrabber_IPin_ConnectedTo,
1440     SampleGrabber_IPin_ConnectionMediaType,
1441     SampleGrabber_IPin_QueryPinInfo,
1442     SampleGrabber_IPin_QueryDirection,
1443     SampleGrabber_IPin_QueryId,
1444     SampleGrabber_IPin_QueryAccept,
1445     SampleGrabber_IPin_EnumMediaTypes,
1446     SampleGrabber_In_IPin_QueryInternalConnections,
1447     SampleGrabber_IPin_EndOfStream,
1448     SampleGrabber_IPin_BeginFlush,
1449     SampleGrabber_IPin_EndFlush,
1450     SampleGrabber_IPin_NewSegment,
1451 };
1452
1453 static const IPinVtbl IPin_Out_VTable =
1454 {
1455     SampleGrabber_IPin_QueryInterface,
1456     SampleGrabber_IPin_AddRef,
1457     SampleGrabber_IPin_Release,
1458     SampleGrabber_Out_IPin_Connect,
1459     SampleGrabber_Out_IPin_ReceiveConnection,
1460     SampleGrabber_Out_IPin_Disconnect,
1461     SampleGrabber_IPin_ConnectedTo,
1462     SampleGrabber_IPin_ConnectionMediaType,
1463     SampleGrabber_IPin_QueryPinInfo,
1464     SampleGrabber_IPin_QueryDirection,
1465     SampleGrabber_IPin_QueryId,
1466     SampleGrabber_IPin_QueryAccept,
1467     SampleGrabber_IPin_EnumMediaTypes,
1468     SampleGrabber_Out_IPin_QueryInternalConnections,
1469     SampleGrabber_IPin_EndOfStream,
1470     SampleGrabber_IPin_BeginFlush,
1471     SampleGrabber_IPin_EndFlush,
1472     SampleGrabber_IPin_NewSegment,
1473 };
1474
1475 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
1476 {
1477     SG_Impl* obj = NULL;
1478     ISeekingPassThru *passthru;
1479     HRESULT hr;
1480
1481     TRACE("(%p,%p)\n", ppv, pUnkOuter);
1482
1483     obj = CoTaskMemAlloc(sizeof(SG_Impl));
1484     if (NULL == obj) {
1485         *ppv = NULL;
1486         return E_OUTOFMEMORY;
1487     }
1488     ZeroMemory(obj, sizeof(SG_Impl));
1489
1490     obj->ref = 1;
1491     obj->IUnknown_inner.lpVtbl = &samplegrabber_vtbl;
1492     obj->IBaseFilter_iface.lpVtbl = &IBaseFilter_VTable;
1493     obj->ISampleGrabber_iface.lpVtbl = &ISampleGrabber_VTable;
1494     obj->IMemInputPin_iface.lpVtbl = &IMemInputPin_VTable;
1495     obj->pin_in.IPin_iface.lpVtbl = &IPin_In_VTable;
1496     obj->pin_in.dir = PINDIR_INPUT;
1497     obj->pin_in.name = pin_in_name;
1498     obj->pin_in.sg = obj;
1499     obj->pin_in.pair = NULL;
1500     obj->pin_out.IPin_iface.lpVtbl = &IPin_Out_VTable;
1501     obj->pin_out.dir = PINDIR_OUTPUT;
1502     obj->pin_out.name = pin_out_name;
1503     obj->pin_out.sg = obj;
1504     obj->pin_out.pair = NULL;
1505     InitializeCriticalSection(&obj->critSect);
1506     obj->critSect.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SG_Impl.critSect");
1507     obj->info.achName[0] = 0;
1508     obj->info.pGraph = NULL;
1509     obj->state = State_Stopped;
1510     obj->mtype.majortype = GUID_NULL;
1511     obj->mtype.subtype = MEDIASUBTYPE_None;
1512     obj->mtype.formattype = FORMAT_None;
1513     obj->allocator = NULL;
1514     obj->refClock = NULL;
1515     obj->memOutput = NULL;
1516     obj->grabberIface = NULL;
1517     obj->grabberMethod = -1;
1518     obj->oneShot = OneShot_None;
1519     obj->bufferLen = -1;
1520     obj->bufferData = NULL;
1521
1522     if (pUnkOuter)
1523         obj->outer_unk = pUnkOuter;
1524     else
1525         obj->outer_unk = &obj->IUnknown_inner;
1526
1527     hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)obj, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&obj->seekthru_unk);
1528     if(hr)
1529         return hr;
1530     IUnknown_QueryInterface(obj->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
1531     ISeekingPassThru_Init(passthru, FALSE, &obj->pin_in.IPin_iface);
1532     ISeekingPassThru_Release(passthru);
1533
1534     *ppv = &obj->IUnknown_inner;
1535     return S_OK;
1536 }