tools: Only allow the absolute difference in bracket pairs to be less than 128, since...
[wine/multimedia.git] / dlls / qedit / samplegrabber.c
blob537e22cfe7242cd4333d1072a8d0f526e33311d4
1 /* DirectShow Sample Grabber object (QEDIT.DLL)
3 * Copyright 2009 Paul Chitescu
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.
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.
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
20 #include <assert.h>
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
30 #include "qedit_private.h"
31 #include "wine/debug.h"
32 #include "wine/strmbase.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(qedit);
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 };
40 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype);
42 /* Single media type enumerator */
43 typedef struct _ME_Impl {
44 IEnumMediaTypes me;
45 LONG refCount;
46 BOOL past;
47 AM_MEDIA_TYPE mtype;
48 } ME_Impl;
51 /* IEnumMediaTypes interface implementation */
53 /* IUnknown */
54 static ULONG WINAPI
55 Single_IEnumMediaTypes_AddRef(IEnumMediaTypes *iface)
57 ME_Impl *This = (ME_Impl *)iface;
58 ULONG refCount = InterlockedIncrement(&This->refCount);
59 TRACE("(%p) new ref = %u\n", This, refCount);
60 return refCount;
63 /* IUnknown */
64 static ULONG WINAPI
65 Single_IEnumMediaTypes_Release(IEnumMediaTypes *iface)
67 ME_Impl *This = (ME_Impl *)iface;
68 ULONG refCount = InterlockedDecrement(&This->refCount);
69 TRACE("(%p) new ref = %u\n", This, refCount);
70 if (refCount == 0)
72 if (This->mtype.pbFormat)
73 CoTaskMemFree(This->mtype.pbFormat);
74 CoTaskMemFree(This);
75 return 0;
77 return refCount;
80 /* IUnknown */
81 static HRESULT WINAPI
82 Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes *iface, REFIID riid, void **ppvObject)
84 ME_Impl *This = (ME_Impl *)iface;
85 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
87 if (IsEqualIID(riid, &IID_IUnknown) ||
88 IsEqualIID(riid, &IID_IEnumMediaTypes)) {
89 Single_IEnumMediaTypes_AddRef(iface);
90 *ppvObject = &(This->me);
91 return S_OK;
93 *ppvObject = NULL;
94 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
95 return E_NOINTERFACE;
98 /* IEnumMediaTypes */
99 static HRESULT WINAPI
100 Single_IEnumMediaTypes_Next(IEnumMediaTypes *iface, ULONG nTypes, AM_MEDIA_TYPE **types, ULONG *fetched)
102 ME_Impl *This = (ME_Impl *)iface;
103 ULONG count = 0;
104 TRACE("(%p)->(%u, %p, %p)\n", This, nTypes, types, fetched);
105 if (!nTypes)
106 return E_INVALIDARG;
107 if (!types || ((nTypes != 1) && !fetched))
108 return E_POINTER;
109 if (!This->past && !IsEqualGUID(&This->mtype.majortype,&GUID_NULL)) {
110 AM_MEDIA_TYPE *mtype = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
111 *mtype = This->mtype;
112 if (mtype->cbFormat) {
113 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
114 CopyMemory(mtype->pbFormat, This->mtype.pbFormat, mtype->cbFormat);
116 *types = mtype;
117 This->past = TRUE;
118 count = 1;
120 if (fetched)
121 *fetched = count;
122 return (count == nTypes) ? S_OK : S_FALSE;
125 /* IEnumMediaTypes */
126 static HRESULT WINAPI
127 Single_IEnumMediaTypes_Skip(IEnumMediaTypes *iface, ULONG nTypes)
129 ME_Impl *This = (ME_Impl *)iface;
130 TRACE("(%p)->(%u)\n", This, nTypes);
131 if (nTypes)
132 This->past = TRUE;
133 return This->past ? S_FALSE : S_OK;
136 /* IEnumMediaTypes */
137 static HRESULT WINAPI
138 Single_IEnumMediaTypes_Reset(IEnumMediaTypes *iface)
140 ME_Impl *This = (ME_Impl *)iface;
141 TRACE("(%p)->()\n", This);
142 This->past = FALSE;
143 return S_OK;
146 /* IEnumMediaTypes */
147 static HRESULT WINAPI
148 Single_IEnumMediaTypes_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **me)
150 ME_Impl *This = (ME_Impl *)iface;
151 TRACE("(%p)->(%p)\n", This, me);
152 if (!me)
153 return E_POINTER;
154 *me = mediaenum_create(&This->mtype);
155 if (!*me)
156 return E_OUTOFMEMORY;
157 ((ME_Impl *)*me)->past = This->past;
158 return S_OK;
162 /* Virtual tables and constructor */
164 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable =
166 Single_IEnumMediaTypes_QueryInterface,
167 Single_IEnumMediaTypes_AddRef,
168 Single_IEnumMediaTypes_Release,
169 Single_IEnumMediaTypes_Next,
170 Single_IEnumMediaTypes_Skip,
171 Single_IEnumMediaTypes_Reset,
172 Single_IEnumMediaTypes_Clone,
175 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype)
177 ME_Impl *obj = CoTaskMemAlloc(sizeof(ME_Impl));
178 if (obj) {
179 ZeroMemory(obj, sizeof(ME_Impl));
180 obj->me.lpVtbl = &IEnumMediaTypes_VTable;
181 obj->refCount = 1;
182 obj->past = FALSE;
183 if (mtype) {
184 obj->mtype = *mtype;
185 obj->mtype.pUnk = NULL;
186 if (mtype->cbFormat) {
187 obj->mtype.pbFormat = CoTaskMemAlloc(mtype->cbFormat);
188 CopyMemory(obj->mtype.pbFormat, mtype->pbFormat, mtype->cbFormat);
190 else
191 obj->mtype.pbFormat = NULL;
193 else
194 obj->mtype.majortype = GUID_NULL;
196 return &obj->me;
200 /* Sample Grabber pin implementation */
201 typedef struct _SG_Pin {
202 IPin IPin_iface;
203 PIN_DIRECTION dir;
204 WCHAR const *name;
205 struct _SG_Impl *sg;
206 IPin *pair;
207 } SG_Pin;
209 static inline SG_Pin *impl_from_IPin(IPin *iface)
211 return CONTAINING_RECORD(iface, SG_Pin, IPin_iface);
214 /* Sample Grabber filter implementation */
215 typedef struct _SG_Impl {
216 IUnknown IUnknown_inner;
217 BaseFilter filter;
218 ISampleGrabber ISampleGrabber_iface;
219 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
220 IUnknown* seekthru_unk;
221 IUnknown *outer_unk;
222 AM_MEDIA_TYPE mtype;
223 SG_Pin pin_in;
224 SG_Pin pin_out;
225 IMemInputPin IMemInputPin_iface;
226 IMemAllocator *allocator;
227 IMemInputPin *memOutput;
228 ISampleGrabberCB *grabberIface;
229 LONG grabberMethod;
230 LONG oneShot;
231 LONG bufferLen;
232 void* bufferData;
233 } SG_Impl;
235 enum {
236 OneShot_None,
237 OneShot_Wait,
238 OneShot_Past,
241 static inline SG_Impl *impl_from_IUnknown(IUnknown *iface)
243 return CONTAINING_RECORD(iface, SG_Impl, IUnknown_inner);
246 static inline SG_Impl *impl_from_BaseFilter(BaseFilter *iface)
248 return CONTAINING_RECORD(iface, SG_Impl, filter);
251 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
253 return CONTAINING_RECORD(iface, SG_Impl, filter.IBaseFilter_iface);
256 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
258 return CONTAINING_RECORD(iface, SG_Impl, ISampleGrabber_iface);
261 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface)
263 return CONTAINING_RECORD(iface, SG_Impl, IMemInputPin_iface);
267 /* Cleanup at end of life */
268 static void SampleGrabber_cleanup(SG_Impl *This)
270 TRACE("(%p)\n", This);
271 if (This->filter.filterInfo.pGraph)
272 WARN("(%p) still joined to filter graph %p\n", This, This->filter.filterInfo.pGraph);
273 if (This->allocator)
274 IMemAllocator_Release(This->allocator);
275 if (This->memOutput)
276 IMemInputPin_Release(This->memOutput);
277 if (This->grabberIface)
278 ISampleGrabberCB_Release(This->grabberIface);
279 if (This->mtype.pbFormat)
280 CoTaskMemFree(This->mtype.pbFormat);
281 if (This->bufferData)
282 CoTaskMemFree(This->bufferData);
283 if(This->seekthru_unk)
284 IUnknown_Release(This->seekthru_unk);
287 /* SampleGrabber inner IUnknown */
288 static HRESULT WINAPI SampleGrabber_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
290 SG_Impl *This = impl_from_IUnknown(iface);
292 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
294 *ppv = NULL;
295 if (IsEqualIID(riid, &IID_IUnknown))
296 *ppv = &This->IUnknown_inner;
297 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IMediaFilter) ||
298 IsEqualIID(riid, &IID_IBaseFilter))
299 *ppv = &This->filter.IBaseFilter_iface;
300 else if (IsEqualIID(riid, &IID_ISampleGrabber))
301 *ppv = &This->ISampleGrabber_iface;
302 else if (IsEqualIID(riid, &IID_IMediaPosition))
303 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
304 else if (IsEqualIID(riid, &IID_IMediaSeeking))
305 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
306 else
307 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
309 if (!*ppv)
310 return E_NOINTERFACE;
312 IUnknown_AddRef((IUnknown*)*ppv);
313 return S_OK;
316 static ULONG WINAPI SampleGrabber_AddRef(IUnknown *iface)
318 SG_Impl *This = impl_from_IUnknown(iface);
319 ULONG ref = BaseFilterImpl_AddRef(&This->filter.IBaseFilter_iface);
321 TRACE("(%p) ref=%d\n", This, ref);
323 return ref;
326 static ULONG WINAPI SampleGrabber_Release(IUnknown *iface)
328 SG_Impl *This = impl_from_IUnknown(iface);
329 ULONG ref = BaseFilterImpl_Release(&This->filter.IBaseFilter_iface);
331 TRACE("(%p) ref=%d\n", This, ref);
333 if (ref == 0)
335 SampleGrabber_cleanup(This);
336 CoTaskMemFree(This);
337 return 0;
339 return ref;
342 static const IUnknownVtbl samplegrabber_vtbl =
344 SampleGrabber_QueryInterface,
345 SampleGrabber_AddRef,
346 SampleGrabber_Release,
349 static IPin *WINAPI SampleGrabber_GetPin(BaseFilter *iface, int pos)
351 SG_Impl *This = impl_from_BaseFilter(iface);
352 IPin *pin;
354 if (pos == 0)
355 pin = &This->pin_in.IPin_iface;
356 else if (pos == 1)
357 pin = &This->pin_out.IPin_iface;
358 else
359 return NULL;
361 IPin_AddRef(pin);
362 return pin;
365 static LONG WINAPI SampleGrabber_GetPinCount(BaseFilter *iface)
367 return 2;
370 static const BaseFilterFuncTable basefunc_vtbl = {
371 SampleGrabber_GetPin,
372 SampleGrabber_GetPinCount
375 /* Helper that buffers data and/or calls installed sample callbacks */
376 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
378 double time = 0.0;
379 REFERENCE_TIME tStart, tEnd;
380 if (This->bufferLen >= 0) {
381 BYTE *data = 0;
382 LONG size = IMediaSample_GetActualDataLength(sample);
383 if (size >= 0 && SUCCEEDED(IMediaSample_GetPointer(sample, &data))) {
384 if (!data)
385 size = 0;
386 EnterCriticalSection(&This->filter.csFilter);
387 if (This->bufferLen != size) {
388 if (This->bufferData)
389 CoTaskMemFree(This->bufferData);
390 This->bufferData = size ? CoTaskMemAlloc(size) : NULL;
391 This->bufferLen = size;
393 if (size)
394 CopyMemory(This->bufferData, data, size);
395 LeaveCriticalSection(&This->filter.csFilter);
398 if (!This->grabberIface)
399 return;
400 if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
401 time = 1e-7 * tStart;
402 switch (This->grabberMethod) {
403 case 0:
405 ULONG ref = IMediaSample_AddRef(sample);
406 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
407 ref = IMediaSample_Release(sample) + 1 - ref;
408 if (ref)
410 ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref);
411 /* ugly as hell but some apps are sooo buggy */
412 while (ref--)
413 IMediaSample_Release(sample);
416 break;
417 case 1:
419 BYTE *data = 0;
420 LONG size = IMediaSample_GetActualDataLength(sample);
421 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
422 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
424 break;
425 case -1:
426 break;
427 default:
428 FIXME("unsupported method %d\n", This->grabberMethod);
429 /* do not bother us again */
430 This->grabberMethod = -1;
435 /* SampleGrabber implementation of IBaseFilter interface */
437 /* IUnknown */
438 static HRESULT WINAPI
439 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)
441 SG_Impl *This = impl_from_IBaseFilter(iface);
442 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
445 /* IUnknown */
446 static ULONG WINAPI
447 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
449 SG_Impl *This = impl_from_IBaseFilter(iface);
450 return IUnknown_AddRef(This->outer_unk);
453 /* IUnknown */
454 static ULONG WINAPI
455 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
457 SG_Impl *This = impl_from_IBaseFilter(iface);
458 return IUnknown_Release(This->outer_unk);
461 /* IMediaFilter */
462 static HRESULT WINAPI
463 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
465 SG_Impl *This = impl_from_IBaseFilter(iface);
466 TRACE("(%p)\n", This);
467 This->filter.state = State_Stopped;
468 return S_OK;
471 /* IMediaFilter */
472 static HRESULT WINAPI
473 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
475 SG_Impl *This = impl_from_IBaseFilter(iface);
476 TRACE("(%p)\n", This);
477 This->filter.state = State_Paused;
478 return S_OK;
481 /* IMediaFilter */
482 static HRESULT WINAPI
483 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
485 SG_Impl *This = impl_from_IBaseFilter(iface);
486 TRACE("(%p)\n", This);
487 This->filter.state = State_Running;
488 return S_OK;
491 /* IBaseFilter */
492 static HRESULT WINAPI
493 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
495 SG_Impl *This = impl_from_IBaseFilter(iface);
496 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin);
497 if (!id || !pin)
498 return E_POINTER;
499 if (!lstrcmpiW(id,pin_in_name))
501 *pin = &This->pin_in.IPin_iface;
502 IPin_AddRef(*pin);
503 return S_OK;
505 else if (!lstrcmpiW(id,pin_out_name))
507 *pin = &This->pin_out.IPin_iface;
508 IPin_AddRef(*pin);
509 return S_OK;
511 *pin = NULL;
512 return VFW_E_NOT_FOUND;
515 /* IBaseFilter */
516 static HRESULT WINAPI
517 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
519 SG_Impl *This = impl_from_IBaseFilter(iface);
521 TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
523 BaseFilterImpl_JoinFilterGraph(iface, graph, name);
524 This->oneShot = OneShot_None;
526 return S_OK;
529 /* IBaseFilter */
530 static HRESULT WINAPI
531 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
533 TRACE("(%p)\n", vendor);
534 if (!vendor)
535 return E_POINTER;
536 *vendor = CoTaskMemAlloc(sizeof(vendor_name));
537 CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
538 return S_OK;
542 /* SampleGrabber implementation of ISampleGrabber interface */
544 /* IUnknown */
545 static HRESULT WINAPI
546 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv)
548 SG_Impl *This = impl_from_ISampleGrabber(iface);
549 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
552 /* IUnknown */
553 static ULONG WINAPI
554 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
556 SG_Impl *This = impl_from_ISampleGrabber(iface);
557 return IUnknown_AddRef(This->outer_unk);
560 /* IUnknown */
561 static ULONG WINAPI
562 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
564 SG_Impl *This = impl_from_ISampleGrabber(iface);
565 return IUnknown_Release(This->outer_unk);
568 /* ISampleGrabber */
569 static HRESULT WINAPI
570 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
572 SG_Impl *This = impl_from_ISampleGrabber(iface);
573 TRACE("(%p)->(%u)\n", This, oneShot);
574 This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
575 return S_OK;
578 /* ISampleGrabber */
579 static HRESULT WINAPI
580 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
582 SG_Impl *This = impl_from_ISampleGrabber(iface);
583 TRACE("(%p)->(%p)\n", This, type);
584 if (!type)
585 return E_POINTER;
586 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
587 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
588 type->lSampleSize,
589 debugstr_guid(&type->formattype), type->cbFormat);
590 if (This->mtype.pbFormat)
591 CoTaskMemFree(This->mtype.pbFormat);
592 This->mtype = *type;
593 This->mtype.pUnk = NULL;
594 if (type->cbFormat) {
595 This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
596 CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat);
598 else
599 This->mtype.pbFormat = NULL;
600 return S_OK;
603 /* ISampleGrabber */
604 static HRESULT WINAPI
605 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
607 SG_Impl *This = impl_from_ISampleGrabber(iface);
608 TRACE("(%p)->(%p)\n", This, type);
609 if (!type)
610 return E_POINTER;
611 if (!This->pin_in.pair)
612 return VFW_E_NOT_CONNECTED;
613 *type = This->mtype;
614 if (type->cbFormat) {
615 type->pbFormat = CoTaskMemAlloc(type->cbFormat);
616 CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat);
618 return S_OK;
621 /* ISampleGrabber */
622 static HRESULT WINAPI
623 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
625 SG_Impl *This = impl_from_ISampleGrabber(iface);
626 TRACE("(%p)->(%u)\n", This, bufferEm);
627 EnterCriticalSection(&This->filter.csFilter);
628 if (bufferEm) {
629 if (This->bufferLen < 0)
630 This->bufferLen = 0;
632 else
633 This->bufferLen = -1;
634 LeaveCriticalSection(&This->filter.csFilter);
635 return S_OK;
638 /* ISampleGrabber */
639 static HRESULT WINAPI
640 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
642 SG_Impl *This = impl_from_ISampleGrabber(iface);
643 HRESULT ret = S_OK;
644 TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer);
645 if (!bufSize)
646 return E_POINTER;
647 EnterCriticalSection(&This->filter.csFilter);
648 if (!This->pin_in.pair)
649 ret = VFW_E_NOT_CONNECTED;
650 else if (This->bufferLen < 0)
651 ret = E_INVALIDARG;
652 else if (This->bufferLen == 0)
653 ret = VFW_E_WRONG_STATE;
654 else {
655 if (buffer) {
656 if (*bufSize >= This->bufferLen)
657 CopyMemory(buffer, This->bufferData, This->bufferLen);
658 else
659 ret = E_OUTOFMEMORY;
661 *bufSize = This->bufferLen;
663 LeaveCriticalSection(&This->filter.csFilter);
664 return ret;
667 /* ISampleGrabber */
668 static HRESULT WINAPI
669 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
671 /* MS doesn't implement it either, no one should call it */
672 WARN("(%p): not implemented\n", sample);
673 return E_NOTIMPL;
676 /* ISampleGrabber */
677 static HRESULT WINAPI
678 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
680 SG_Impl *This = impl_from_ISampleGrabber(iface);
681 TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
682 if (This->grabberIface)
683 ISampleGrabberCB_Release(This->grabberIface);
684 This->grabberIface = cb;
685 This->grabberMethod = whichMethod;
686 if (cb)
687 ISampleGrabberCB_AddRef(cb);
688 return S_OK;
692 /* SampleGrabber implementation of IMemInputPin interface */
694 /* IUnknown */
695 static HRESULT WINAPI
696 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv)
698 SG_Impl *This = impl_from_IMemInputPin(iface);
699 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
702 /* IUnknown */
703 static ULONG WINAPI
704 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
706 SG_Impl *This = impl_from_IMemInputPin(iface);
707 return IUnknown_AddRef(This->outer_unk);
710 /* IUnknown */
711 static ULONG WINAPI
712 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
714 SG_Impl *This = impl_from_IMemInputPin(iface);
715 return IUnknown_Release(This->outer_unk);
718 /* IMemInputPin */
719 static HRESULT WINAPI
720 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
722 SG_Impl *This = impl_from_IMemInputPin(iface);
723 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
724 if (!allocator)
725 return E_POINTER;
726 *allocator = This->allocator;
727 if (!*allocator)
728 return VFW_E_NO_ALLOCATOR;
729 IMemAllocator_AddRef(*allocator);
730 return S_OK;
733 /* IMemInputPin */
734 static HRESULT WINAPI
735 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
737 SG_Impl *This = impl_from_IMemInputPin(iface);
738 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
739 if (This->allocator == allocator)
740 return S_OK;
741 if (This->allocator)
742 IMemAllocator_Release(This->allocator);
743 This->allocator = allocator;
744 if (allocator)
745 IMemAllocator_AddRef(allocator);
746 return S_OK;
749 /* IMemInputPin */
750 static HRESULT WINAPI
751 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
753 SG_Impl *This = impl_from_IMemInputPin(iface);
754 FIXME("(%p)->(%p): semi-stub\n", This, props);
755 if (!props)
756 return E_POINTER;
757 return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL;
760 /* IMemInputPin */
761 static HRESULT WINAPI
762 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
764 SG_Impl *This = impl_from_IMemInputPin(iface);
765 HRESULT hr;
766 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface);
767 if (!sample)
768 return E_POINTER;
769 if ((This->filter.state != State_Running) || (This->oneShot == OneShot_Past))
770 return S_FALSE;
771 SampleGrabber_callback(This, sample);
772 hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK;
773 if (This->oneShot == OneShot_Wait) {
774 This->oneShot = OneShot_Past;
775 hr = S_FALSE;
776 if (This->pin_out.pair)
777 IPin_EndOfStream(This->pin_out.pair);
779 return hr;
782 /* IMemInputPin */
783 static HRESULT WINAPI
784 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
786 SG_Impl *This = impl_from_IMemInputPin(iface);
787 LONG idx;
788 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface);
789 if (!samples || !nProcessed)
790 return E_POINTER;
791 if ((This->filter.state != State_Running) || (This->oneShot == OneShot_Past))
792 return S_FALSE;
793 for (idx = 0; idx < nSamples; idx++)
794 SampleGrabber_callback(This, samples[idx]);
795 return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK;
798 /* IMemInputPin */
799 static HRESULT WINAPI
800 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
802 SG_Impl *This = impl_from_IMemInputPin(iface);
803 TRACE("(%p)\n", This);
804 return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK;
808 /* SampleGrabber member pin implementation */
810 /* IUnknown */
811 static ULONG WINAPI
812 SampleGrabber_IPin_AddRef(IPin *iface)
814 SG_Pin *This = impl_from_IPin(iface);
815 return ISampleGrabber_AddRef(&This->sg->ISampleGrabber_iface);
818 /* IUnknown */
819 static ULONG WINAPI
820 SampleGrabber_IPin_Release(IPin *iface)
822 SG_Pin *This = impl_from_IPin(iface);
823 return ISampleGrabber_Release(&This->sg->ISampleGrabber_iface);
826 /* IUnknown */
827 static HRESULT WINAPI
828 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
830 SG_Pin *This = impl_from_IPin(iface);
831 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
833 *ppv = NULL;
834 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
835 *ppv = iface;
836 else if (IsEqualIID(riid, &IID_IMemInputPin))
837 *ppv = &This->sg->IMemInputPin_iface;
838 else if (IsEqualIID(riid, &IID_IMediaSeeking))
839 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
840 else if (IsEqualIID(riid, &IID_IMediaPosition))
841 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
842 else {
843 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
844 return E_NOINTERFACE;
847 IUnknown_AddRef((IUnknown*)*ppv);
848 return S_OK;
851 /* IPin - input pin */
852 static HRESULT WINAPI
853 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype)
855 WARN("(%p, %p): unexpected\n", receiver, mtype);
856 return E_UNEXPECTED;
859 /* IPin - output pin */
860 static HRESULT WINAPI
861 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type)
863 SG_Pin *This = impl_from_IPin(iface);
864 HRESULT hr;
866 TRACE("(%p)->(%p, %p)\n", This, receiver, type);
867 if (!receiver)
868 return E_POINTER;
869 if (This->pair)
870 return VFW_E_ALREADY_CONNECTED;
871 if (This->sg->filter.state != State_Stopped)
872 return VFW_E_NOT_STOPPED;
873 if (type) {
874 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
875 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
876 type->lSampleSize,
877 debugstr_guid(&type->formattype), type->cbFormat);
878 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
879 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
880 return VFW_E_TYPE_NOT_ACCEPTED;
881 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
882 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
883 return VFW_E_TYPE_NOT_ACCEPTED;
884 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
885 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
886 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
887 return VFW_E_TYPE_NOT_ACCEPTED;
889 else
890 type = &This->sg->mtype;
891 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
892 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
893 !type->pbFormat)
894 return VFW_E_TYPE_NOT_ACCEPTED;
895 hr = IPin_ReceiveConnection(receiver, &This->IPin_iface, type);
896 if (FAILED(hr))
897 return hr;
898 This->pair = receiver;
899 if (This->sg->memOutput) {
900 IMemInputPin_Release(This->sg->memOutput);
901 This->sg->memOutput = NULL;
903 IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput));
904 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput);
905 return S_OK;
908 /* IPin - input pin */
909 static HRESULT WINAPI
910 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type)
912 SG_Pin *This = impl_from_IPin(iface);
914 TRACE("(%p)->(%p, %p)\n", This, connector, type);
915 if (!connector)
916 return E_POINTER;
917 if (This->pair)
918 return VFW_E_ALREADY_CONNECTED;
919 if (This->sg->filter.state != State_Stopped)
920 return VFW_E_NOT_STOPPED;
921 if (type) {
922 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
923 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
924 type->lSampleSize,
925 debugstr_guid(&type->formattype), type->cbFormat);
926 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
927 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
928 !type->pbFormat)
929 return VFW_E_INVALIDMEDIATYPE;
930 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
931 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
932 return VFW_E_TYPE_NOT_ACCEPTED;
933 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
934 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
935 return VFW_E_TYPE_NOT_ACCEPTED;
936 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
937 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
938 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
939 return VFW_E_TYPE_NOT_ACCEPTED;
940 if (This->sg->mtype.pbFormat)
941 CoTaskMemFree(This->sg->mtype.pbFormat);
942 This->sg->mtype = *type;
943 This->sg->mtype.pUnk = NULL;
944 if (type->cbFormat) {
945 This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
946 CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat);
948 else
949 This->sg->mtype.pbFormat = NULL;
951 This->pair = connector;
952 TRACE("(%p) Accepted IPin %p\n", This, connector);
953 return S_OK;
956 /* IPin - output pin */
957 static HRESULT WINAPI
958 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype)
960 WARN("(%p, %p): unexpected\n", connector, mtype);
961 return E_UNEXPECTED;
964 /* IPin - input pin */
965 static HRESULT WINAPI
966 SampleGrabber_In_IPin_Disconnect(IPin *iface)
968 SG_Pin *This = impl_from_IPin(iface);
970 TRACE("(%p)->() pair = %p\n", This, This->pair);
971 if (This->sg->filter.state != State_Stopped)
972 return VFW_E_NOT_STOPPED;
973 if (This->pair) {
974 This->pair = NULL;
975 return S_OK;
977 return S_FALSE;
980 /* IPin - output pin */
981 static HRESULT WINAPI
982 SampleGrabber_Out_IPin_Disconnect(IPin *iface)
984 SG_Pin *This = impl_from_IPin(iface);
986 TRACE("(%p)->() pair = %p\n", This, This->pair);
987 if (This->sg->filter.state != State_Stopped)
988 return VFW_E_NOT_STOPPED;
989 if (This->pair) {
990 This->pair = NULL;
991 if (This->sg->memOutput) {
992 IMemInputPin_Release(This->sg->memOutput);
993 This->sg->memOutput = NULL;
995 return S_OK;
997 return S_FALSE;
1000 /* IPin */
1001 static HRESULT WINAPI
1002 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin)
1004 SG_Pin *This = impl_from_IPin(iface);
1006 TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair);
1007 if (!pin)
1008 return E_POINTER;
1009 *pin = This->pair;
1010 if (*pin) {
1011 IPin_AddRef(*pin);
1012 return S_OK;
1014 return VFW_E_NOT_CONNECTED;
1017 /* IPin */
1018 static HRESULT WINAPI
1019 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype)
1021 SG_Pin *This = impl_from_IPin(iface);
1023 TRACE("(%p)->(%p)\n", This, mtype);
1024 if (!mtype)
1025 return E_POINTER;
1026 if (!This->pair)
1027 return VFW_E_NOT_CONNECTED;
1028 *mtype = This->sg->mtype;
1029 if (mtype->cbFormat) {
1030 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
1031 CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat);
1033 return S_OK;
1036 /* IPin */
1037 static HRESULT WINAPI
1038 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info)
1040 SG_Pin *This = impl_from_IPin(iface);
1042 TRACE("(%p)->(%p)\n", This, info);
1043 if (!info)
1044 return E_POINTER;
1045 info->pFilter = &This->sg->filter.IBaseFilter_iface;
1046 IBaseFilter_AddRef(info->pFilter);
1047 info->dir = This->dir;
1048 lstrcpynW(info->achName,This->name,MAX_PIN_NAME);
1049 return S_OK;
1052 /* IPin */
1053 static HRESULT WINAPI
1054 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1056 SG_Pin *This = impl_from_IPin(iface);
1058 TRACE("(%p)->(%p)\n", This, dir);
1059 if (!dir)
1060 return E_POINTER;
1061 *dir = This->dir;
1062 return S_OK;
1065 /* IPin */
1066 static HRESULT WINAPI
1067 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id)
1069 SG_Pin *This = impl_from_IPin(iface);
1071 int len;
1072 TRACE("(%p)->(%p)\n", This, id);
1073 if (!id)
1074 return E_POINTER;
1075 len = sizeof(WCHAR)*(1+lstrlenW(This->name));
1076 *id = CoTaskMemAlloc(len);
1077 CopyMemory(*id, This->name, len);
1078 return S_OK;
1081 /* IPin */
1082 static HRESULT WINAPI
1083 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype)
1085 TRACE("(%p)\n", mtype);
1086 return S_OK;
1089 /* IPin */
1090 static HRESULT WINAPI
1091 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes)
1093 SG_Pin *This = impl_from_IPin(iface);
1095 TRACE("(%p)->(%p)\n", This, mtypes);
1096 if (!mtypes)
1097 return E_POINTER;
1098 *mtypes = mediaenum_create(This->sg->pin_in.pair ? &This->sg->mtype : NULL);
1099 return *mtypes ? S_OK : E_OUTOFMEMORY;
1102 /* IPin - input pin */
1103 static HRESULT WINAPI
1104 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1106 SG_Pin *This = impl_from_IPin(iface);
1108 TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0));
1109 if (!nPins)
1110 return E_POINTER;
1111 if (*nPins) {
1112 if (!pins)
1113 return E_POINTER;
1114 IPin_AddRef(&This->sg->pin_out.IPin_iface);
1115 *pins = &This->sg->pin_out.IPin_iface;
1116 *nPins = 1;
1117 return S_OK;
1119 *nPins = 1;
1120 return S_FALSE;
1123 /* IPin - output pin */
1124 static HRESULT WINAPI
1125 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1127 WARN("(%p, %p): unexpected\n", pins, nPins);
1128 if (nPins)
1129 *nPins = 0;
1130 return E_NOTIMPL;
1133 /* IPin */
1134 static HRESULT WINAPI
1135 SampleGrabber_IPin_EndOfStream(IPin *iface)
1137 FIXME(": stub\n");
1138 return S_OK;
1141 /* IPin */
1142 static HRESULT WINAPI
1143 SampleGrabber_IPin_BeginFlush(IPin *iface)
1145 FIXME(": stub\n");
1146 return S_OK;
1149 /* IPin */
1150 static HRESULT WINAPI
1151 SampleGrabber_IPin_EndFlush(IPin *iface)
1153 FIXME(": stub\n");
1154 return S_OK;
1157 /* IPin */
1158 static HRESULT WINAPI
1159 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate)
1161 FIXME(": stub\n");
1162 return S_OK;
1166 /* SampleGrabber vtables and constructor */
1168 static const IBaseFilterVtbl IBaseFilter_VTable =
1170 SampleGrabber_IBaseFilter_QueryInterface,
1171 SampleGrabber_IBaseFilter_AddRef,
1172 SampleGrabber_IBaseFilter_Release,
1173 BaseFilterImpl_GetClassID,
1174 SampleGrabber_IBaseFilter_Stop,
1175 SampleGrabber_IBaseFilter_Pause,
1176 SampleGrabber_IBaseFilter_Run,
1177 BaseFilterImpl_GetState,
1178 BaseFilterImpl_SetSyncSource,
1179 BaseFilterImpl_GetSyncSource,
1180 BaseFilterImpl_EnumPins,
1181 SampleGrabber_IBaseFilter_FindPin,
1182 BaseFilterImpl_QueryFilterInfo,
1183 SampleGrabber_IBaseFilter_JoinFilterGraph,
1184 SampleGrabber_IBaseFilter_QueryVendorInfo,
1187 static const ISampleGrabberVtbl ISampleGrabber_VTable =
1189 SampleGrabber_ISampleGrabber_QueryInterface,
1190 SampleGrabber_ISampleGrabber_AddRef,
1191 SampleGrabber_ISampleGrabber_Release,
1192 SampleGrabber_ISampleGrabber_SetOneShot,
1193 SampleGrabber_ISampleGrabber_SetMediaType,
1194 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
1195 SampleGrabber_ISampleGrabber_SetBufferSamples,
1196 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
1197 SampleGrabber_ISampleGrabber_GetCurrentSample,
1198 SampleGrabber_ISampleGrabber_SetCallback,
1201 static const IMemInputPinVtbl IMemInputPin_VTable =
1203 SampleGrabber_IMemInputPin_QueryInterface,
1204 SampleGrabber_IMemInputPin_AddRef,
1205 SampleGrabber_IMemInputPin_Release,
1206 SampleGrabber_IMemInputPin_GetAllocator,
1207 SampleGrabber_IMemInputPin_NotifyAllocator,
1208 SampleGrabber_IMemInputPin_GetAllocatorRequirements,
1209 SampleGrabber_IMemInputPin_Receive,
1210 SampleGrabber_IMemInputPin_ReceiveMultiple,
1211 SampleGrabber_IMemInputPin_ReceiveCanBlock,
1214 static const IPinVtbl IPin_In_VTable =
1216 SampleGrabber_IPin_QueryInterface,
1217 SampleGrabber_IPin_AddRef,
1218 SampleGrabber_IPin_Release,
1219 SampleGrabber_In_IPin_Connect,
1220 SampleGrabber_In_IPin_ReceiveConnection,
1221 SampleGrabber_In_IPin_Disconnect,
1222 SampleGrabber_IPin_ConnectedTo,
1223 SampleGrabber_IPin_ConnectionMediaType,
1224 SampleGrabber_IPin_QueryPinInfo,
1225 SampleGrabber_IPin_QueryDirection,
1226 SampleGrabber_IPin_QueryId,
1227 SampleGrabber_IPin_QueryAccept,
1228 SampleGrabber_IPin_EnumMediaTypes,
1229 SampleGrabber_In_IPin_QueryInternalConnections,
1230 SampleGrabber_IPin_EndOfStream,
1231 SampleGrabber_IPin_BeginFlush,
1232 SampleGrabber_IPin_EndFlush,
1233 SampleGrabber_IPin_NewSegment,
1236 static const IPinVtbl IPin_Out_VTable =
1238 SampleGrabber_IPin_QueryInterface,
1239 SampleGrabber_IPin_AddRef,
1240 SampleGrabber_IPin_Release,
1241 SampleGrabber_Out_IPin_Connect,
1242 SampleGrabber_Out_IPin_ReceiveConnection,
1243 SampleGrabber_Out_IPin_Disconnect,
1244 SampleGrabber_IPin_ConnectedTo,
1245 SampleGrabber_IPin_ConnectionMediaType,
1246 SampleGrabber_IPin_QueryPinInfo,
1247 SampleGrabber_IPin_QueryDirection,
1248 SampleGrabber_IPin_QueryId,
1249 SampleGrabber_IPin_QueryAccept,
1250 SampleGrabber_IPin_EnumMediaTypes,
1251 SampleGrabber_Out_IPin_QueryInternalConnections,
1252 SampleGrabber_IPin_EndOfStream,
1253 SampleGrabber_IPin_BeginFlush,
1254 SampleGrabber_IPin_EndFlush,
1255 SampleGrabber_IPin_NewSegment,
1258 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
1260 SG_Impl* obj = NULL;
1261 ISeekingPassThru *passthru;
1262 HRESULT hr;
1264 TRACE("(%p,%p)\n", ppv, pUnkOuter);
1266 obj = CoTaskMemAlloc(sizeof(SG_Impl));
1267 if (NULL == obj) {
1268 *ppv = NULL;
1269 return E_OUTOFMEMORY;
1271 ZeroMemory(obj, sizeof(SG_Impl));
1273 BaseFilter_Init(&obj->filter, &IBaseFilter_VTable, &CLSID_SampleGrabber,
1274 (DWORD_PTR)(__FILE__ ": SG_Impl.csFilter"), &basefunc_vtbl);
1275 obj->IUnknown_inner.lpVtbl = &samplegrabber_vtbl;
1276 obj->ISampleGrabber_iface.lpVtbl = &ISampleGrabber_VTable;
1277 obj->IMemInputPin_iface.lpVtbl = &IMemInputPin_VTable;
1278 obj->pin_in.IPin_iface.lpVtbl = &IPin_In_VTable;
1279 obj->pin_in.dir = PINDIR_INPUT;
1280 obj->pin_in.name = pin_in_name;
1281 obj->pin_in.sg = obj;
1282 obj->pin_in.pair = NULL;
1283 obj->pin_out.IPin_iface.lpVtbl = &IPin_Out_VTable;
1284 obj->pin_out.dir = PINDIR_OUTPUT;
1285 obj->pin_out.name = pin_out_name;
1286 obj->pin_out.sg = obj;
1287 obj->pin_out.pair = NULL;
1288 obj->mtype.majortype = GUID_NULL;
1289 obj->mtype.subtype = MEDIASUBTYPE_None;
1290 obj->mtype.formattype = FORMAT_None;
1291 obj->allocator = NULL;
1292 obj->memOutput = NULL;
1293 obj->grabberIface = NULL;
1294 obj->grabberMethod = -1;
1295 obj->oneShot = OneShot_None;
1296 obj->bufferLen = -1;
1297 obj->bufferData = NULL;
1299 if (pUnkOuter)
1300 obj->outer_unk = pUnkOuter;
1301 else
1302 obj->outer_unk = &obj->IUnknown_inner;
1304 hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)obj, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&obj->seekthru_unk);
1305 if(hr)
1306 return hr;
1307 IUnknown_QueryInterface(obj->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
1308 ISeekingPassThru_Init(passthru, FALSE, &obj->pin_in.IPin_iface);
1309 ISeekingPassThru_Release(passthru);
1311 *ppv = &obj->IUnknown_inner;
1312 return S_OK;