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