dxdiagn: Mark internal symbols with hidden visibility.
[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 WCHAR const vendor_name[] = { 'W', 'i', 'n', 'e', 0 };
36 static WCHAR const pin_in_name[] = { 'I', 'n', 0 };
37 static WCHAR const 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     const IPinVtbl* lpVtbl;
355     PIN_DIRECTION dir;
356     WCHAR const *name;
357     struct _SG_Impl *sg;
358     IPin *pair;
359 } SG_Pin;
360
361 /* Sample Grabber filter implementation */
362 typedef struct _SG_Impl {
363     const IBaseFilterVtbl* IBaseFilter_Vtbl;
364     const ISampleGrabberVtbl* ISampleGrabber_Vtbl;
365     const IMemInputPinVtbl* IMemInputPin_Vtbl;
366     /* TODO: IMediaPosition, IMediaSeeking, IQualityControl */
367     LONG refCount;
368     CRITICAL_SECTION critSect;
369     FILTER_INFO info;
370     FILTER_STATE state;
371     AM_MEDIA_TYPE mtype;
372     SG_Pin pin_in;
373     SG_Pin pin_out;
374     IMemAllocator *allocator;
375     IReferenceClock *refClock;
376     IMemInputPin *memOutput;
377     ISampleGrabberCB *grabberIface;
378     LONG grabberMethod;
379     LONG oneShot;
380     LONG bufferLen;
381     void* bufferData;
382 } SG_Impl;
383
384 enum {
385     OneShot_None,
386     OneShot_Wait,
387     OneShot_Past,
388 };
389
390 /* Get the SampleGrabber implementation This pointer from various interface pointers */
391 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
392 {
393     return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, IBaseFilter_Vtbl));
394 }
395
396 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
397 {
398     return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, ISampleGrabber_Vtbl));
399 }
400
401 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface)
402 {
403     return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, IMemInputPin_Vtbl));
404 }
405
406
407 /* Cleanup at end of life */
408 static void SampleGrabber_cleanup(SG_Impl *This)
409 {
410     TRACE("(%p)\n", This);
411     if (This->info.pGraph)
412         WARN("(%p) still joined to filter graph %p\n", This, This->info.pGraph);
413     if (This->allocator)
414         IMemAllocator_Release(This->allocator);
415     if (This->refClock)
416         IReferenceClock_Release(This->refClock);
417     if (This->memOutput)
418         IMemInputPin_Release(This->memOutput);
419     if (This->grabberIface)
420         ISampleGrabberCB_Release(This->grabberIface);
421     if (This->mtype.pbFormat)
422         CoTaskMemFree(This->mtype.pbFormat);
423     if (This->bufferData)
424         CoTaskMemFree(This->bufferData);
425     This->critSect.DebugInfo->Spare[0] = 0;
426     DeleteCriticalSection(&This->critSect);
427 }
428
429 /* Common helper AddRef called from all interfaces */
430 static ULONG SampleGrabber_addref(SG_Impl *This)
431 {
432     ULONG refCount = InterlockedIncrement(&This->refCount);
433     TRACE("(%p) new ref = %u\n", This, refCount);
434     return refCount;
435 }
436
437 /* Common helper Release called from all interfaces */
438 static ULONG SampleGrabber_release(SG_Impl *This)
439 {
440     ULONG refCount = InterlockedDecrement(&This->refCount);
441     TRACE("(%p) new ref = %u\n", This, refCount);
442     if (refCount == 0)
443     {
444         SampleGrabber_cleanup(This);
445         CoTaskMemFree(This);
446         return 0;
447     }
448     return refCount;
449 }
450
451 /* Common helper QueryInterface called from all interfaces */
452 static HRESULT SampleGrabber_query(SG_Impl *This, REFIID riid, void **ppvObject)
453 {
454     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
455
456     if (IsEqualIID(riid, &IID_IUnknown) ||
457         IsEqualIID(riid, &IID_IPersist) ||
458         IsEqualIID(riid, &IID_IMediaFilter) ||
459         IsEqualIID(riid, &IID_IBaseFilter)) {
460         SampleGrabber_addref(This);
461         *ppvObject = &(This->IBaseFilter_Vtbl);
462         return S_OK;
463     }
464     else if (IsEqualIID(riid, &IID_ISampleGrabber)) {
465         SampleGrabber_addref(This);
466         *ppvObject = &(This->ISampleGrabber_Vtbl);
467         return S_OK;
468     }
469     else if (IsEqualIID(riid, &IID_IMemInputPin)) {
470         SampleGrabber_addref(This);
471         *ppvObject = &(This->IMemInputPin_Vtbl);
472         return S_OK;
473     }
474     else if (IsEqualIID(riid, &IID_IMediaPosition))
475         FIXME("IMediaPosition not implemented\n");
476     else if (IsEqualIID(riid, &IID_IMediaSeeking))
477         FIXME("IMediaSeeking not implemented\n");
478     else if (IsEqualIID(riid, &IID_IQualityControl))
479         FIXME("IQualityControl not implemented\n");
480     *ppvObject = NULL;
481     WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
482     return E_NOINTERFACE;
483 }
484
485 /* Helper that buffers data and/or calls installed sample callbacks */
486 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
487 {
488     double time = 0.0;
489     REFERENCE_TIME tStart, tEnd;
490     if (This->bufferLen >= 0) {
491         BYTE *data = 0;
492         LONG size = IMediaSample_GetActualDataLength(sample);
493         if (size >= 0 && SUCCEEDED(IMediaSample_GetPointer(sample, &data))) {
494             if (!data)
495                 size = 0;
496             EnterCriticalSection(&This->critSect);
497             if (This->bufferLen != size) {
498                 if (This->bufferData)
499                     CoTaskMemFree(This->bufferData);
500                 This->bufferData = size ? CoTaskMemAlloc(size) : NULL;
501                 This->bufferLen = size;
502             }
503             if (size)
504                 CopyMemory(This->bufferData, data, size);
505             LeaveCriticalSection(&This->critSect);
506         }
507     }
508     if (!This->grabberIface)
509         return;
510     if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
511         time = 1e-7 * tStart;
512     switch (This->grabberMethod) {
513         case 0:
514             {
515                 ULONG ref = IMediaSample_AddRef(sample);
516                 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
517                 ref = IMediaSample_Release(sample) + 1 - ref;
518                 if (ref)
519                 {
520                     ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref);
521                     /* ugly as hell but some apps are sooo buggy */
522                     while (ref--)
523                         IMediaSample_Release(sample);
524                 }
525             }
526             break;
527         case 1:
528             {
529                 BYTE *data = 0;
530                 LONG size = IMediaSample_GetActualDataLength(sample);
531                 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
532                     ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
533             }
534             break;
535         case -1:
536             break;
537         default:
538             FIXME("unsupported method %d\n", This->grabberMethod);
539             /* do not bother us again */
540             This->grabberMethod = -1;
541     }
542 }
543
544
545 /* SampleGrabber implementation of IBaseFilter interface */
546
547 /* IUnknown */
548 static HRESULT WINAPI
549 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppvObject)
550 {
551     return SampleGrabber_query(impl_from_IBaseFilter(iface), riid, ppvObject);
552 }
553
554 /* IUnknown */
555 static ULONG WINAPI
556 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
557 {
558     return SampleGrabber_addref(impl_from_IBaseFilter(iface));
559 }
560
561 /* IUnknown */
562 static ULONG WINAPI
563 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
564 {
565     return SampleGrabber_release(impl_from_IBaseFilter(iface));
566 }
567
568 /* IPersist */
569 static HRESULT WINAPI
570 SampleGrabber_IBaseFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID)
571 {
572     TRACE("(%p)\n", pClassID);
573     if (!pClassID)
574         return E_POINTER;
575     *pClassID = CLSID_SampleGrabber;
576     return S_OK;
577 }
578
579 /* IMediaFilter */
580 static HRESULT WINAPI
581 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
582 {
583     SG_Impl *This = impl_from_IBaseFilter(iface);
584     TRACE("(%p)\n", This);
585     This->state = State_Stopped;
586     return S_OK;
587 }
588
589 /* IMediaFilter */
590 static HRESULT WINAPI
591 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
592 {
593     SG_Impl *This = impl_from_IBaseFilter(iface);
594     TRACE("(%p)\n", This);
595     This->state = State_Paused;
596     return S_OK;
597 }
598
599 /* IMediaFilter */
600 static HRESULT WINAPI
601 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
602 {
603     SG_Impl *This = impl_from_IBaseFilter(iface);
604     TRACE("(%p)\n", This);
605     This->state = State_Running;
606     return S_OK;
607 }
608
609 /* IMediaFilter */
610 static HRESULT WINAPI
611 SampleGrabber_IBaseFilter_GetState(IBaseFilter *iface, DWORD msTout, FILTER_STATE *state)
612 {
613     SG_Impl *This = impl_from_IBaseFilter(iface);
614     TRACE("(%p)->(%u, %p)\n", This, msTout, state);
615     if (!state)
616         return E_POINTER;
617     *state = This->state;
618     return S_OK;
619 }
620
621 /* IMediaFilter */
622 static HRESULT WINAPI
623 SampleGrabber_IBaseFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
624 {
625     SG_Impl *This = impl_from_IBaseFilter(iface);
626     TRACE("(%p)->(%p)\n", This, clock);
627     if (clock != This->refClock)
628     {
629         if (clock)
630             IReferenceClock_AddRef(clock);
631         if (This->refClock)
632             IReferenceClock_Release(This->refClock);
633         This->refClock = clock;
634     }
635     return S_OK;
636 }
637
638 /* IMediaFilter */
639 static HRESULT WINAPI
640 SampleGrabber_IBaseFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock)
641 {
642     SG_Impl *This = impl_from_IBaseFilter(iface);
643     TRACE("(%p)->(%p)\n", This, clock);
644     if (!clock)
645         return E_POINTER;
646     if (This->refClock)
647         IReferenceClock_AddRef(This->refClock);
648     *clock = This->refClock;
649     return S_OK;
650 }
651
652 /* IBaseFilter */
653 static HRESULT WINAPI
654 SampleGrabber_IBaseFilter_EnumPins(IBaseFilter *iface, IEnumPins **pins)
655 {
656     SG_Impl *This = impl_from_IBaseFilter(iface);
657     IPin *pin[2];
658     TRACE("(%p)->(%p)\n", This, pins);
659     if (!pins)
660         return E_POINTER;
661     pin[0] = (IPin*)&This->pin_in.lpVtbl;
662     pin[1] = (IPin*)&This->pin_out.lpVtbl;
663     *pins = pinsenum_create(iface, pin, 2);
664     return *pins ? S_OK : E_OUTOFMEMORY;
665 }
666
667 /* IBaseFilter */
668 static HRESULT WINAPI
669 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
670 {
671     SG_Impl *This = impl_from_IBaseFilter(iface);
672     TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin);
673     if (!id || !pin)
674         return E_POINTER;
675     if (!lstrcmpiW(id,pin_in_name))
676     {
677         SampleGrabber_addref(This);
678         *pin = (IPin*)&(This->pin_in.lpVtbl);
679         return S_OK;
680     }
681     else if (!lstrcmpiW(id,pin_out_name))
682     {
683         SampleGrabber_addref(This);
684         *pin = (IPin*)&(This->pin_out.lpVtbl);
685         return S_OK;
686     }
687     *pin = NULL;
688     return VFW_E_NOT_FOUND;
689 }
690
691 /* IBaseFilter */
692 static HRESULT WINAPI
693 SampleGrabber_IBaseFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info)
694 {
695     SG_Impl *This = impl_from_IBaseFilter(iface);
696     TRACE("(%p)->(%p)\n", This, info);
697     if (!info)
698         return E_POINTER;
699     if (This->info.pGraph)
700         IFilterGraph_AddRef(This->info.pGraph);
701     *info = This->info;
702     return S_OK;
703 }
704
705 /* IBaseFilter */
706 static HRESULT WINAPI
707 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
708 {
709     SG_Impl *This = impl_from_IBaseFilter(iface);
710     TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
711     This->info.pGraph = graph;
712     if (name)
713         lstrcpynW(This->info.achName,name,MAX_FILTER_NAME);
714     This->oneShot = OneShot_None;
715     return S_OK;
716 }
717
718 /* IBaseFilter */
719 static HRESULT WINAPI
720 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
721 {
722     TRACE("(%p)\n", vendor);
723     if (!vendor)
724         return E_POINTER;
725     *vendor = CoTaskMemAlloc(sizeof(vendor_name));
726     CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
727     return S_OK;
728 }
729
730
731 /* SampleGrabber implementation of ISampleGrabber interface */
732
733 /* IUnknown */
734 static HRESULT WINAPI
735 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppvObject)
736 {
737     return SampleGrabber_query(impl_from_ISampleGrabber(iface), riid, ppvObject);
738 }
739
740 /* IUnknown */
741 static ULONG WINAPI
742 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
743 {
744     return SampleGrabber_addref(impl_from_ISampleGrabber(iface));
745 }
746
747 /* IUnknown */
748 static ULONG WINAPI
749 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
750 {
751     return SampleGrabber_release(impl_from_ISampleGrabber(iface));
752 }
753
754 /* ISampleGrabber */
755 static HRESULT WINAPI
756 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
757 {
758     SG_Impl *This = impl_from_ISampleGrabber(iface);
759     TRACE("(%p)->(%u)\n", This, oneShot);
760     This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
761     return S_OK;
762 }
763
764 /* ISampleGrabber */
765 static HRESULT WINAPI
766 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
767 {
768     SG_Impl *This = impl_from_ISampleGrabber(iface);
769     TRACE("(%p)->(%p)\n", This, type);
770     if (!type)
771         return E_POINTER;
772     TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
773         debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
774         type->lSampleSize,
775         debugstr_guid(&type->formattype), type->cbFormat);
776     if (This->mtype.pbFormat)
777         CoTaskMemFree(This->mtype.pbFormat);
778     This->mtype = *type;
779     This->mtype.pUnk = NULL;
780     if (type->cbFormat) {
781         This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
782         CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat);
783     }
784     else
785         This->mtype.pbFormat = NULL;
786     return S_OK;
787 }
788
789 /* ISampleGrabber */
790 static HRESULT WINAPI
791 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
792 {
793     SG_Impl *This = impl_from_ISampleGrabber(iface);
794     TRACE("(%p)->(%p)\n", This, type);
795     if (!type)
796         return E_POINTER;
797     if (!This->pin_in.pair)
798         return VFW_E_NOT_CONNECTED;
799     *type = This->mtype;
800     if (type->cbFormat) {
801         type->pbFormat = CoTaskMemAlloc(type->cbFormat);
802         CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat);
803     }
804     return S_OK;
805 }
806
807 /* ISampleGrabber */
808 static HRESULT WINAPI
809 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
810 {
811     SG_Impl *This = impl_from_ISampleGrabber(iface);
812     TRACE("(%p)->(%u)\n", This, bufferEm);
813     EnterCriticalSection(&This->critSect);
814     if (bufferEm) {
815         if (This->bufferLen < 0)
816             This->bufferLen = 0;
817     }
818     else
819         This->bufferLen = -1;
820     LeaveCriticalSection(&This->critSect);
821     return S_OK;
822 }
823
824 /* ISampleGrabber */
825 static HRESULT WINAPI
826 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
827 {
828     SG_Impl *This = impl_from_ISampleGrabber(iface);
829     HRESULT ret = S_OK;
830     TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer);
831     if (!bufSize)
832         return E_POINTER;
833     EnterCriticalSection(&This->critSect);
834     if (!This->pin_in.pair)
835         ret = VFW_E_NOT_CONNECTED;
836     else if (This->bufferLen < 0)
837         ret = E_INVALIDARG;
838     else if (This->bufferLen == 0)
839         ret = VFW_E_WRONG_STATE;
840     else {
841         if (buffer) {
842             if (*bufSize >= This->bufferLen)
843                 CopyMemory(buffer, This->bufferData, This->bufferLen);
844             else
845                 ret = E_OUTOFMEMORY;
846         }
847         *bufSize = This->bufferLen;
848     }
849     LeaveCriticalSection(&This->critSect);
850     return ret;
851 }
852
853 /* ISampleGrabber */
854 static HRESULT WINAPI
855 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
856 {
857     /* MS doesn't implement it either, no one should call it */
858     WARN("(%p): not implemented\n", sample);
859     return E_NOTIMPL;
860 }
861
862 /* ISampleGrabber */
863 static HRESULT WINAPI
864 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
865 {
866     SG_Impl *This = impl_from_ISampleGrabber(iface);
867     TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
868     if (This->grabberIface)
869         ISampleGrabberCB_Release(This->grabberIface);
870     This->grabberIface = cb;
871     This->grabberMethod = whichMethod;
872     if (cb)
873         ISampleGrabberCB_AddRef(cb);
874     return S_OK;
875 }
876
877
878 /* SampleGrabber implementation of IMemInputPin interface */
879
880 /* IUnknown */
881 static HRESULT WINAPI
882 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppvObject)
883 {
884     return SampleGrabber_query(impl_from_IMemInputPin(iface), riid, ppvObject);
885 }
886
887 /* IUnknown */
888 static ULONG WINAPI
889 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
890 {
891     return SampleGrabber_addref(impl_from_IMemInputPin(iface));
892 }
893
894 /* IUnknown */
895 static ULONG WINAPI
896 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
897 {
898     return SampleGrabber_release(impl_from_IMemInputPin(iface));
899 }
900
901 /* IMemInputPin */
902 static HRESULT WINAPI
903 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
904 {
905     SG_Impl *This = impl_from_IMemInputPin(iface);
906     TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
907     if (!allocator)
908         return E_POINTER;
909     *allocator = This->allocator;
910     if (!*allocator)
911         return VFW_E_NO_ALLOCATOR;
912     IMemAllocator_AddRef(*allocator);
913     return S_OK;
914 }
915
916 /* IMemInputPin */
917 static HRESULT WINAPI
918 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
919 {
920     SG_Impl *This = impl_from_IMemInputPin(iface);
921     TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
922     if (This->allocator == allocator)
923         return S_OK;
924     if (This->allocator)
925         IMemAllocator_Release(This->allocator);
926     This->allocator = allocator;
927     if (allocator)
928         IMemAllocator_AddRef(allocator);
929     return S_OK;
930 }
931
932 /* IMemInputPin */
933 static HRESULT WINAPI
934 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
935 {
936     SG_Impl *This = impl_from_IMemInputPin(iface);
937     FIXME("(%p)->(%p): semi-stub\n", This, props);
938     if (!props)
939         return E_POINTER;
940     return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL;
941 }
942
943 /* IMemInputPin */
944 static HRESULT WINAPI
945 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
946 {
947     SG_Impl *This = impl_from_IMemInputPin(iface);
948     HRESULT hr;
949     TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface);
950     if (!sample)
951         return E_POINTER;
952     if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
953         return S_FALSE;
954     SampleGrabber_callback(This, sample);
955     hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK;
956     if (This->oneShot == OneShot_Wait) {
957         This->oneShot = OneShot_Past;
958         hr = S_FALSE;
959         if (This->pin_out.pair)
960             IPin_EndOfStream(This->pin_out.pair);
961     }
962     return hr;
963 }
964
965 /* IMemInputPin */
966 static HRESULT WINAPI
967 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
968 {
969     SG_Impl *This = impl_from_IMemInputPin(iface);
970     LONG idx;
971     TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface);
972     if (!samples || !nProcessed)
973         return E_POINTER;
974     if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
975         return S_FALSE;
976     for (idx = 0; idx < nSamples; idx++)
977         SampleGrabber_callback(This, samples[idx]);
978     return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK;
979 }
980
981 /* IMemInputPin */
982 static HRESULT WINAPI
983 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
984 {
985     SG_Impl *This = impl_from_IMemInputPin(iface);
986     TRACE("(%p)\n", This);
987     return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK;
988 }
989
990
991 /* SampleGrabber member pin implementation */
992
993 /* IUnknown */
994 static ULONG WINAPI
995 SampleGrabber_IPin_AddRef(IPin *iface)
996 {
997     return SampleGrabber_addref(((SG_Pin *)iface)->sg);
998 }
999
1000 /* IUnknown */
1001 static ULONG WINAPI
1002 SampleGrabber_IPin_Release(IPin *iface)
1003 {
1004     return SampleGrabber_release(((SG_Pin *)iface)->sg);
1005 }
1006
1007 /* IUnknown */
1008 static HRESULT WINAPI
1009 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppvObject)
1010 {
1011     SG_Pin *This = (SG_Pin *)iface;
1012     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
1013
1014     if (IsEqualIID(riid, &IID_IUnknown) ||
1015         IsEqualIID(riid, &IID_IPin)) {
1016         SampleGrabber_addref(This->sg);
1017         *ppvObject = This;
1018         return S_OK;
1019     }
1020     else if (IsEqualIID(riid, &IID_IMemInputPin)) {
1021         SampleGrabber_addref(This->sg);
1022         *ppvObject = &(This->sg->IMemInputPin_Vtbl);
1023         return S_OK;
1024     }
1025     *ppvObject = NULL;
1026     WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
1027     return E_NOINTERFACE;
1028 }
1029
1030 /* IPin - input pin */
1031 static HRESULT WINAPI
1032 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype)
1033 {
1034     WARN("(%p, %p): unexpected\n", receiver, mtype);
1035     return E_UNEXPECTED;
1036 }
1037
1038 /* IPin - output pin */
1039 static HRESULT WINAPI
1040 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type)
1041 {
1042     SG_Pin *This = (SG_Pin *)iface;
1043     HRESULT hr;
1044     TRACE("(%p)->(%p, %p)\n", This, receiver, type);
1045     if (!receiver)
1046         return E_POINTER;
1047     if (This->pair)
1048         return VFW_E_ALREADY_CONNECTED;
1049     if (This->sg->state != State_Stopped)
1050         return VFW_E_NOT_STOPPED;
1051     if (type) {
1052         TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1053             debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1054             type->lSampleSize,
1055             debugstr_guid(&type->formattype), type->cbFormat);
1056         if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1057             !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1058             return VFW_E_TYPE_NOT_ACCEPTED;
1059         if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1060             !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1061             return VFW_E_TYPE_NOT_ACCEPTED;
1062         if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1063             !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1064             !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1065             return VFW_E_TYPE_NOT_ACCEPTED;
1066     }
1067     else
1068         type = &This->sg->mtype;
1069     if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
1070         !IsEqualGUID(&type->formattype, &GUID_NULL) &&
1071         !type->pbFormat)
1072         return VFW_E_TYPE_NOT_ACCEPTED;
1073     hr = IPin_ReceiveConnection(receiver,(IPin*)&This->lpVtbl,type);
1074     if (FAILED(hr))
1075         return hr;
1076     This->pair = receiver;
1077     if (This->sg->memOutput) {
1078         IMemInputPin_Release(This->sg->memOutput);
1079         This->sg->memOutput = NULL;
1080     }
1081     IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput));
1082     TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput);
1083     return S_OK;
1084 }
1085
1086 /* IPin - input pin */
1087 static HRESULT WINAPI
1088 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type)
1089 {
1090     SG_Pin *This = (SG_Pin *)iface;
1091     TRACE("(%p)->(%p, %p)\n", This, connector, type);
1092     if (!connector)
1093         return E_POINTER;
1094     if (This->pair)
1095         return VFW_E_ALREADY_CONNECTED;
1096     if (This->sg->state != State_Stopped)
1097         return VFW_E_NOT_STOPPED;
1098     if (type) {
1099         TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1100             debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1101             type->lSampleSize,
1102             debugstr_guid(&type->formattype), type->cbFormat);
1103         if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
1104             !IsEqualGUID(&type->formattype, &GUID_NULL) &&
1105             !type->pbFormat)
1106             return VFW_E_INVALIDMEDIATYPE;
1107         if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1108             !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1109             return VFW_E_TYPE_NOT_ACCEPTED;
1110         if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1111             !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1112             return VFW_E_TYPE_NOT_ACCEPTED;
1113         if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1114             !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1115             !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1116             return VFW_E_TYPE_NOT_ACCEPTED;
1117         if (This->sg->mtype.pbFormat)
1118             CoTaskMemFree(This->sg->mtype.pbFormat);
1119         This->sg->mtype = *type;
1120         This->sg->mtype.pUnk = NULL;
1121         if (type->cbFormat) {
1122             This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
1123             CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat);
1124         }
1125         else
1126             This->sg->mtype.pbFormat = NULL;
1127     }
1128     This->pair = connector;
1129     TRACE("(%p) Accepted IPin %p\n", This, connector);
1130     return S_OK;
1131 }
1132
1133 /* IPin - output pin */
1134 static HRESULT WINAPI
1135 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype)
1136 {
1137     WARN("(%p, %p): unexpected\n", connector, mtype);
1138     return E_UNEXPECTED;
1139 }
1140
1141 /* IPin - input pin */
1142 static HRESULT WINAPI
1143 SampleGrabber_In_IPin_Disconnect(IPin *iface)
1144 {
1145     SG_Pin *This = (SG_Pin *)iface;
1146     TRACE("(%p)->() pair = %p\n", This, This->pair);
1147     if (This->sg->state != State_Stopped)
1148         return VFW_E_NOT_STOPPED;
1149     if (This->pair) {
1150         This->pair = NULL;
1151         return S_OK;
1152     }
1153     return S_FALSE;
1154 }
1155
1156 /* IPin - output pin */
1157 static HRESULT WINAPI
1158 SampleGrabber_Out_IPin_Disconnect(IPin *iface)
1159 {
1160     SG_Pin *This = (SG_Pin *)iface;
1161     TRACE("(%p)->() pair = %p\n", This, This->pair);
1162     if (This->sg->state != State_Stopped)
1163         return VFW_E_NOT_STOPPED;
1164     if (This->pair) {
1165         This->pair = NULL;
1166         if (This->sg->memOutput) {
1167             IMemInputPin_Release(This->sg->memOutput);
1168             This->sg->memOutput = NULL;
1169         }
1170         return S_OK;
1171     }
1172     return S_FALSE;
1173 }
1174
1175 /* IPin */
1176 static HRESULT WINAPI
1177 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin)
1178 {
1179     SG_Pin *This = (SG_Pin *)iface;
1180     TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair);
1181     if (!pin)
1182         return E_POINTER;
1183     *pin = This->pair;
1184     if (*pin) {
1185         IPin_AddRef(*pin);
1186         return S_OK;
1187     }
1188     return VFW_E_NOT_CONNECTED;
1189 }
1190
1191 /* IPin */
1192 static HRESULT WINAPI
1193 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype)
1194 {
1195     SG_Pin *This = (SG_Pin *)iface;
1196     TRACE("(%p)->(%p)\n", This, mtype);
1197     if (!mtype)
1198         return E_POINTER;
1199     if (!This->pair)
1200         return VFW_E_NOT_CONNECTED;
1201     *mtype = This->sg->mtype;
1202     if (mtype->cbFormat) {
1203         mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
1204         CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat);
1205     }
1206     return S_OK;
1207 }
1208
1209 /* IPin */
1210 static HRESULT WINAPI
1211 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info)
1212 {
1213     SG_Pin *This = (SG_Pin *)iface;
1214     TRACE("(%p)->(%p)\n", This, info);
1215     if (!info)
1216         return E_POINTER;
1217     SampleGrabber_addref(This->sg);
1218     info->pFilter = (IBaseFilter *)This->sg;
1219     info->dir = This->dir;
1220     lstrcpynW(info->achName,This->name,MAX_PIN_NAME);
1221     return S_OK;
1222 }
1223
1224 /* IPin */
1225 static HRESULT WINAPI
1226 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1227 {
1228     SG_Pin *This = (SG_Pin *)iface;
1229     TRACE("(%p)->(%p)\n", This, dir);
1230     if (!dir)
1231         return E_POINTER;
1232     *dir = This->dir;
1233     return S_OK;
1234 }
1235
1236 /* IPin */
1237 static HRESULT WINAPI
1238 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id)
1239 {
1240     SG_Pin *This = (SG_Pin *)iface;
1241     int len;
1242     TRACE("(%p)->(%p)\n", This, id);
1243     if (!id)
1244         return E_POINTER;
1245     len = sizeof(WCHAR)*(1+lstrlenW(This->name));
1246     *id = CoTaskMemAlloc(len);
1247     CopyMemory(*id, This->name, len);
1248     return S_OK;
1249 }
1250
1251 /* IPin */
1252 static HRESULT WINAPI
1253 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype)
1254 {
1255     TRACE("(%p)\n", mtype);
1256     return S_OK;
1257 }
1258
1259 /* IPin */
1260 static HRESULT WINAPI
1261 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes)
1262 {
1263     SG_Pin *This = (SG_Pin *)iface;
1264     TRACE("(%p)->(%p)\n", This, mtypes);
1265     if (!mtypes)
1266         return E_POINTER;
1267     *mtypes = mediaenum_create(This->sg->pin_in.pair ? &This->sg->mtype : NULL);
1268     return *mtypes ? S_OK : E_OUTOFMEMORY;
1269 }
1270
1271 /* IPin - input pin */
1272 static HRESULT WINAPI
1273 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1274 {
1275     SG_Pin *This = (SG_Pin *)iface;
1276     TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0));
1277     if (!nPins)
1278         return E_POINTER;
1279     if (*nPins) {
1280         if (!pins)
1281             return E_POINTER;
1282         IPin_AddRef((IPin*)&This->sg->pin_out.lpVtbl);
1283         *pins = (IPin*)&This->sg->pin_out.lpVtbl;
1284         *nPins = 1;
1285         return S_OK;
1286     }
1287     *nPins = 1;
1288     return S_FALSE;
1289 }
1290
1291 /* IPin - output pin */
1292 static HRESULT WINAPI
1293 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1294 {
1295     WARN("(%p, %p): unexpected\n", pins, nPins);
1296     if (nPins)
1297         *nPins = 0;
1298     return E_NOTIMPL;
1299 }
1300
1301 /* IPin */
1302 static HRESULT WINAPI
1303 SampleGrabber_IPin_EndOfStream(IPin *iface)
1304 {
1305     FIXME(": stub\n");
1306     return S_OK;
1307 }
1308
1309 /* IPin */
1310 static HRESULT WINAPI
1311 SampleGrabber_IPin_BeginFlush(IPin *iface)
1312 {
1313     FIXME(": stub\n");
1314     return S_OK;
1315 }
1316
1317 /* IPin */
1318 static HRESULT WINAPI
1319 SampleGrabber_IPin_EndFlush(IPin *iface)
1320 {
1321     FIXME(": stub\n");
1322     return S_OK;
1323 }
1324
1325 /* IPin */
1326 static HRESULT WINAPI
1327 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate)
1328 {
1329     FIXME(": stub\n");
1330     return S_OK;
1331 }
1332
1333
1334 /* SampleGrabber vtables and constructor */
1335
1336 static const IBaseFilterVtbl IBaseFilter_VTable =
1337 {
1338     SampleGrabber_IBaseFilter_QueryInterface,
1339     SampleGrabber_IBaseFilter_AddRef,
1340     SampleGrabber_IBaseFilter_Release,
1341     SampleGrabber_IBaseFilter_GetClassID,
1342     SampleGrabber_IBaseFilter_Stop,
1343     SampleGrabber_IBaseFilter_Pause,
1344     SampleGrabber_IBaseFilter_Run,
1345     SampleGrabber_IBaseFilter_GetState,
1346     SampleGrabber_IBaseFilter_SetSyncSource,
1347     SampleGrabber_IBaseFilter_GetSyncSource,
1348     SampleGrabber_IBaseFilter_EnumPins,
1349     SampleGrabber_IBaseFilter_FindPin,
1350     SampleGrabber_IBaseFilter_QueryFilterInfo,
1351     SampleGrabber_IBaseFilter_JoinFilterGraph,
1352     SampleGrabber_IBaseFilter_QueryVendorInfo,
1353 };
1354
1355 static const ISampleGrabberVtbl ISampleGrabber_VTable =
1356 {
1357     SampleGrabber_ISampleGrabber_QueryInterface,
1358     SampleGrabber_ISampleGrabber_AddRef,
1359     SampleGrabber_ISampleGrabber_Release,
1360     SampleGrabber_ISampleGrabber_SetOneShot,
1361     SampleGrabber_ISampleGrabber_SetMediaType,
1362     SampleGrabber_ISampleGrabber_GetConnectedMediaType,
1363     SampleGrabber_ISampleGrabber_SetBufferSamples,
1364     SampleGrabber_ISampleGrabber_GetCurrentBuffer,
1365     SampleGrabber_ISampleGrabber_GetCurrentSample,
1366     SampleGrabber_ISampleGrabber_SetCallback,
1367 };
1368
1369 static const IMemInputPinVtbl IMemInputPin_VTable =
1370 {
1371     SampleGrabber_IMemInputPin_QueryInterface,
1372     SampleGrabber_IMemInputPin_AddRef,
1373     SampleGrabber_IMemInputPin_Release,
1374     SampleGrabber_IMemInputPin_GetAllocator,
1375     SampleGrabber_IMemInputPin_NotifyAllocator,
1376     SampleGrabber_IMemInputPin_GetAllocatorRequirements,
1377     SampleGrabber_IMemInputPin_Receive,
1378     SampleGrabber_IMemInputPin_ReceiveMultiple,
1379     SampleGrabber_IMemInputPin_ReceiveCanBlock,
1380 };
1381
1382 static const IPinVtbl IPin_In_VTable =
1383 {
1384     SampleGrabber_IPin_QueryInterface,
1385     SampleGrabber_IPin_AddRef,
1386     SampleGrabber_IPin_Release,
1387     SampleGrabber_In_IPin_Connect,
1388     SampleGrabber_In_IPin_ReceiveConnection,
1389     SampleGrabber_In_IPin_Disconnect,
1390     SampleGrabber_IPin_ConnectedTo,
1391     SampleGrabber_IPin_ConnectionMediaType,
1392     SampleGrabber_IPin_QueryPinInfo,
1393     SampleGrabber_IPin_QueryDirection,
1394     SampleGrabber_IPin_QueryId,
1395     SampleGrabber_IPin_QueryAccept,
1396     SampleGrabber_IPin_EnumMediaTypes,
1397     SampleGrabber_In_IPin_QueryInternalConnections,
1398     SampleGrabber_IPin_EndOfStream,
1399     SampleGrabber_IPin_BeginFlush,
1400     SampleGrabber_IPin_EndFlush,
1401     SampleGrabber_IPin_NewSegment,
1402 };
1403
1404 static const IPinVtbl IPin_Out_VTable =
1405 {
1406     SampleGrabber_IPin_QueryInterface,
1407     SampleGrabber_IPin_AddRef,
1408     SampleGrabber_IPin_Release,
1409     SampleGrabber_Out_IPin_Connect,
1410     SampleGrabber_Out_IPin_ReceiveConnection,
1411     SampleGrabber_Out_IPin_Disconnect,
1412     SampleGrabber_IPin_ConnectedTo,
1413     SampleGrabber_IPin_ConnectionMediaType,
1414     SampleGrabber_IPin_QueryPinInfo,
1415     SampleGrabber_IPin_QueryDirection,
1416     SampleGrabber_IPin_QueryId,
1417     SampleGrabber_IPin_QueryAccept,
1418     SampleGrabber_IPin_EnumMediaTypes,
1419     SampleGrabber_Out_IPin_QueryInternalConnections,
1420     SampleGrabber_IPin_EndOfStream,
1421     SampleGrabber_IPin_BeginFlush,
1422     SampleGrabber_IPin_EndFlush,
1423     SampleGrabber_IPin_NewSegment,
1424 };
1425
1426 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
1427 {
1428     SG_Impl* obj = NULL;
1429
1430     TRACE("(%p,%p)\n", ppv, pUnkOuter);
1431
1432     if (pUnkOuter)
1433         return CLASS_E_NOAGGREGATION;
1434
1435     obj = CoTaskMemAlloc(sizeof(SG_Impl));
1436     if (NULL == obj) {
1437         *ppv = NULL;
1438         return E_OUTOFMEMORY;
1439     }
1440     ZeroMemory(obj, sizeof(SG_Impl));
1441
1442     obj->refCount = 1;
1443     obj->IBaseFilter_Vtbl = &IBaseFilter_VTable;
1444     obj->ISampleGrabber_Vtbl = &ISampleGrabber_VTable;
1445     obj->IMemInputPin_Vtbl = &IMemInputPin_VTable;
1446     obj->pin_in.lpVtbl = &IPin_In_VTable;
1447     obj->pin_in.dir = PINDIR_INPUT;
1448     obj->pin_in.name = pin_in_name;
1449     obj->pin_in.sg = obj;
1450     obj->pin_in.pair = NULL;
1451     obj->pin_out.lpVtbl = &IPin_Out_VTable;
1452     obj->pin_out.dir = PINDIR_OUTPUT;
1453     obj->pin_out.name = pin_out_name;
1454     obj->pin_out.sg = obj;
1455     obj->pin_out.pair = NULL;
1456     InitializeCriticalSection(&obj->critSect);
1457     obj->critSect.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SG_Impl.critSect");
1458     obj->info.achName[0] = 0;
1459     obj->info.pGraph = NULL;
1460     obj->state = State_Stopped;
1461     obj->mtype.majortype = GUID_NULL;
1462     obj->mtype.subtype = MEDIASUBTYPE_None;
1463     obj->mtype.formattype = FORMAT_None;
1464     obj->allocator = NULL;
1465     obj->refClock = NULL;
1466     obj->memOutput = NULL;
1467     obj->grabberIface = NULL;
1468     obj->grabberMethod = -1;
1469     obj->oneShot = OneShot_None;
1470     obj->bufferLen = -1;
1471     obj->bufferData = NULL;
1472     *ppv = obj;
1473
1474     return S_OK;
1475 }