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