comsvcs/tests: Avoid "misleading indentation" warnings.
[wine.git] / dlls / qedit / samplegrabber.c
blobd1b974d3d5dedce0deba6e586a9573a200aa7ab7
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 %u\n", This, sample, ref);
167 /* ugly as hell but some apps are sooo buggy */
168 while (ref--)
169 IMediaSample_Release(sample);
172 break;
173 case 1:
175 BYTE *data = 0;
176 LONG size = IMediaSample_GetActualDataLength(sample);
177 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
178 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
180 break;
181 case -1:
182 break;
183 default:
184 FIXME("unsupported method %d\n", This->grabberMethod);
185 /* do not bother us again */
186 This->grabberMethod = -1;
190 /* IUnknown */
191 static HRESULT WINAPI
192 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv)
194 struct sample_grabber *filter = impl_from_ISampleGrabber(iface);
195 return IUnknown_QueryInterface(filter->filter.outer_unk, riid, ppv);
198 /* IUnknown */
199 static ULONG WINAPI
200 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
202 struct sample_grabber *filter = impl_from_ISampleGrabber(iface);
203 return IUnknown_AddRef(filter->filter.outer_unk);
206 /* IUnknown */
207 static ULONG WINAPI
208 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
210 struct sample_grabber *filter = impl_from_ISampleGrabber(iface);
211 return IUnknown_Release(filter->filter.outer_unk);
214 /* ISampleGrabber */
215 static HRESULT WINAPI
216 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
218 struct sample_grabber *This = impl_from_ISampleGrabber(iface);
219 TRACE("(%p)->(%u)\n", This, oneShot);
220 This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
221 return S_OK;
224 /* ISampleGrabber */
225 static HRESULT WINAPI SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *mt)
227 struct sample_grabber *filter = impl_from_ISampleGrabber(iface);
229 TRACE("filter %p, mt %p.\n", filter, mt);
230 strmbase_dump_media_type(mt);
232 if (!mt)
233 return E_POINTER;
235 FreeMediaType(&filter->filter_mt);
236 CopyMediaType(&filter->filter_mt, mt);
237 return S_OK;
240 /* ISampleGrabber */
241 static HRESULT WINAPI
242 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *mt)
244 struct sample_grabber *filter = impl_from_ISampleGrabber(iface);
246 TRACE("filter %p, mt %p.\n", filter, mt);
248 if (!mt)
249 return E_POINTER;
251 if (!filter->sink.pin.peer)
252 return VFW_E_NOT_CONNECTED;
254 CopyMediaType(mt, &filter->sink.pin.mt);
255 return S_OK;
258 /* ISampleGrabber */
259 static HRESULT WINAPI
260 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
262 struct sample_grabber *This = impl_from_ISampleGrabber(iface);
263 TRACE("(%p)->(%u)\n", This, bufferEm);
264 EnterCriticalSection(&This->filter.filter_cs);
265 if (bufferEm) {
266 if (This->bufferLen < 0)
267 This->bufferLen = 0;
269 else
270 This->bufferLen = -1;
271 LeaveCriticalSection(&This->filter.filter_cs);
272 return S_OK;
275 /* ISampleGrabber */
276 static HRESULT WINAPI
277 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
279 struct sample_grabber *This = impl_from_ISampleGrabber(iface);
280 HRESULT ret = S_OK;
281 TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer);
282 if (!bufSize)
283 return E_POINTER;
284 EnterCriticalSection(&This->filter.filter_cs);
285 if (!This->sink.pin.peer)
286 ret = VFW_E_NOT_CONNECTED;
287 else if (This->bufferLen < 0)
288 ret = E_INVALIDARG;
289 else if (This->bufferLen == 0)
290 ret = VFW_E_WRONG_STATE;
291 else {
292 if (buffer) {
293 if (*bufSize >= This->bufferLen)
294 CopyMemory(buffer, This->bufferData, This->bufferLen);
295 else
296 ret = E_OUTOFMEMORY;
298 *bufSize = This->bufferLen;
300 LeaveCriticalSection(&This->filter.filter_cs);
301 return ret;
304 /* ISampleGrabber */
305 static HRESULT WINAPI
306 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
308 /* MS doesn't implement it either, no one should call it */
309 WARN("(%p): not implemented\n", sample);
310 return E_NOTIMPL;
313 /* ISampleGrabber */
314 static HRESULT WINAPI
315 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
317 struct sample_grabber *This = impl_from_ISampleGrabber(iface);
318 TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
319 if (This->grabberIface)
320 ISampleGrabberCB_Release(This->grabberIface);
321 This->grabberIface = cb;
322 This->grabberMethod = whichMethod;
323 if (cb)
324 ISampleGrabberCB_AddRef(cb);
325 return S_OK;
328 static HRESULT WINAPI SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID iid, void **out)
330 struct sample_grabber *filter = impl_from_IMemInputPin(iface);
331 return IPin_QueryInterface(&filter->sink.pin.IPin_iface, iid, out);
334 static ULONG WINAPI SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
336 struct sample_grabber *filter = impl_from_IMemInputPin(iface);
337 return IPin_AddRef(&filter->sink.pin.IPin_iface);
340 static ULONG WINAPI SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
342 struct sample_grabber *filter = impl_from_IMemInputPin(iface);
343 return IPin_Release(&filter->sink.pin.IPin_iface);
346 /* IMemInputPin */
347 static HRESULT WINAPI
348 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
350 struct sample_grabber *This = impl_from_IMemInputPin(iface);
351 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
352 if (!allocator)
353 return E_POINTER;
354 *allocator = This->allocator;
355 if (!*allocator)
356 return VFW_E_NO_ALLOCATOR;
357 IMemAllocator_AddRef(*allocator);
358 return S_OK;
361 /* IMemInputPin */
362 static HRESULT WINAPI
363 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
365 struct sample_grabber *This = impl_from_IMemInputPin(iface);
366 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
367 if (This->allocator == allocator)
368 return S_OK;
369 if (This->allocator)
370 IMemAllocator_Release(This->allocator);
371 This->allocator = allocator;
372 if (allocator)
373 IMemAllocator_AddRef(allocator);
374 return S_OK;
377 /* IMemInputPin */
378 static HRESULT WINAPI
379 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
381 struct sample_grabber *This = impl_from_IMemInputPin(iface);
382 FIXME("(%p)->(%p): semi-stub\n", This, props);
383 if (!props)
384 return E_POINTER;
385 return This->source.pMemInputPin ? IMemInputPin_GetAllocatorRequirements(This->source.pMemInputPin, props) : E_NOTIMPL;
388 /* IMemInputPin */
389 static HRESULT WINAPI
390 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
392 struct sample_grabber *This = impl_from_IMemInputPin(iface);
393 HRESULT hr;
394 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->source.pMemInputPin, This->grabberIface);
395 if (!sample)
396 return E_POINTER;
397 if (This->oneShot == OneShot_Past)
398 return S_FALSE;
399 SampleGrabber_callback(This, sample);
400 hr = This->source.pMemInputPin ? IMemInputPin_Receive(This->source.pMemInputPin, sample) : S_OK;
401 if (This->oneShot == OneShot_Wait) {
402 This->oneShot = OneShot_Past;
403 hr = S_FALSE;
404 if (This->source.pin.peer)
405 IPin_EndOfStream(This->source.pin.peer);
407 return hr;
410 /* IMemInputPin */
411 static HRESULT WINAPI
412 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
414 struct sample_grabber *This = impl_from_IMemInputPin(iface);
415 LONG idx;
416 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->source.pMemInputPin, This->grabberIface);
417 if (!samples || !nProcessed)
418 return E_POINTER;
419 if ((This->filter.state != State_Running) || (This->oneShot == OneShot_Past))
420 return S_FALSE;
421 for (idx = 0; idx < nSamples; idx++)
422 SampleGrabber_callback(This, samples[idx]);
423 return This->source.pMemInputPin ? IMemInputPin_ReceiveMultiple(This->source.pMemInputPin, samples, nSamples, nProcessed) : S_OK;
426 /* IMemInputPin */
427 static HRESULT WINAPI
428 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
430 struct sample_grabber *This = impl_from_IMemInputPin(iface);
431 TRACE("(%p)\n", This);
432 return This->source.pMemInputPin ? IMemInputPin_ReceiveCanBlock(This->source.pMemInputPin) : S_OK;
435 static const ISampleGrabberVtbl ISampleGrabber_VTable =
437 SampleGrabber_ISampleGrabber_QueryInterface,
438 SampleGrabber_ISampleGrabber_AddRef,
439 SampleGrabber_ISampleGrabber_Release,
440 SampleGrabber_ISampleGrabber_SetOneShot,
441 SampleGrabber_ISampleGrabber_SetMediaType,
442 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
443 SampleGrabber_ISampleGrabber_SetBufferSamples,
444 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
445 SampleGrabber_ISampleGrabber_GetCurrentSample,
446 SampleGrabber_ISampleGrabber_SetCallback,
449 static const IMemInputPinVtbl IMemInputPin_VTable =
451 SampleGrabber_IMemInputPin_QueryInterface,
452 SampleGrabber_IMemInputPin_AddRef,
453 SampleGrabber_IMemInputPin_Release,
454 SampleGrabber_IMemInputPin_GetAllocator,
455 SampleGrabber_IMemInputPin_NotifyAllocator,
456 SampleGrabber_IMemInputPin_GetAllocatorRequirements,
457 SampleGrabber_IMemInputPin_Receive,
458 SampleGrabber_IMemInputPin_ReceiveMultiple,
459 SampleGrabber_IMemInputPin_ReceiveCanBlock,
462 static struct sample_grabber *impl_from_sink_pin(struct strmbase_pin *iface)
464 return CONTAINING_RECORD(iface, struct sample_grabber, sink.pin);
467 static HRESULT sample_grabber_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
469 struct sample_grabber *filter = impl_from_sink_pin(iface);
471 if (IsEqualGUID(iid, &IID_IMemInputPin))
472 *out = &filter->IMemInputPin_iface;
473 else
474 return E_NOINTERFACE;
476 IUnknown_AddRef((IUnknown *)*out);
477 return S_OK;
480 static BOOL check_filter_mt(struct sample_grabber *filter, const AM_MEDIA_TYPE *mt)
482 if (IsEqualGUID(&filter->filter_mt.majortype, &GUID_NULL))
483 return TRUE;
484 if (!IsEqualGUID(&filter->filter_mt.majortype, &mt->majortype))
485 return FALSE;
487 if (IsEqualGUID(&filter->filter_mt.subtype, &GUID_NULL))
488 return TRUE;
489 if (!IsEqualGUID(&filter->filter_mt.subtype, &mt->subtype))
490 return FALSE;
492 if (IsEqualGUID(&filter->filter_mt.formattype, &GUID_NULL))
493 return TRUE;
494 if (!IsEqualGUID(&filter->filter_mt.formattype, &mt->formattype))
495 return FALSE;
497 return TRUE;
500 static HRESULT sample_grabber_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
502 struct sample_grabber *filter = impl_from_sink_pin(iface);
504 return check_filter_mt(filter, mt) ? S_OK : S_FALSE;
507 static HRESULT sample_grabber_sink_get_media_type(struct strmbase_pin *iface,
508 unsigned int index, AM_MEDIA_TYPE *mt)
510 struct sample_grabber *filter = impl_from_sink_pin(iface);
511 IEnumMediaTypes *enummt;
512 AM_MEDIA_TYPE *pmt;
513 HRESULT hr;
515 if (!filter->source.pin.peer)
516 return VFW_E_NOT_CONNECTED;
518 if (FAILED(hr = IPin_EnumMediaTypes(filter->source.pin.peer, &enummt)))
519 return hr;
521 if ((!index || IEnumMediaTypes_Skip(enummt, index) == S_OK)
522 && IEnumMediaTypes_Next(enummt, 1, &pmt, NULL) == S_OK)
524 CopyMediaType(mt, pmt);
525 DeleteMediaType(pmt);
526 IEnumMediaTypes_Release(enummt);
527 return S_OK;
530 IEnumMediaTypes_Release(enummt);
531 return VFW_S_NO_MORE_ITEMS;
534 static const struct strmbase_sink_ops sink_ops =
536 .base.pin_query_interface = sample_grabber_sink_query_interface,
537 .base.pin_query_accept = sample_grabber_sink_query_accept,
538 .base.pin_get_media_type = sample_grabber_sink_get_media_type,
541 static struct sample_grabber *impl_from_source_pin(struct strmbase_pin *iface)
543 return CONTAINING_RECORD(iface, struct sample_grabber, source.pin);
546 static HRESULT sample_grabber_source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
548 struct sample_grabber *filter = impl_from_source_pin(iface);
550 if (IsEqualGUID(iid, &IID_IMediaPosition))
551 *out = &filter->passthrough.IMediaPosition_iface;
552 else if (IsEqualGUID(iid, &IID_IMediaSeeking))
553 *out = &filter->passthrough.IMediaSeeking_iface;
554 else
555 return E_NOINTERFACE;
557 IUnknown_AddRef((IUnknown *)*out);
558 return S_OK;
561 static HRESULT sample_grabber_source_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt)
563 struct sample_grabber *filter = impl_from_source_pin(iface);
565 if (filter->sink.pin.peer && IPin_QueryAccept(filter->sink.pin.peer, mt) != S_OK)
566 return S_FALSE;
568 return check_filter_mt(filter, mt) ? S_OK : S_FALSE;
571 static HRESULT sample_grabber_source_get_media_type(struct strmbase_pin *iface,
572 unsigned int index, AM_MEDIA_TYPE *mt)
574 struct sample_grabber *filter = impl_from_source_pin(iface);
575 IEnumMediaTypes *enummt;
576 AM_MEDIA_TYPE *pmt;
577 HRESULT hr;
579 if (!filter->sink.pin.peer)
580 return VFW_E_NOT_CONNECTED;
582 if (FAILED(hr = IPin_EnumMediaTypes(filter->sink.pin.peer, &enummt)))
583 return hr;
585 if ((!index || IEnumMediaTypes_Skip(enummt, index) == S_OK)
586 && IEnumMediaTypes_Next(enummt, 1, &pmt, NULL) == S_OK)
588 CopyMediaType(mt, pmt);
589 DeleteMediaType(pmt);
590 IEnumMediaTypes_Release(enummt);
591 return S_OK;
594 IEnumMediaTypes_Release(enummt);
595 return VFW_S_NO_MORE_ITEMS;
598 static inline BOOL compare_media_types(const AM_MEDIA_TYPE *a, const AM_MEDIA_TYPE *b)
600 return !memcmp(a, b, offsetof(AM_MEDIA_TYPE, pbFormat))
601 && !memcmp(a->pbFormat, b->pbFormat, a->cbFormat);
604 static HRESULT WINAPI sample_grabber_source_DecideAllocator(struct strmbase_source *iface,
605 IMemInputPin *peer, IMemAllocator **allocator)
607 struct sample_grabber *filter = impl_from_source_pin(&iface->pin);
608 const AM_MEDIA_TYPE *mt = &iface->pin.mt;
610 if (!compare_media_types(mt, &filter->sink.pin.mt))
612 IFilterGraph2 *graph;
613 HRESULT hr;
615 if (FAILED(hr = IFilterGraph_QueryInterface(filter->filter.graph,
616 &IID_IFilterGraph2, (void **)&graph)))
618 ERR("Failed to get IFilterGraph2 interface, hr %#x.\n", hr);
619 return hr;
622 hr = IFilterGraph2_ReconnectEx(graph, &filter->sink.pin.IPin_iface, mt);
623 IFilterGraph2_Release(graph);
624 return hr;
627 return S_OK;
630 static const struct strmbase_source_ops source_ops =
632 .base.pin_query_interface = sample_grabber_source_query_interface,
633 .base.pin_query_accept = sample_grabber_source_query_accept,
634 .base.pin_get_media_type = sample_grabber_source_get_media_type,
635 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
636 .pfnDecideAllocator = sample_grabber_source_DecideAllocator,
639 HRESULT sample_grabber_create(IUnknown *outer, IUnknown **out)
641 struct sample_grabber *object;
643 if (!(object = calloc(1, sizeof(*object))))
644 return E_OUTOFMEMORY;
646 strmbase_filter_init(&object->filter, outer, &CLSID_SampleGrabber, &filter_ops);
647 object->ISampleGrabber_iface.lpVtbl = &ISampleGrabber_VTable;
648 object->IMemInputPin_iface.lpVtbl = &IMemInputPin_VTable;
650 strmbase_sink_init(&object->sink, &object->filter, L"In", &sink_ops, NULL);
652 strmbase_source_init(&object->source, &object->filter, L"Out", &source_ops);
653 strmbase_passthrough_init(&object->passthrough, (IUnknown *)&object->source.pin.IPin_iface);
654 ISeekingPassThru_Init(&object->passthrough.ISeekingPassThru_iface, FALSE,
655 &object->sink.pin.IPin_iface);
657 object->grabberMethod = -1;
658 object->oneShot = OneShot_None;
659 object->bufferLen = -1;
661 TRACE("Created sample grabber %p.\n", object);
662 *out = &object->filter.IUnknown_inner;
663 return S_OK;