mshtml: Implement MediaQueryList's addListener method.
[wine.git] / dlls / qedit / samplegrabber.c
blobcefb2f3707859744cadecdccaa53ff26efa95a40
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"
33 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
35 struct sample_grabber
37 struct strmbase_filter filter;
38 ISampleGrabber ISampleGrabber_iface;
40 struct strmbase_source source;
41 struct strmbase_passthrough passthrough;
43 struct strmbase_sink sink;
44 AM_MEDIA_TYPE filter_mt;
45 IMemInputPin IMemInputPin_iface;
46 IMemAllocator *allocator;
48 ISampleGrabberCB *grabberIface;
49 LONG grabberMethod;
50 LONG oneShot;
51 LONG bufferLen;
52 void* bufferData;
55 enum {
56 OneShot_None,
57 OneShot_Wait,
58 OneShot_Past,
61 static struct sample_grabber *impl_from_strmbase_filter(struct strmbase_filter *iface)
63 return CONTAINING_RECORD(iface, struct sample_grabber, filter);
66 static struct sample_grabber *impl_from_ISampleGrabber(ISampleGrabber *iface)
68 return CONTAINING_RECORD(iface, struct sample_grabber, ISampleGrabber_iface);
71 static struct sample_grabber *impl_from_IMemInputPin(IMemInputPin *iface)
73 return CONTAINING_RECORD(iface, struct sample_grabber, IMemInputPin_iface);
77 /* Cleanup at end of life */
78 static void SampleGrabber_cleanup(struct sample_grabber *This)
80 TRACE("(%p)\n", This);
81 if (This->allocator)
82 IMemAllocator_Release(This->allocator);
83 if (This->grabberIface)
84 ISampleGrabberCB_Release(This->grabberIface);
85 FreeMediaType(&This->filter_mt);
86 CoTaskMemFree(This->bufferData);
89 static struct strmbase_pin *sample_grabber_get_pin(struct strmbase_filter *iface, unsigned int index)
91 struct sample_grabber *filter = impl_from_strmbase_filter(iface);
93 if (index == 0)
94 return &filter->sink.pin;
95 else if (index == 1)
96 return &filter->source.pin;
97 return NULL;
100 static void sample_grabber_destroy(struct strmbase_filter *iface)
102 struct sample_grabber *filter = impl_from_strmbase_filter(iface);
104 SampleGrabber_cleanup(filter);
105 strmbase_sink_cleanup(&filter->sink);
106 strmbase_source_cleanup(&filter->source);
107 strmbase_passthrough_cleanup(&filter->passthrough);
108 strmbase_filter_cleanup(&filter->filter);
109 free(filter);
112 static HRESULT sample_grabber_query_interface(struct strmbase_filter *iface, REFIID iid, void **out)
114 struct sample_grabber *filter = impl_from_strmbase_filter(iface);
116 if (IsEqualGUID(iid, &IID_ISampleGrabber))
117 *out = &filter->ISampleGrabber_iface;
118 else
119 return E_NOINTERFACE;
121 IUnknown_AddRef((IUnknown *)*out);
122 return S_OK;
125 static const struct strmbase_filter_ops filter_ops =
127 .filter_get_pin = sample_grabber_get_pin,
128 .filter_destroy = sample_grabber_destroy,
129 .filter_query_interface = sample_grabber_query_interface,
132 /* Helper that buffers data and/or calls installed sample callbacks */
133 static void SampleGrabber_callback(struct sample_grabber *This, IMediaSample *sample)
135 double time = 0.0;
136 REFERENCE_TIME tStart, tEnd;
137 if (This->bufferLen >= 0) {
138 BYTE *data = 0;
139 LONG size = IMediaSample_GetActualDataLength(sample);
140 if (size >= 0 && SUCCEEDED(IMediaSample_GetPointer(sample, &data))) {
141 if (!data)
142 size = 0;
143 EnterCriticalSection(&This->filter.filter_cs);
144 if (This->bufferLen != size) {
145 CoTaskMemFree(This->bufferData);
146 This->bufferData = size ? CoTaskMemAlloc(size) : NULL;
147 This->bufferLen = size;
149 if (size)
150 CopyMemory(This->bufferData, data, size);
151 LeaveCriticalSection(&This->filter.filter_cs);
154 if (!This->grabberIface)
155 return;
156 if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
157 time = 1e-7 * tStart;
158 switch (This->grabberMethod) {
159 case 0:
161 ULONG ref = IMediaSample_AddRef(sample);
162 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
163 ref = IMediaSample_Release(sample) + 1 - ref;
164 if (ref)
166 ERR("(%p) Callback referenced sample %p by %lu\n", This, sample, ref);
169 break;
170 case 1:
172 BYTE *data = 0;
173 LONG size = IMediaSample_GetActualDataLength(sample);
174 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
175 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
177 break;
178 case -1:
179 break;
180 default:
181 FIXME("Unknown method %ld.\n", This->grabberMethod);
182 /* do not bother us again */
183 This->grabberMethod = -1;
187 /* IUnknown */
188 static HRESULT WINAPI
189 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv)
191 struct sample_grabber *filter = impl_from_ISampleGrabber(iface);
192 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
195 /* IUnknown */
196 static ULONG WINAPI
197 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
199 struct sample_grabber *filter = impl_from_ISampleGrabber(iface);
200 return IUnknown_AddRef(filter->filter.outer_unk);
203 /* IUnknown */
204 static ULONG WINAPI
205 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
207 struct sample_grabber *filter = impl_from_ISampleGrabber(iface);
208 return IUnknown_Release(filter->filter.outer_unk);
211 /* ISampleGrabber */
212 static HRESULT WINAPI
213 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
215 struct sample_grabber *This = impl_from_ISampleGrabber(iface);
216 TRACE("(%p)->(%u)\n", This, oneShot);
217 This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
218 return S_OK;
221 /* ISampleGrabber */
222 static HRESULT WINAPI SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *mt)
224 struct sample_grabber *filter = impl_from_ISampleGrabber(iface);
226 TRACE("filter %p, mt %p.\n", filter, mt);
227 strmbase_dump_media_type(mt);
229 if (!mt)
230 return E_POINTER;
232 FreeMediaType(&filter->filter_mt);
233 CopyMediaType(&filter->filter_mt, mt);
234 return S_OK;
237 /* ISampleGrabber */
238 static HRESULT WINAPI
239 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *mt)
241 struct sample_grabber *filter = impl_from_ISampleGrabber(iface);
243 TRACE("filter %p, mt %p.\n", filter, mt);
245 if (!mt)
246 return E_POINTER;
248 if (!filter->sink.pin.peer)
249 return VFW_E_NOT_CONNECTED;
251 CopyMediaType(mt, &filter->sink.pin.mt);
252 return S_OK;
255 /* ISampleGrabber */
256 static HRESULT WINAPI
257 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
259 struct sample_grabber *This = impl_from_ISampleGrabber(iface);
260 TRACE("(%p)->(%u)\n", This, bufferEm);
261 EnterCriticalSection(&This->filter.filter_cs);
262 if (bufferEm) {
263 if (This->bufferLen < 0)
264 This->bufferLen = 0;
266 else
267 This->bufferLen = -1;
268 LeaveCriticalSection(&This->filter.filter_cs);
269 return S_OK;
272 /* ISampleGrabber */
273 static HRESULT WINAPI
274 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
276 struct sample_grabber *This = impl_from_ISampleGrabber(iface);
277 HRESULT ret = S_OK;
278 TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer);
279 if (!bufSize)
280 return E_POINTER;
281 EnterCriticalSection(&This->filter.filter_cs);
282 if (!This->sink.pin.peer)
283 ret = VFW_E_NOT_CONNECTED;
284 else if (This->bufferLen < 0)
285 ret = E_INVALIDARG;
286 else if (This->bufferLen == 0)
287 ret = VFW_E_WRONG_STATE;
288 else {
289 if (buffer) {
290 if (*bufSize >= This->bufferLen)
291 CopyMemory(buffer, This->bufferData, This->bufferLen);
292 else
293 ret = E_OUTOFMEMORY;
295 *bufSize = This->bufferLen;
297 LeaveCriticalSection(&This->filter.filter_cs);
298 return ret;
301 /* ISampleGrabber */
302 static HRESULT WINAPI
303 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
305 /* MS doesn't implement it either, no one should call it */
306 WARN("(%p): not implemented\n", sample);
307 return E_NOTIMPL;
310 /* ISampleGrabber */
311 static HRESULT WINAPI
312 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
314 struct sample_grabber *This = impl_from_ISampleGrabber(iface);
316 TRACE("filter %p, callback %p, method %ld.\n", This, cb, whichMethod);
318 if (This->grabberIface)
319 ISampleGrabberCB_Release(This->grabberIface);
320 This->grabberIface = cb;
321 This->grabberMethod = whichMethod;
322 if (cb)
323 ISampleGrabberCB_AddRef(cb);
324 return S_OK;
327 static HRESULT WINAPI SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
329 struct sample_grabber *filter = impl_from_IMemInputPin(iface);
330 return IPin_QueryInterface(&filter->sink.pin.IPin_iface, iid, out);
333 static ULONG WINAPI SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
335 struct sample_grabber *filter = impl_from_IMemInputPin(iface);
336 return IPin_AddRef(&filter->sink.pin.IPin_iface);
339 static ULONG WINAPI SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
341 struct sample_grabber *filter = impl_from_IMemInputPin(iface);
342 return IPin_Release(&filter->sink.pin.IPin_iface);
345 /* IMemInputPin */
346 static HRESULT WINAPI
347 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
349 struct sample_grabber *This = impl_from_IMemInputPin(iface);
350 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
351 if (!allocator)
352 return E_POINTER;
353 *allocator = This->allocator;
354 if (!*allocator)
355 return VFW_E_NO_ALLOCATOR;
356 IMemAllocator_AddRef(*allocator);
357 return S_OK;
360 /* IMemInputPin */
361 static HRESULT WINAPI
362 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
364 struct sample_grabber *This = impl_from_IMemInputPin(iface);
365 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
366 if (This->allocator == allocator)
367 return S_OK;
368 if (This->allocator)
369 IMemAllocator_Release(This->allocator);
370 This->allocator = allocator;
371 if (allocator)
372 IMemAllocator_AddRef(allocator);
373 return S_OK;
376 /* IMemInputPin */
377 static HRESULT WINAPI
378 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
380 struct sample_grabber *This = impl_from_IMemInputPin(iface);
381 FIXME("(%p)->(%p): semi-stub\n", This, props);
382 if (!props)
383 return E_POINTER;
384 return This->source.pMemInputPin ? IMemInputPin_GetAllocatorRequirements(This->source.pMemInputPin, props) : E_NOTIMPL;
387 /* IMemInputPin */
388 static HRESULT WINAPI
389 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
391 struct sample_grabber *This = impl_from_IMemInputPin(iface);
392 HRESULT hr;
393 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->source.pMemInputPin, This->grabberIface);
394 if (!sample)
395 return E_POINTER;
396 if (This->oneShot == OneShot_Past)
397 return S_FALSE;
398 SampleGrabber_callback(This, sample);
399 hr = This->source.pMemInputPin ? IMemInputPin_Receive(This->source.pMemInputPin, sample) : S_OK;
400 if (This->oneShot == OneShot_Wait) {
401 This->oneShot = OneShot_Past;
402 hr = S_FALSE;
403 if (This->source.pin.peer)
404 IPin_EndOfStream(This->source.pin.peer);
406 return hr;
409 /* IMemInputPin */
410 static HRESULT WINAPI
411 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
413 struct sample_grabber *This = impl_from_IMemInputPin(iface);
414 LONG idx;
416 TRACE("filter %p, samples %p, count %lu, ret_count %p.\n", This, samples, nSamples, nProcessed);
418 if (!samples || !nProcessed)
419 return E_POINTER;
420 if ((This->filter.state != State_Running) || (This->oneShot == OneShot_Past))
421 return S_FALSE;
422 for (idx = 0; idx < nSamples; idx++)
423 SampleGrabber_callback(This, samples[idx]);
424 return This->source.pMemInputPin ? IMemInputPin_ReceiveMultiple(This->source.pMemInputPin, samples, nSamples, nProcessed) : S_OK;
427 /* IMemInputPin */
428 static HRESULT WINAPI
429 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
431 struct sample_grabber *This = impl_from_IMemInputPin(iface);
432 TRACE("(%p)\n", This);
433 return This->source.pMemInputPin ? IMemInputPin_ReceiveCanBlock(This->source.pMemInputPin) : S_OK;
436 static const ISampleGrabberVtbl ISampleGrabber_VTable =
438 SampleGrabber_ISampleGrabber_QueryInterface,
439 SampleGrabber_ISampleGrabber_AddRef,
440 SampleGrabber_ISampleGrabber_Release,
441 SampleGrabber_ISampleGrabber_SetOneShot,
442 SampleGrabber_ISampleGrabber_SetMediaType,
443 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
444 SampleGrabber_ISampleGrabber_SetBufferSamples,
445 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
446 SampleGrabber_ISampleGrabber_GetCurrentSample,
447 SampleGrabber_ISampleGrabber_SetCallback,
450 static const IMemInputPinVtbl IMemInputPin_VTable =
452 SampleGrabber_IMemInputPin_QueryInterface,
453 SampleGrabber_IMemInputPin_AddRef,
454 SampleGrabber_IMemInputPin_Release,
455 SampleGrabber_IMemInputPin_GetAllocator,
456 SampleGrabber_IMemInputPin_NotifyAllocator,
457 SampleGrabber_IMemInputPin_GetAllocatorRequirements,
458 SampleGrabber_IMemInputPin_Receive,
459 SampleGrabber_IMemInputPin_ReceiveMultiple,
460 SampleGrabber_IMemInputPin_ReceiveCanBlock,
463 static struct sample_grabber *impl_from_sink_pin(struct strmbase_pin *iface)
465 return CONTAINING_RECORD(iface, struct sample_grabber, sink.pin);
468 static HRESULT sample_grabber_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
470 struct sample_grabber *filter = impl_from_sink_pin(iface);
472 if (IsEqualGUID(iid, &IID_IMemInputPin))
473 *out = &filter->IMemInputPin_iface;
474 else
475 return E_NOINTERFACE;
477 IUnknown_AddRef((IUnknown *)*out);
478 return S_OK;
481 static BOOL check_filter_mt(struct sample_grabber *filter, const AM_MEDIA_TYPE *mt)
483 if (IsEqualGUID(&filter->filter_mt.majortype, &GUID_NULL))
484 return TRUE;
485 if (!IsEqualGUID(&filter->filter_mt.majortype, &mt->majortype))
486 return FALSE;
488 if (IsEqualGUID(&filter->filter_mt.subtype, &GUID_NULL))
489 return TRUE;
490 if (!IsEqualGUID(&filter->filter_mt.subtype, &mt->subtype))
491 return FALSE;
493 if (IsEqualGUID(&filter->filter_mt.formattype, &GUID_NULL))
494 return TRUE;
495 if (!IsEqualGUID(&filter->filter_mt.formattype, &mt->formattype))
496 return FALSE;
498 return TRUE;
501 static HRESULT sample_grabber_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
503 struct sample_grabber *filter = impl_from_sink_pin(iface);
505 return check_filter_mt(filter, mt) ? S_OK : S_FALSE;
508 static HRESULT sample_grabber_sink_get_media_type(struct strmbase_pin *iface,
509 unsigned int index, AM_MEDIA_TYPE *mt)
511 struct sample_grabber *filter = impl_from_sink_pin(iface);
512 IEnumMediaTypes *enummt;
513 AM_MEDIA_TYPE *pmt;
514 HRESULT hr;
516 if (!filter->source.pin.peer)
517 return VFW_E_NOT_CONNECTED;
519 if (FAILED(hr = IPin_EnumMediaTypes(filter->source.pin.peer, &enummt)))
520 return hr;
522 if ((!index || IEnumMediaTypes_Skip(enummt, index) == S_OK)
523 && IEnumMediaTypes_Next(enummt, 1, &pmt, NULL) == S_OK)
525 CopyMediaType(mt, pmt);
526 DeleteMediaType(pmt);
527 IEnumMediaTypes_Release(enummt);
528 return S_OK;
531 IEnumMediaTypes_Release(enummt);
532 return VFW_S_NO_MORE_ITEMS;
535 static const struct strmbase_sink_ops sink_ops =
537 .base.pin_query_interface = sample_grabber_sink_query_interface,
538 .base.pin_query_accept = sample_grabber_sink_query_accept,
539 .base.pin_get_media_type = sample_grabber_sink_get_media_type,
542 static struct sample_grabber *impl_from_source_pin(struct strmbase_pin *iface)
544 return CONTAINING_RECORD(iface, struct sample_grabber, source.pin);
547 static HRESULT sample_grabber_source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
549 struct sample_grabber *filter = impl_from_source_pin(iface);
551 if (IsEqualGUID(iid, &IID_IMediaPosition))
552 *out = &filter->passthrough.IMediaPosition_iface;
553 else if (IsEqualGUID(iid, &IID_IMediaSeeking))
554 *out = &filter->passthrough.IMediaSeeking_iface;
555 else
556 return E_NOINTERFACE;
558 IUnknown_AddRef((IUnknown *)*out);
559 return S_OK;
562 static HRESULT sample_grabber_source_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
564 struct sample_grabber *filter = impl_from_source_pin(iface);
566 if (filter->sink.pin.peer && IPin_QueryAccept(filter->sink.pin.peer, mt) != S_OK)
567 return S_FALSE;
569 return check_filter_mt(filter, mt) ? S_OK : S_FALSE;
572 static HRESULT sample_grabber_source_get_media_type(struct strmbase_pin *iface,
573 unsigned int index, AM_MEDIA_TYPE *mt)
575 struct sample_grabber *filter = impl_from_source_pin(iface);
576 IEnumMediaTypes *enummt;
577 AM_MEDIA_TYPE *pmt;
578 HRESULT hr;
580 if (!filter->sink.pin.peer)
581 return VFW_E_NOT_CONNECTED;
583 if (FAILED(hr = IPin_EnumMediaTypes(filter->sink.pin.peer, &enummt)))
584 return hr;
586 if ((!index || IEnumMediaTypes_Skip(enummt, index) == S_OK)
587 && IEnumMediaTypes_Next(enummt, 1, &pmt, NULL) == S_OK)
589 CopyMediaType(mt, pmt);
590 DeleteMediaType(pmt);
591 IEnumMediaTypes_Release(enummt);
592 return S_OK;
595 IEnumMediaTypes_Release(enummt);
596 return VFW_S_NO_MORE_ITEMS;
599 static inline BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TYPE *b)
601 return !memcmp(a, b, offsetof(AM_MEDIA_TYPE, pbFormat))
602 && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat);
605 static HRESULT WINAPI sample_grabber_source_DecideAllocator(struct strmbase_source *iface,
606 IMemInputPin *peer, IMemAllocator **allocator)
608 struct sample_grabber *filter = impl_from_source_pin(&iface->pin);
609 const AM_MEDIA_TYPE *mt = &iface->pin.mt;
611 if (!compare_media_types(mt, &filter->sink.pin.mt))
613 IFilterGraph2 *graph;
614 HRESULT hr;
616 if (FAILED(hr = IFilterGraph_QueryInterface(filter->filter.graph,
617 &IID_IFilterGraph2, (void **)&graph)))
619 ERR("Failed to get IFilterGraph2 interface, hr %#lx.\n", hr);
620 return hr;
623 hr = IFilterGraph2_ReconnectEx(graph, &filter->sink.pin.IPin_iface, mt);
624 IFilterGraph2_Release(graph);
625 return hr;
628 return S_OK;
631 static const struct strmbase_source_ops source_ops =
633 .base.pin_query_interface = sample_grabber_source_query_interface,
634 .base.pin_query_accept = sample_grabber_source_query_accept,
635 .base.pin_get_media_type = sample_grabber_source_get_media_type,
636 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
637 .pfnDecideAllocator = sample_grabber_source_DecideAllocator,
640 HRESULT sample_grabber_create(IUnknown *outer, IUnknown **out)
642 struct sample_grabber *object;
644 if (!(object = calloc(1, sizeof(*object))))
645 return E_OUTOFMEMORY;
647 strmbase_filter_init(&object->filter, outer, &CLSID_SampleGrabber, &filter_ops);
648 object->ISampleGrabber_iface.lpVtbl = &ISampleGrabber_VTable;
649 object->IMemInputPin_iface.lpVtbl = &IMemInputPin_VTable;
651 strmbase_sink_init(&object->sink, &object->filter, L"In", &sink_ops, NULL);
652 wcscpy(object->sink.pin.name, L"Input");
654 strmbase_source_init(&object->source, &object->filter, L"Out", &source_ops);
655 wcscpy(object->source.pin.name, L"Output");
657 strmbase_passthrough_init(&object->passthrough, (IUnknown *)&object->source.pin.IPin_iface);
658 ISeekingPassThru_Init(&object->passthrough.ISeekingPassThru_iface, FALSE,
659 &object->sink.pin.IPin_iface);
661 object->grabberMethod = -1;
662 object->oneShot = OneShot_None;
663 object->bufferLen = -1;
665 TRACE("Created sample grabber %p.\n", object);
666 *out = &object->filter.IUnknown_inner;
667 return S_OK;