ole32: Add more traces to the storage methods.
[wine/multimedia.git] / dlls / qedit / samplegrabber.c
blobe9e49061c8bd8b424785d7cd17fd50e0106cd465
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, BOOL past);
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;
51 /* IEnumMediaTypes interface implementation */
53 static inline ME_Impl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
55 return CONTAINING_RECORD(iface, ME_Impl, IEnumMediaTypes_iface);
58 static HRESULT WINAPI Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes *iface, REFIID riid,
59 void **ret_iface)
61 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
63 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ret_iface);
65 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumMediaTypes)) {
66 *ret_iface = iface;
67 IEnumMediaTypes_AddRef(iface);
68 return S_OK;
70 *ret_iface = NULL;
71 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ret_iface);
72 return E_NOINTERFACE;
75 static ULONG WINAPI Single_IEnumMediaTypes_AddRef(IEnumMediaTypes *iface)
77 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
78 ULONG refCount = InterlockedIncrement(&This->refCount);
80 TRACE("(%p) new ref = %u\n", This, refCount);
81 return refCount;
84 static ULONG WINAPI Single_IEnumMediaTypes_Release(IEnumMediaTypes *iface)
86 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
87 ULONG refCount = InterlockedDecrement(&This->refCount);
89 TRACE("(%p) new ref = %u\n", This, refCount);
90 if (refCount == 0)
92 if (This->mtype.pbFormat)
93 CoTaskMemFree(This->mtype.pbFormat);
94 CoTaskMemFree(This);
95 return 0;
97 return refCount;
100 /* IEnumMediaTypes */
101 static HRESULT WINAPI Single_IEnumMediaTypes_Next(IEnumMediaTypes *iface, ULONG nTypes,
102 AM_MEDIA_TYPE **types, ULONG *fetched)
104 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
105 ULONG count = 0;
107 TRACE("(%p)->(%u, %p, %p)\n", This, nTypes, types, fetched);
108 if (!nTypes)
109 return E_INVALIDARG;
110 if (!types || ((nTypes != 1) && !fetched))
111 return E_POINTER;
112 if (!This->past && !IsEqualGUID(&This->mtype.majortype,&GUID_NULL)) {
113 AM_MEDIA_TYPE *mtype = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
114 *mtype = This->mtype;
115 if (mtype->cbFormat) {
116 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
117 CopyMemory(mtype->pbFormat, This->mtype.pbFormat, mtype->cbFormat);
119 *types = mtype;
120 This->past = TRUE;
121 count = 1;
123 if (fetched)
124 *fetched = count;
125 return (count == nTypes) ? S_OK : S_FALSE;
128 static HRESULT WINAPI Single_IEnumMediaTypes_Skip(IEnumMediaTypes *iface, ULONG nTypes)
130 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
132 TRACE("(%p)->(%u)\n", This, nTypes);
133 if (nTypes)
134 This->past = TRUE;
135 return This->past ? S_FALSE : S_OK;
138 static HRESULT WINAPI Single_IEnumMediaTypes_Reset(IEnumMediaTypes *iface)
140 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
142 TRACE("(%p)->()\n", This);
143 This->past = FALSE;
144 return S_OK;
147 static HRESULT WINAPI Single_IEnumMediaTypes_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **me)
149 ME_Impl *This = impl_from_IEnumMediaTypes(iface);
151 TRACE("(%p)->(%p)\n", This, me);
152 if (!me)
153 return E_POINTER;
154 *me = mediaenum_create(&This->mtype, This->past);
155 if (!*me)
156 return E_OUTOFMEMORY;
157 return S_OK;
161 /* Virtual tables and constructor */
163 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable =
165 Single_IEnumMediaTypes_QueryInterface,
166 Single_IEnumMediaTypes_AddRef,
167 Single_IEnumMediaTypes_Release,
168 Single_IEnumMediaTypes_Next,
169 Single_IEnumMediaTypes_Skip,
170 Single_IEnumMediaTypes_Reset,
171 Single_IEnumMediaTypes_Clone,
174 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype, BOOL past)
176 ME_Impl *obj = CoTaskMemAlloc(sizeof(ME_Impl));
178 if (!obj)
179 return NULL;
180 ZeroMemory(obj, sizeof(*obj));
181 obj->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypes_VTable;
182 obj->refCount = 1;
183 obj->past = past;
184 if (mtype) {
185 obj->mtype = *mtype;
186 obj->mtype.pUnk = NULL;
187 if (mtype->cbFormat) {
188 obj->mtype.pbFormat = CoTaskMemAlloc(mtype->cbFormat);
189 CopyMemory(obj->mtype.pbFormat, mtype->pbFormat, mtype->cbFormat);
191 else
192 obj->mtype.pbFormat = NULL;
194 else
195 obj->mtype.majortype = GUID_NULL;
197 return &obj->IEnumMediaTypes_iface;
201 /* Sample Grabber pin implementation */
202 typedef struct _SG_Pin {
203 IPin IPin_iface;
204 PIN_DIRECTION dir;
205 WCHAR const *name;
206 struct _SG_Impl *sg;
207 IPin *pair;
208 } SG_Pin;
210 static inline SG_Pin *impl_from_IPin(IPin *iface)
212 return CONTAINING_RECORD(iface, SG_Pin, IPin_iface);
215 /* Sample Grabber filter implementation */
216 typedef struct _SG_Impl {
217 IUnknown IUnknown_inner;
218 BaseFilter filter;
219 ISampleGrabber ISampleGrabber_iface;
220 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
221 IUnknown* seekthru_unk;
222 IUnknown *outer_unk;
223 AM_MEDIA_TYPE mtype;
224 SG_Pin pin_in;
225 SG_Pin pin_out;
226 IMemInputPin IMemInputPin_iface;
227 IMemAllocator *allocator;
228 IMemInputPin *memOutput;
229 ISampleGrabberCB *grabberIface;
230 LONG grabberMethod;
231 LONG oneShot;
232 LONG bufferLen;
233 void* bufferData;
234 } SG_Impl;
236 enum {
237 OneShot_None,
238 OneShot_Wait,
239 OneShot_Past,
242 static inline SG_Impl *impl_from_IUnknown(IUnknown *iface)
244 return CONTAINING_RECORD(iface, SG_Impl, IUnknown_inner);
247 static inline SG_Impl *impl_from_BaseFilter(BaseFilter *iface)
249 return CONTAINING_RECORD(iface, SG_Impl, filter);
252 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
254 return CONTAINING_RECORD(iface, SG_Impl, filter.IBaseFilter_iface);
257 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
259 return CONTAINING_RECORD(iface, SG_Impl, ISampleGrabber_iface);
262 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface)
264 return CONTAINING_RECORD(iface, SG_Impl, IMemInputPin_iface);
268 /* Cleanup at end of life */
269 static void SampleGrabber_cleanup(SG_Impl *This)
271 TRACE("(%p)\n", This);
272 if (This->filter.filterInfo.pGraph)
273 WARN("(%p) still joined to filter graph %p\n", This, This->filter.filterInfo.pGraph);
274 if (This->allocator)
275 IMemAllocator_Release(This->allocator);
276 if (This->memOutput)
277 IMemInputPin_Release(This->memOutput);
278 if (This->grabberIface)
279 ISampleGrabberCB_Release(This->grabberIface);
280 if (This->mtype.pbFormat)
281 CoTaskMemFree(This->mtype.pbFormat);
282 if (This->bufferData)
283 CoTaskMemFree(This->bufferData);
284 if(This->seekthru_unk)
285 IUnknown_Release(This->seekthru_unk);
288 /* SampleGrabber inner IUnknown */
289 static HRESULT WINAPI SampleGrabber_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
291 SG_Impl *This = impl_from_IUnknown(iface);
293 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
295 *ppv = NULL;
296 if (IsEqualIID(riid, &IID_IUnknown))
297 *ppv = &This->IUnknown_inner;
298 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IMediaFilter) ||
299 IsEqualIID(riid, &IID_IBaseFilter))
300 *ppv = &This->filter.IBaseFilter_iface;
301 else if (IsEqualIID(riid, &IID_ISampleGrabber))
302 *ppv = &This->ISampleGrabber_iface;
303 else if (IsEqualIID(riid, &IID_IMediaPosition))
304 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
305 else if (IsEqualIID(riid, &IID_IMediaSeeking))
306 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
307 else
308 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
310 if (!*ppv)
311 return E_NOINTERFACE;
313 IUnknown_AddRef((IUnknown*)*ppv);
314 return S_OK;
317 static ULONG WINAPI SampleGrabber_AddRef(IUnknown *iface)
319 SG_Impl *This = impl_from_IUnknown(iface);
320 ULONG ref = BaseFilterImpl_AddRef(&This->filter.IBaseFilter_iface);
322 TRACE("(%p) ref=%d\n", This, ref);
324 return ref;
327 static ULONG WINAPI SampleGrabber_Release(IUnknown *iface)
329 SG_Impl *This = impl_from_IUnknown(iface);
330 ULONG ref = BaseFilterImpl_Release(&This->filter.IBaseFilter_iface);
332 TRACE("(%p) ref=%d\n", This, ref);
334 if (ref == 0)
336 SampleGrabber_cleanup(This);
337 CoTaskMemFree(This);
338 return 0;
340 return ref;
343 static const IUnknownVtbl samplegrabber_vtbl =
345 SampleGrabber_QueryInterface,
346 SampleGrabber_AddRef,
347 SampleGrabber_Release,
350 static IPin *WINAPI SampleGrabber_GetPin(BaseFilter *iface, int pos)
352 SG_Impl *This = impl_from_BaseFilter(iface);
353 IPin *pin;
355 if (pos == 0)
356 pin = &This->pin_in.IPin_iface;
357 else if (pos == 1)
358 pin = &This->pin_out.IPin_iface;
359 else
360 return NULL;
362 IPin_AddRef(pin);
363 return pin;
366 static LONG WINAPI SampleGrabber_GetPinCount(BaseFilter *iface)
368 return 2;
371 static const BaseFilterFuncTable basefunc_vtbl = {
372 SampleGrabber_GetPin,
373 SampleGrabber_GetPinCount
376 /* Helper that buffers data and/or calls installed sample callbacks */
377 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
379 double time = 0.0;
380 REFERENCE_TIME tStart, tEnd;
381 if (This->bufferLen >= 0) {
382 BYTE *data = 0;
383 LONG size = IMediaSample_GetActualDataLength(sample);
384 if (size >= 0 && SUCCEEDED(IMediaSample_GetPointer(sample, &data))) {
385 if (!data)
386 size = 0;
387 EnterCriticalSection(&This->filter.csFilter);
388 if (This->bufferLen != size) {
389 if (This->bufferData)
390 CoTaskMemFree(This->bufferData);
391 This->bufferData = size ? CoTaskMemAlloc(size) : NULL;
392 This->bufferLen = size;
394 if (size)
395 CopyMemory(This->bufferData, data, size);
396 LeaveCriticalSection(&This->filter.csFilter);
399 if (!This->grabberIface)
400 return;
401 if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
402 time = 1e-7 * tStart;
403 switch (This->grabberMethod) {
404 case 0:
406 ULONG ref = IMediaSample_AddRef(sample);
407 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
408 ref = IMediaSample_Release(sample) + 1 - ref;
409 if (ref)
411 ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref);
412 /* ugly as hell but some apps are sooo buggy */
413 while (ref--)
414 IMediaSample_Release(sample);
417 break;
418 case 1:
420 BYTE *data = 0;
421 LONG size = IMediaSample_GetActualDataLength(sample);
422 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
423 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
425 break;
426 case -1:
427 break;
428 default:
429 FIXME("unsupported method %d\n", This->grabberMethod);
430 /* do not bother us again */
431 This->grabberMethod = -1;
436 /* SampleGrabber implementation of IBaseFilter interface */
438 /* IUnknown */
439 static HRESULT WINAPI
440 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)
442 SG_Impl *This = impl_from_IBaseFilter(iface);
443 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
446 /* IUnknown */
447 static ULONG WINAPI
448 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
450 SG_Impl *This = impl_from_IBaseFilter(iface);
451 return IUnknown_AddRef(This->outer_unk);
454 /* IUnknown */
455 static ULONG WINAPI
456 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
458 SG_Impl *This = impl_from_IBaseFilter(iface);
459 return IUnknown_Release(This->outer_unk);
462 /* IMediaFilter */
463 static HRESULT WINAPI
464 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
466 SG_Impl *This = impl_from_IBaseFilter(iface);
467 TRACE("(%p)\n", This);
468 This->filter.state = State_Stopped;
469 return S_OK;
472 /* IMediaFilter */
473 static HRESULT WINAPI
474 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
476 SG_Impl *This = impl_from_IBaseFilter(iface);
477 TRACE("(%p)\n", This);
478 This->filter.state = State_Paused;
479 return S_OK;
482 /* IMediaFilter */
483 static HRESULT WINAPI
484 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
486 SG_Impl *This = impl_from_IBaseFilter(iface);
487 TRACE("(%p)\n", This);
488 This->filter.state = State_Running;
489 return S_OK;
492 /* IBaseFilter */
493 static HRESULT WINAPI
494 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
496 SG_Impl *This = impl_from_IBaseFilter(iface);
497 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin);
498 if (!id || !pin)
499 return E_POINTER;
500 if (!lstrcmpiW(id,pin_in_name))
502 *pin = &This->pin_in.IPin_iface;
503 IPin_AddRef(*pin);
504 return S_OK;
506 else if (!lstrcmpiW(id,pin_out_name))
508 *pin = &This->pin_out.IPin_iface;
509 IPin_AddRef(*pin);
510 return S_OK;
512 *pin = NULL;
513 return VFW_E_NOT_FOUND;
516 /* IBaseFilter */
517 static HRESULT WINAPI
518 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
520 SG_Impl *This = impl_from_IBaseFilter(iface);
522 TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
524 BaseFilterImpl_JoinFilterGraph(iface, graph, name);
525 This->oneShot = OneShot_None;
527 return S_OK;
530 /* IBaseFilter */
531 static HRESULT WINAPI
532 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
534 TRACE("(%p)\n", vendor);
535 if (!vendor)
536 return E_POINTER;
537 *vendor = CoTaskMemAlloc(sizeof(vendor_name));
538 CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
539 return S_OK;
543 /* SampleGrabber implementation of ISampleGrabber interface */
545 /* IUnknown */
546 static HRESULT WINAPI
547 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv)
549 SG_Impl *This = impl_from_ISampleGrabber(iface);
550 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
553 /* IUnknown */
554 static ULONG WINAPI
555 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
557 SG_Impl *This = impl_from_ISampleGrabber(iface);
558 return IUnknown_AddRef(This->outer_unk);
561 /* IUnknown */
562 static ULONG WINAPI
563 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
565 SG_Impl *This = impl_from_ISampleGrabber(iface);
566 return IUnknown_Release(This->outer_unk);
569 /* ISampleGrabber */
570 static HRESULT WINAPI
571 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
573 SG_Impl *This = impl_from_ISampleGrabber(iface);
574 TRACE("(%p)->(%u)\n", This, oneShot);
575 This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
576 return S_OK;
579 /* ISampleGrabber */
580 static HRESULT WINAPI
581 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
583 SG_Impl *This = impl_from_ISampleGrabber(iface);
584 TRACE("(%p)->(%p)\n", This, type);
585 if (!type)
586 return E_POINTER;
587 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
588 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
589 type->lSampleSize,
590 debugstr_guid(&type->formattype), type->cbFormat);
591 if (This->mtype.pbFormat)
592 CoTaskMemFree(This->mtype.pbFormat);
593 This->mtype = *type;
594 This->mtype.pUnk = NULL;
595 if (type->cbFormat) {
596 This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
597 CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat);
599 else
600 This->mtype.pbFormat = NULL;
601 return S_OK;
604 /* ISampleGrabber */
605 static HRESULT WINAPI
606 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
608 SG_Impl *This = impl_from_ISampleGrabber(iface);
609 TRACE("(%p)->(%p)\n", This, type);
610 if (!type)
611 return E_POINTER;
612 if (!This->pin_in.pair)
613 return VFW_E_NOT_CONNECTED;
614 *type = This->mtype;
615 if (type->cbFormat) {
616 type->pbFormat = CoTaskMemAlloc(type->cbFormat);
617 CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat);
619 return S_OK;
622 /* ISampleGrabber */
623 static HRESULT WINAPI
624 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
626 SG_Impl *This = impl_from_ISampleGrabber(iface);
627 TRACE("(%p)->(%u)\n", This, bufferEm);
628 EnterCriticalSection(&This->filter.csFilter);
629 if (bufferEm) {
630 if (This->bufferLen < 0)
631 This->bufferLen = 0;
633 else
634 This->bufferLen = -1;
635 LeaveCriticalSection(&This->filter.csFilter);
636 return S_OK;
639 /* ISampleGrabber */
640 static HRESULT WINAPI
641 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
643 SG_Impl *This = impl_from_ISampleGrabber(iface);
644 HRESULT ret = S_OK;
645 TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer);
646 if (!bufSize)
647 return E_POINTER;
648 EnterCriticalSection(&This->filter.csFilter);
649 if (!This->pin_in.pair)
650 ret = VFW_E_NOT_CONNECTED;
651 else if (This->bufferLen < 0)
652 ret = E_INVALIDARG;
653 else if (This->bufferLen == 0)
654 ret = VFW_E_WRONG_STATE;
655 else {
656 if (buffer) {
657 if (*bufSize >= This->bufferLen)
658 CopyMemory(buffer, This->bufferData, This->bufferLen);
659 else
660 ret = E_OUTOFMEMORY;
662 *bufSize = This->bufferLen;
664 LeaveCriticalSection(&This->filter.csFilter);
665 return ret;
668 /* ISampleGrabber */
669 static HRESULT WINAPI
670 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
672 /* MS doesn't implement it either, no one should call it */
673 WARN("(%p): not implemented\n", sample);
674 return E_NOTIMPL;
677 /* ISampleGrabber */
678 static HRESULT WINAPI
679 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
681 SG_Impl *This = impl_from_ISampleGrabber(iface);
682 TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
683 if (This->grabberIface)
684 ISampleGrabberCB_Release(This->grabberIface);
685 This->grabberIface = cb;
686 This->grabberMethod = whichMethod;
687 if (cb)
688 ISampleGrabberCB_AddRef(cb);
689 return S_OK;
693 /* SampleGrabber implementation of IMemInputPin interface */
695 /* IUnknown */
696 static HRESULT WINAPI
697 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv)
699 SG_Impl *This = impl_from_IMemInputPin(iface);
700 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
703 /* IUnknown */
704 static ULONG WINAPI
705 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
707 SG_Impl *This = impl_from_IMemInputPin(iface);
708 return IUnknown_AddRef(This->outer_unk);
711 /* IUnknown */
712 static ULONG WINAPI
713 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
715 SG_Impl *This = impl_from_IMemInputPin(iface);
716 return IUnknown_Release(This->outer_unk);
719 /* IMemInputPin */
720 static HRESULT WINAPI
721 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
723 SG_Impl *This = impl_from_IMemInputPin(iface);
724 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
725 if (!allocator)
726 return E_POINTER;
727 *allocator = This->allocator;
728 if (!*allocator)
729 return VFW_E_NO_ALLOCATOR;
730 IMemAllocator_AddRef(*allocator);
731 return S_OK;
734 /* IMemInputPin */
735 static HRESULT WINAPI
736 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
738 SG_Impl *This = impl_from_IMemInputPin(iface);
739 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
740 if (This->allocator == allocator)
741 return S_OK;
742 if (This->allocator)
743 IMemAllocator_Release(This->allocator);
744 This->allocator = allocator;
745 if (allocator)
746 IMemAllocator_AddRef(allocator);
747 return S_OK;
750 /* IMemInputPin */
751 static HRESULT WINAPI
752 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
754 SG_Impl *This = impl_from_IMemInputPin(iface);
755 FIXME("(%p)->(%p): semi-stub\n", This, props);
756 if (!props)
757 return E_POINTER;
758 return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL;
761 /* IMemInputPin */
762 static HRESULT WINAPI
763 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
765 SG_Impl *This = impl_from_IMemInputPin(iface);
766 HRESULT hr;
767 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface);
768 if (!sample)
769 return E_POINTER;
770 if ((This->filter.state != State_Running) || (This->oneShot == OneShot_Past))
771 return S_FALSE;
772 SampleGrabber_callback(This, sample);
773 hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK;
774 if (This->oneShot == OneShot_Wait) {
775 This->oneShot = OneShot_Past;
776 hr = S_FALSE;
777 if (This->pin_out.pair)
778 IPin_EndOfStream(This->pin_out.pair);
780 return hr;
783 /* IMemInputPin */
784 static HRESULT WINAPI
785 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
787 SG_Impl *This = impl_from_IMemInputPin(iface);
788 LONG idx;
789 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface);
790 if (!samples || !nProcessed)
791 return E_POINTER;
792 if ((This->filter.state != State_Running) || (This->oneShot == OneShot_Past))
793 return S_FALSE;
794 for (idx = 0; idx < nSamples; idx++)
795 SampleGrabber_callback(This, samples[idx]);
796 return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK;
799 /* IMemInputPin */
800 static HRESULT WINAPI
801 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
803 SG_Impl *This = impl_from_IMemInputPin(iface);
804 TRACE("(%p)\n", This);
805 return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK;
809 /* SampleGrabber member pin implementation */
811 /* IUnknown */
812 static ULONG WINAPI
813 SampleGrabber_IPin_AddRef(IPin *iface)
815 SG_Pin *This = impl_from_IPin(iface);
816 return ISampleGrabber_AddRef(&This->sg->ISampleGrabber_iface);
819 /* IUnknown */
820 static ULONG WINAPI
821 SampleGrabber_IPin_Release(IPin *iface)
823 SG_Pin *This = impl_from_IPin(iface);
824 return ISampleGrabber_Release(&This->sg->ISampleGrabber_iface);
827 /* IUnknown */
828 static HRESULT WINAPI
829 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
831 SG_Pin *This = impl_from_IPin(iface);
832 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
834 *ppv = NULL;
835 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
836 *ppv = iface;
837 else if (IsEqualIID(riid, &IID_IMemInputPin))
838 *ppv = &This->sg->IMemInputPin_iface;
839 else if (IsEqualIID(riid, &IID_IMediaSeeking))
840 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
841 else if (IsEqualIID(riid, &IID_IMediaPosition))
842 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
843 else {
844 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
845 return E_NOINTERFACE;
848 IUnknown_AddRef((IUnknown*)*ppv);
849 return S_OK;
852 /* IPin - input pin */
853 static HRESULT WINAPI
854 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype)
856 WARN("(%p, %p): unexpected\n", receiver, mtype);
857 return E_UNEXPECTED;
860 /* IPin - output pin */
861 static HRESULT WINAPI
862 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type)
864 SG_Pin *This = impl_from_IPin(iface);
865 HRESULT hr;
867 TRACE("(%p)->(%p, %p)\n", This, receiver, type);
868 if (!receiver)
869 return E_POINTER;
870 if (This->pair)
871 return VFW_E_ALREADY_CONNECTED;
872 if (This->sg->filter.state != State_Stopped)
873 return VFW_E_NOT_STOPPED;
874 if (type) {
875 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
876 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
877 type->lSampleSize,
878 debugstr_guid(&type->formattype), type->cbFormat);
879 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
880 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
881 return VFW_E_TYPE_NOT_ACCEPTED;
882 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
883 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
884 return VFW_E_TYPE_NOT_ACCEPTED;
885 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
886 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
887 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
888 return VFW_E_TYPE_NOT_ACCEPTED;
890 else
891 type = &This->sg->mtype;
892 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
893 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
894 !type->pbFormat)
895 return VFW_E_TYPE_NOT_ACCEPTED;
896 hr = IPin_ReceiveConnection(receiver, &This->IPin_iface, type);
897 if (FAILED(hr))
898 return hr;
899 This->pair = receiver;
900 if (This->sg->memOutput) {
901 IMemInputPin_Release(This->sg->memOutput);
902 This->sg->memOutput = NULL;
904 IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput));
905 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput);
906 return S_OK;
909 /* IPin - input pin */
910 static HRESULT WINAPI
911 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type)
913 SG_Pin *This = impl_from_IPin(iface);
915 TRACE("(%p)->(%p, %p)\n", This, connector, type);
916 if (!connector)
917 return E_POINTER;
918 if (This->pair)
919 return VFW_E_ALREADY_CONNECTED;
920 if (This->sg->filter.state != State_Stopped)
921 return VFW_E_NOT_STOPPED;
922 if (type) {
923 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
924 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
925 type->lSampleSize,
926 debugstr_guid(&type->formattype), type->cbFormat);
927 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
928 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
929 !type->pbFormat)
930 return VFW_E_INVALIDMEDIATYPE;
931 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
932 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
933 return VFW_E_TYPE_NOT_ACCEPTED;
934 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
935 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
936 return VFW_E_TYPE_NOT_ACCEPTED;
937 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
938 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
939 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
940 return VFW_E_TYPE_NOT_ACCEPTED;
941 if (This->sg->mtype.pbFormat)
942 CoTaskMemFree(This->sg->mtype.pbFormat);
943 This->sg->mtype = *type;
944 This->sg->mtype.pUnk = NULL;
945 if (type->cbFormat) {
946 This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
947 CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat);
949 else
950 This->sg->mtype.pbFormat = NULL;
952 This->pair = connector;
953 TRACE("(%p) Accepted IPin %p\n", This, connector);
954 return S_OK;
957 /* IPin - output pin */
958 static HRESULT WINAPI
959 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype)
961 WARN("(%p, %p): unexpected\n", connector, mtype);
962 return E_UNEXPECTED;
965 /* IPin - input pin */
966 static HRESULT WINAPI
967 SampleGrabber_In_IPin_Disconnect(IPin *iface)
969 SG_Pin *This = impl_from_IPin(iface);
971 TRACE("(%p)->() pair = %p\n", This, This->pair);
972 if (This->sg->filter.state != State_Stopped)
973 return VFW_E_NOT_STOPPED;
974 if (This->pair) {
975 This->pair = NULL;
976 return S_OK;
978 return S_FALSE;
981 /* IPin - output pin */
982 static HRESULT WINAPI
983 SampleGrabber_Out_IPin_Disconnect(IPin *iface)
985 SG_Pin *This = impl_from_IPin(iface);
987 TRACE("(%p)->() pair = %p\n", This, This->pair);
988 if (This->sg->filter.state != State_Stopped)
989 return VFW_E_NOT_STOPPED;
990 if (This->pair) {
991 This->pair = NULL;
992 if (This->sg->memOutput) {
993 IMemInputPin_Release(This->sg->memOutput);
994 This->sg->memOutput = NULL;
996 return S_OK;
998 return S_FALSE;
1001 /* IPin */
1002 static HRESULT WINAPI
1003 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin)
1005 SG_Pin *This = impl_from_IPin(iface);
1007 TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair);
1008 if (!pin)
1009 return E_POINTER;
1010 *pin = This->pair;
1011 if (*pin) {
1012 IPin_AddRef(*pin);
1013 return S_OK;
1015 return VFW_E_NOT_CONNECTED;
1018 /* IPin */
1019 static HRESULT WINAPI
1020 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype)
1022 SG_Pin *This = impl_from_IPin(iface);
1024 TRACE("(%p)->(%p)\n", This, mtype);
1025 if (!mtype)
1026 return E_POINTER;
1027 if (!This->pair)
1028 return VFW_E_NOT_CONNECTED;
1029 *mtype = This->sg->mtype;
1030 if (mtype->cbFormat) {
1031 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
1032 CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat);
1034 return S_OK;
1037 /* IPin */
1038 static HRESULT WINAPI
1039 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info)
1041 SG_Pin *This = impl_from_IPin(iface);
1043 TRACE("(%p)->(%p)\n", This, info);
1044 if (!info)
1045 return E_POINTER;
1046 info->pFilter = &This->sg->filter.IBaseFilter_iface;
1047 IBaseFilter_AddRef(info->pFilter);
1048 info->dir = This->dir;
1049 lstrcpynW(info->achName,This->name,MAX_PIN_NAME);
1050 return S_OK;
1053 /* IPin */
1054 static HRESULT WINAPI
1055 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1057 SG_Pin *This = impl_from_IPin(iface);
1059 TRACE("(%p)->(%p)\n", This, dir);
1060 if (!dir)
1061 return E_POINTER;
1062 *dir = This->dir;
1063 return S_OK;
1066 /* IPin */
1067 static HRESULT WINAPI
1068 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id)
1070 SG_Pin *This = impl_from_IPin(iface);
1072 int len;
1073 TRACE("(%p)->(%p)\n", This, id);
1074 if (!id)
1075 return E_POINTER;
1076 len = sizeof(WCHAR)*(1+lstrlenW(This->name));
1077 *id = CoTaskMemAlloc(len);
1078 CopyMemory(*id, This->name, len);
1079 return S_OK;
1082 /* IPin */
1083 static HRESULT WINAPI
1084 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype)
1086 TRACE("(%p)\n", mtype);
1087 return S_OK;
1090 /* IPin */
1091 static HRESULT WINAPI
1092 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes)
1094 SG_Pin *This = impl_from_IPin(iface);
1096 TRACE("(%p)->(%p)\n", This, mtypes);
1097 if (!mtypes)
1098 return E_POINTER;
1099 *mtypes = mediaenum_create(This->sg->pin_in.pair ? &This->sg->mtype : NULL, FALSE);
1100 return *mtypes ? S_OK : E_OUTOFMEMORY;
1103 /* IPin - input pin */
1104 static HRESULT WINAPI
1105 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1107 SG_Pin *This = impl_from_IPin(iface);
1109 TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0));
1110 if (!nPins)
1111 return E_POINTER;
1112 if (*nPins) {
1113 if (!pins)
1114 return E_POINTER;
1115 IPin_AddRef(&This->sg->pin_out.IPin_iface);
1116 *pins = &This->sg->pin_out.IPin_iface;
1117 *nPins = 1;
1118 return S_OK;
1120 *nPins = 1;
1121 return S_FALSE;
1124 /* IPin - output pin */
1125 static HRESULT WINAPI
1126 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1128 WARN("(%p, %p): unexpected\n", pins, nPins);
1129 if (nPins)
1130 *nPins = 0;
1131 return E_NOTIMPL;
1134 /* IPin */
1135 static HRESULT WINAPI
1136 SampleGrabber_IPin_EndOfStream(IPin *iface)
1138 FIXME(": stub\n");
1139 return S_OK;
1142 /* IPin */
1143 static HRESULT WINAPI
1144 SampleGrabber_IPin_BeginFlush(IPin *iface)
1146 FIXME(": stub\n");
1147 return S_OK;
1150 /* IPin */
1151 static HRESULT WINAPI
1152 SampleGrabber_IPin_EndFlush(IPin *iface)
1154 FIXME(": stub\n");
1155 return S_OK;
1158 /* IPin */
1159 static HRESULT WINAPI
1160 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate)
1162 FIXME(": stub\n");
1163 return S_OK;
1167 /* SampleGrabber vtables and constructor */
1169 static const IBaseFilterVtbl IBaseFilter_VTable =
1171 SampleGrabber_IBaseFilter_QueryInterface,
1172 SampleGrabber_IBaseFilter_AddRef,
1173 SampleGrabber_IBaseFilter_Release,
1174 BaseFilterImpl_GetClassID,
1175 SampleGrabber_IBaseFilter_Stop,
1176 SampleGrabber_IBaseFilter_Pause,
1177 SampleGrabber_IBaseFilter_Run,
1178 BaseFilterImpl_GetState,
1179 BaseFilterImpl_SetSyncSource,
1180 BaseFilterImpl_GetSyncSource,
1181 BaseFilterImpl_EnumPins,
1182 SampleGrabber_IBaseFilter_FindPin,
1183 BaseFilterImpl_QueryFilterInfo,
1184 SampleGrabber_IBaseFilter_JoinFilterGraph,
1185 SampleGrabber_IBaseFilter_QueryVendorInfo,
1188 static const ISampleGrabberVtbl ISampleGrabber_VTable =
1190 SampleGrabber_ISampleGrabber_QueryInterface,
1191 SampleGrabber_ISampleGrabber_AddRef,
1192 SampleGrabber_ISampleGrabber_Release,
1193 SampleGrabber_ISampleGrabber_SetOneShot,
1194 SampleGrabber_ISampleGrabber_SetMediaType,
1195 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
1196 SampleGrabber_ISampleGrabber_SetBufferSamples,
1197 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
1198 SampleGrabber_ISampleGrabber_GetCurrentSample,
1199 SampleGrabber_ISampleGrabber_SetCallback,
1202 static const IMemInputPinVtbl IMemInputPin_VTable =
1204 SampleGrabber_IMemInputPin_QueryInterface,
1205 SampleGrabber_IMemInputPin_AddRef,
1206 SampleGrabber_IMemInputPin_Release,
1207 SampleGrabber_IMemInputPin_GetAllocator,
1208 SampleGrabber_IMemInputPin_NotifyAllocator,
1209 SampleGrabber_IMemInputPin_GetAllocatorRequirements,
1210 SampleGrabber_IMemInputPin_Receive,
1211 SampleGrabber_IMemInputPin_ReceiveMultiple,
1212 SampleGrabber_IMemInputPin_ReceiveCanBlock,
1215 static const IPinVtbl IPin_In_VTable =
1217 SampleGrabber_IPin_QueryInterface,
1218 SampleGrabber_IPin_AddRef,
1219 SampleGrabber_IPin_Release,
1220 SampleGrabber_In_IPin_Connect,
1221 SampleGrabber_In_IPin_ReceiveConnection,
1222 SampleGrabber_In_IPin_Disconnect,
1223 SampleGrabber_IPin_ConnectedTo,
1224 SampleGrabber_IPin_ConnectionMediaType,
1225 SampleGrabber_IPin_QueryPinInfo,
1226 SampleGrabber_IPin_QueryDirection,
1227 SampleGrabber_IPin_QueryId,
1228 SampleGrabber_IPin_QueryAccept,
1229 SampleGrabber_IPin_EnumMediaTypes,
1230 SampleGrabber_In_IPin_QueryInternalConnections,
1231 SampleGrabber_IPin_EndOfStream,
1232 SampleGrabber_IPin_BeginFlush,
1233 SampleGrabber_IPin_EndFlush,
1234 SampleGrabber_IPin_NewSegment,
1237 static const IPinVtbl IPin_Out_VTable =
1239 SampleGrabber_IPin_QueryInterface,
1240 SampleGrabber_IPin_AddRef,
1241 SampleGrabber_IPin_Release,
1242 SampleGrabber_Out_IPin_Connect,
1243 SampleGrabber_Out_IPin_ReceiveConnection,
1244 SampleGrabber_Out_IPin_Disconnect,
1245 SampleGrabber_IPin_ConnectedTo,
1246 SampleGrabber_IPin_ConnectionMediaType,
1247 SampleGrabber_IPin_QueryPinInfo,
1248 SampleGrabber_IPin_QueryDirection,
1249 SampleGrabber_IPin_QueryId,
1250 SampleGrabber_IPin_QueryAccept,
1251 SampleGrabber_IPin_EnumMediaTypes,
1252 SampleGrabber_Out_IPin_QueryInternalConnections,
1253 SampleGrabber_IPin_EndOfStream,
1254 SampleGrabber_IPin_BeginFlush,
1255 SampleGrabber_IPin_EndFlush,
1256 SampleGrabber_IPin_NewSegment,
1259 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
1261 SG_Impl* obj = NULL;
1262 ISeekingPassThru *passthru;
1263 HRESULT hr;
1265 TRACE("(%p,%p)\n", ppv, pUnkOuter);
1267 obj = CoTaskMemAlloc(sizeof(SG_Impl));
1268 if (NULL == obj) {
1269 *ppv = NULL;
1270 return E_OUTOFMEMORY;
1272 ZeroMemory(obj, sizeof(SG_Impl));
1274 BaseFilter_Init(&obj->filter, &IBaseFilter_VTable, &CLSID_SampleGrabber,
1275 (DWORD_PTR)(__FILE__ ": SG_Impl.csFilter"), &basefunc_vtbl);
1276 obj->IUnknown_inner.lpVtbl = &samplegrabber_vtbl;
1277 obj->ISampleGrabber_iface.lpVtbl = &ISampleGrabber_VTable;
1278 obj->IMemInputPin_iface.lpVtbl = &IMemInputPin_VTable;
1279 obj->pin_in.IPin_iface.lpVtbl = &IPin_In_VTable;
1280 obj->pin_in.dir = PINDIR_INPUT;
1281 obj->pin_in.name = pin_in_name;
1282 obj->pin_in.sg = obj;
1283 obj->pin_in.pair = NULL;
1284 obj->pin_out.IPin_iface.lpVtbl = &IPin_Out_VTable;
1285 obj->pin_out.dir = PINDIR_OUTPUT;
1286 obj->pin_out.name = pin_out_name;
1287 obj->pin_out.sg = obj;
1288 obj->pin_out.pair = NULL;
1289 obj->mtype.majortype = GUID_NULL;
1290 obj->mtype.subtype = MEDIASUBTYPE_None;
1291 obj->mtype.formattype = FORMAT_None;
1292 obj->allocator = NULL;
1293 obj->memOutput = NULL;
1294 obj->grabberIface = NULL;
1295 obj->grabberMethod = -1;
1296 obj->oneShot = OneShot_None;
1297 obj->bufferLen = -1;
1298 obj->bufferData = NULL;
1300 if (pUnkOuter)
1301 obj->outer_unk = pUnkOuter;
1302 else
1303 obj->outer_unk = &obj->IUnknown_inner;
1305 hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)obj, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&obj->seekthru_unk);
1306 if(hr)
1307 return hr;
1308 IUnknown_QueryInterface(obj->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
1309 ISeekingPassThru_Init(passthru, FALSE, &obj->pin_in.IPin_iface);
1310 ISeekingPassThru_Release(passthru);
1312 *ppv = &obj->IUnknown_inner;
1313 return S_OK;