wbemprox: Add a partial implementation of Win32_NetworkAdapterConfiguration.
[wine.git] / dlls / qedit / samplegrabber.c
blobd2523a84bfcc08e0b85bb37922f5883b033515ce
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(qedit);
35 static const WCHAR vendor_name[] = { 'W', 'i', 'n', 'e', 0 };
36 static const WCHAR pin_in_name[] = { 'I', 'n', 0 };
37 static const WCHAR pin_out_name[] = { 'O', 'u', 't', 0 };
39 static IEnumPins *pinsenum_create(IBaseFilter *filter, IPin **pins, ULONG pinCount);
40 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype);
42 /* Fixed pins enumerator, holds filter referenced */
43 typedef struct _PE_Impl {
44 IEnumPins pe;
45 IBaseFilter *filter;
46 LONG refCount;
47 ULONG numPins;
48 ULONG index;
49 IPin *pins[0];
50 } PE_Impl;
53 /* IEnumPins interface implementation */
55 /* IUnknown */
56 static ULONG WINAPI
57 Fixed_IEnumPins_AddRef(IEnumPins *iface)
59 PE_Impl *This = (PE_Impl *)iface;
60 ULONG refCount = InterlockedIncrement(&This->refCount);
61 TRACE("(%p) new ref = %u\n", This, refCount);
62 return refCount;
65 /* IUnknown */
66 static ULONG WINAPI
67 Fixed_IEnumPins_Release(IEnumPins *iface)
69 PE_Impl *This = (PE_Impl *)iface;
70 ULONG refCount = InterlockedDecrement(&This->refCount);
71 TRACE("(%p) new ref = %u\n", This, refCount);
72 if (refCount == 0)
74 IBaseFilter_Release(This->filter);
75 CoTaskMemFree(This);
76 return 0;
78 return refCount;
81 /* IUnknown */
82 static HRESULT WINAPI
83 Fixed_IEnumPins_QueryInterface(IEnumPins *iface, REFIID riid, void **ppvObject)
85 PE_Impl *This = (PE_Impl *)iface;
86 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
88 if (IsEqualIID(riid, &IID_IUnknown) ||
89 IsEqualIID(riid, &IID_IEnumPins)) {
90 Fixed_IEnumPins_AddRef(iface);
91 *ppvObject = This->pins;
92 return S_OK;
94 *ppvObject = NULL;
95 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
96 return E_NOINTERFACE;
99 /* IEnumPins */
100 static HRESULT WINAPI
101 Fixed_IEnumPins_Next(IEnumPins *iface, ULONG nPins, IPin **pins, ULONG *fetched)
103 PE_Impl *This = (PE_Impl *)iface;
104 ULONG count = 0;
105 TRACE("(%p)->(%u, %p, %p) index = %u\n", This, nPins, pins, fetched, This->index);
106 if (!nPins)
107 return E_INVALIDARG;
108 if (!pins || ((nPins != 1) && !fetched))
109 return E_POINTER;
110 while ((count < nPins) && (This->index < This->numPins)) {
111 IPin *pin = This->pins[This->index++];
112 IPin_AddRef(pin);
113 pins[count++] = pin;
115 if (fetched)
116 *fetched = count;
117 return (count == nPins) ? S_OK : S_FALSE;
120 /* IEnumPins */
121 static HRESULT WINAPI
122 Fixed_IEnumPins_Skip(IEnumPins *iface, ULONG nPins)
124 PE_Impl *This = (PE_Impl *)iface;
125 TRACE("(%p)->(%u) index = %u\n", This, nPins, This->index);
126 nPins += This->index;
127 if (nPins >= This->numPins) {
128 This->index = This->numPins;
129 return S_FALSE;
131 This->index = nPins;
132 return S_OK;
135 /* IEnumPins */
136 static HRESULT WINAPI
137 Fixed_IEnumPins_Reset(IEnumPins *iface)
139 PE_Impl *This = (PE_Impl *)iface;
140 TRACE("(%p)->() index = %u\n", This, This->index);
141 This->index = 0;
142 return S_OK;
145 /* IEnumPins */
146 static HRESULT WINAPI
147 Fixed_IEnumPins_Clone(IEnumPins *iface, IEnumPins **pins)
149 PE_Impl *This = (PE_Impl *)iface;
150 TRACE("(%p)->(%p) index = %u\n", This, pins, This->index);
151 if (!pins)
152 return E_POINTER;
153 *pins = pinsenum_create(This->filter, This->pins, This->numPins);
154 if (!*pins)
155 return E_OUTOFMEMORY;
156 ((PE_Impl *)*pins)->index = This->index;
157 return S_OK;
161 /* Virtual tables and constructor */
163 static const IEnumPinsVtbl IEnumPins_VTable =
165 Fixed_IEnumPins_QueryInterface,
166 Fixed_IEnumPins_AddRef,
167 Fixed_IEnumPins_Release,
168 Fixed_IEnumPins_Next,
169 Fixed_IEnumPins_Skip,
170 Fixed_IEnumPins_Reset,
171 Fixed_IEnumPins_Clone,
174 static IEnumPins *pinsenum_create(IBaseFilter *filter, IPin **pins, ULONG pinCount)
176 ULONG len = sizeof(PE_Impl) + (pinCount * sizeof(IPin *));
177 PE_Impl *obj = CoTaskMemAlloc(len);
178 if (obj) {
179 ULONG i;
180 ZeroMemory(obj, len);
181 obj->pe.lpVtbl = &IEnumPins_VTable;
182 obj->refCount = 1;
183 obj->filter = filter;
184 obj->numPins = pinCount;
185 obj->index = 0;
186 for (i=0; i<pinCount; i++)
187 obj->pins[i] = pins[i];
188 IBaseFilter_AddRef(filter);
190 return &obj->pe;
194 /* Single media type enumerator */
195 typedef struct _ME_Impl {
196 IEnumMediaTypes me;
197 LONG refCount;
198 BOOL past;
199 AM_MEDIA_TYPE mtype;
200 } ME_Impl;
203 /* IEnumMediaTypes interface implementation */
205 /* IUnknown */
206 static ULONG WINAPI
207 Single_IEnumMediaTypes_AddRef(IEnumMediaTypes *iface)
209 ME_Impl *This = (ME_Impl *)iface;
210 ULONG refCount = InterlockedIncrement(&This->refCount);
211 TRACE("(%p) new ref = %u\n", This, refCount);
212 return refCount;
215 /* IUnknown */
216 static ULONG WINAPI
217 Single_IEnumMediaTypes_Release(IEnumMediaTypes *iface)
219 ME_Impl *This = (ME_Impl *)iface;
220 ULONG refCount = InterlockedDecrement(&This->refCount);
221 TRACE("(%p) new ref = %u\n", This, refCount);
222 if (refCount == 0)
224 if (This->mtype.pbFormat)
225 CoTaskMemFree(This->mtype.pbFormat);
226 CoTaskMemFree(This);
227 return 0;
229 return refCount;
232 /* IUnknown */
233 static HRESULT WINAPI
234 Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes *iface, REFIID riid, void **ppvObject)
236 ME_Impl *This = (ME_Impl *)iface;
237 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
239 if (IsEqualIID(riid, &IID_IUnknown) ||
240 IsEqualIID(riid, &IID_IEnumMediaTypes)) {
241 Single_IEnumMediaTypes_AddRef(iface);
242 *ppvObject = &(This->me);
243 return S_OK;
245 *ppvObject = NULL;
246 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
247 return E_NOINTERFACE;
250 /* IEnumMediaTypes */
251 static HRESULT WINAPI
252 Single_IEnumMediaTypes_Next(IEnumMediaTypes *iface, ULONG nTypes, AM_MEDIA_TYPE **types, ULONG *fetched)
254 ME_Impl *This = (ME_Impl *)iface;
255 ULONG count = 0;
256 TRACE("(%p)->(%u, %p, %p)\n", This, nTypes, types, fetched);
257 if (!nTypes)
258 return E_INVALIDARG;
259 if (!types || ((nTypes != 1) && !fetched))
260 return E_POINTER;
261 if (!This->past && !IsEqualGUID(&This->mtype.majortype,&GUID_NULL)) {
262 AM_MEDIA_TYPE *mtype = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
263 *mtype = This->mtype;
264 if (mtype->cbFormat) {
265 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
266 CopyMemory(mtype->pbFormat, This->mtype.pbFormat, mtype->cbFormat);
268 *types = mtype;
269 This->past = TRUE;
270 count = 1;
272 if (fetched)
273 *fetched = count;
274 return (count == nTypes) ? S_OK : S_FALSE;
277 /* IEnumMediaTypes */
278 static HRESULT WINAPI
279 Single_IEnumMediaTypes_Skip(IEnumMediaTypes *iface, ULONG nTypes)
281 ME_Impl *This = (ME_Impl *)iface;
282 TRACE("(%p)->(%u)\n", This, nTypes);
283 if (nTypes)
284 This->past = TRUE;
285 return This->past ? S_FALSE : S_OK;
288 /* IEnumMediaTypes */
289 static HRESULT WINAPI
290 Single_IEnumMediaTypes_Reset(IEnumMediaTypes *iface)
292 ME_Impl *This = (ME_Impl *)iface;
293 TRACE("(%p)->()\n", This);
294 This->past = FALSE;
295 return S_OK;
298 /* IEnumMediaTypes */
299 static HRESULT WINAPI
300 Single_IEnumMediaTypes_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **me)
302 ME_Impl *This = (ME_Impl *)iface;
303 TRACE("(%p)->(%p)\n", This, me);
304 if (!me)
305 return E_POINTER;
306 *me = mediaenum_create(&This->mtype);
307 if (!*me)
308 return E_OUTOFMEMORY;
309 ((ME_Impl *)*me)->past = This->past;
310 return S_OK;
314 /* Virtual tables and constructor */
316 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable =
318 Single_IEnumMediaTypes_QueryInterface,
319 Single_IEnumMediaTypes_AddRef,
320 Single_IEnumMediaTypes_Release,
321 Single_IEnumMediaTypes_Next,
322 Single_IEnumMediaTypes_Skip,
323 Single_IEnumMediaTypes_Reset,
324 Single_IEnumMediaTypes_Clone,
327 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype)
329 ME_Impl *obj = CoTaskMemAlloc(sizeof(ME_Impl));
330 if (obj) {
331 ZeroMemory(obj, sizeof(ME_Impl));
332 obj->me.lpVtbl = &IEnumMediaTypes_VTable;
333 obj->refCount = 1;
334 obj->past = FALSE;
335 if (mtype) {
336 obj->mtype = *mtype;
337 obj->mtype.pUnk = NULL;
338 if (mtype->cbFormat) {
339 obj->mtype.pbFormat = CoTaskMemAlloc(mtype->cbFormat);
340 CopyMemory(obj->mtype.pbFormat, mtype->pbFormat, mtype->cbFormat);
342 else
343 obj->mtype.pbFormat = NULL;
345 else
346 obj->mtype.majortype = GUID_NULL;
348 return &obj->me;
352 /* Sample Grabber pin implementation */
353 typedef struct _SG_Pin {
354 IPin IPin_iface;
355 PIN_DIRECTION dir;
356 WCHAR const *name;
357 struct _SG_Impl *sg;
358 IPin *pair;
359 } SG_Pin;
361 static inline SG_Pin *impl_from_IPin(IPin *iface)
363 return CONTAINING_RECORD(iface, SG_Pin, IPin_iface);
366 /* Sample Grabber filter implementation */
367 typedef struct _SG_Impl {
368 IUnknown IUnknown_inner;
369 IBaseFilter IBaseFilter_iface;
370 ISampleGrabber ISampleGrabber_iface;
371 IMemInputPin IMemInputPin_iface;
372 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
373 IUnknown* seekthru_unk;
374 /* TODO: IQualityControl */
375 IUnknown *outer_unk;
376 LONG ref;
377 CRITICAL_SECTION critSect;
378 FILTER_INFO info;
379 FILTER_STATE state;
380 AM_MEDIA_TYPE mtype;
381 SG_Pin pin_in;
382 SG_Pin pin_out;
383 IMemAllocator *allocator;
384 IReferenceClock *refClock;
385 IMemInputPin *memOutput;
386 ISampleGrabberCB *grabberIface;
387 LONG grabberMethod;
388 LONG oneShot;
389 LONG bufferLen;
390 void* bufferData;
391 } SG_Impl;
393 enum {
394 OneShot_None,
395 OneShot_Wait,
396 OneShot_Past,
399 static inline SG_Impl *impl_from_IUnknown(IUnknown *iface)
401 return CONTAINING_RECORD(iface, SG_Impl, IUnknown_inner);
404 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
406 return CONTAINING_RECORD(iface, SG_Impl, IBaseFilter_iface);
409 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
411 return CONTAINING_RECORD(iface, SG_Impl, ISampleGrabber_iface);
414 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface)
416 return CONTAINING_RECORD(iface, SG_Impl, IMemInputPin_iface);
420 /* Cleanup at end of life */
421 static void SampleGrabber_cleanup(SG_Impl *This)
423 TRACE("(%p)\n", This);
424 if (This->info.pGraph)
425 WARN("(%p) still joined to filter graph %p\n", This, This->info.pGraph);
426 if (This->allocator)
427 IMemAllocator_Release(This->allocator);
428 if (This->refClock)
429 IReferenceClock_Release(This->refClock);
430 if (This->memOutput)
431 IMemInputPin_Release(This->memOutput);
432 if (This->grabberIface)
433 ISampleGrabberCB_Release(This->grabberIface);
434 if (This->mtype.pbFormat)
435 CoTaskMemFree(This->mtype.pbFormat);
436 if (This->bufferData)
437 CoTaskMemFree(This->bufferData);
438 if(This->seekthru_unk)
439 IUnknown_Release(This->seekthru_unk);
440 This->critSect.DebugInfo->Spare[0] = 0;
441 DeleteCriticalSection(&This->critSect);
444 /* SampleGrabber inner IUnknown */
445 static HRESULT WINAPI SampleGrabber_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
447 SG_Impl *This = impl_from_IUnknown(iface);
449 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
451 *ppv = NULL;
452 if (IsEqualIID(riid, &IID_IUnknown))
453 *ppv = &This->IUnknown_inner;
454 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IMediaFilter) ||
455 IsEqualIID(riid, &IID_IBaseFilter))
456 *ppv = &This->IBaseFilter_iface;
457 else if (IsEqualIID(riid, &IID_ISampleGrabber))
458 *ppv = &This->ISampleGrabber_iface;
459 else if (IsEqualIID(riid, &IID_IMemInputPin))
460 *ppv = &This->IMemInputPin_iface;
461 else if (IsEqualIID(riid, &IID_IMediaPosition))
462 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
463 else if (IsEqualIID(riid, &IID_IMediaSeeking))
464 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
465 else if (IsEqualIID(riid, &IID_IQualityControl))
466 FIXME("IQualityControl not implemented\n");
467 else
468 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
470 if (!*ppv)
471 return E_NOINTERFACE;
473 IUnknown_AddRef((IUnknown*)*ppv);
474 return S_OK;
477 static ULONG WINAPI SampleGrabber_AddRef(IUnknown *iface)
479 SG_Impl *This = impl_from_IUnknown(iface);
480 ULONG ref = InterlockedIncrement(&This->ref);
482 TRACE("(%p) new ref = %u\n", This, ref);
484 return ref;
487 static ULONG WINAPI SampleGrabber_Release(IUnknown *iface)
489 SG_Impl *This = impl_from_IUnknown(iface);
490 ULONG ref = InterlockedDecrement(&This->ref);
492 TRACE("(%p) new ref = %u\n", This, ref);
494 if (ref == 0)
496 SampleGrabber_cleanup(This);
497 CoTaskMemFree(This);
498 return 0;
500 return ref;
503 static const IUnknownVtbl samplegrabber_vtbl =
505 SampleGrabber_QueryInterface,
506 SampleGrabber_AddRef,
507 SampleGrabber_Release,
510 /* Helper that buffers data and/or calls installed sample callbacks */
511 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
513 double time = 0.0;
514 REFERENCE_TIME tStart, tEnd;
515 if (This->bufferLen >= 0) {
516 BYTE *data = 0;
517 LONG size = IMediaSample_GetActualDataLength(sample);
518 if (size >= 0 && SUCCEEDED(IMediaSample_GetPointer(sample, &data))) {
519 if (!data)
520 size = 0;
521 EnterCriticalSection(&This->critSect);
522 if (This->bufferLen != size) {
523 if (This->bufferData)
524 CoTaskMemFree(This->bufferData);
525 This->bufferData = size ? CoTaskMemAlloc(size) : NULL;
526 This->bufferLen = size;
528 if (size)
529 CopyMemory(This->bufferData, data, size);
530 LeaveCriticalSection(&This->critSect);
533 if (!This->grabberIface)
534 return;
535 if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
536 time = 1e-7 * tStart;
537 switch (This->grabberMethod) {
538 case 0:
540 ULONG ref = IMediaSample_AddRef(sample);
541 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
542 ref = IMediaSample_Release(sample) + 1 - ref;
543 if (ref)
545 ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref);
546 /* ugly as hell but some apps are sooo buggy */
547 while (ref--)
548 IMediaSample_Release(sample);
551 break;
552 case 1:
554 BYTE *data = 0;
555 LONG size = IMediaSample_GetActualDataLength(sample);
556 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
557 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
559 break;
560 case -1:
561 break;
562 default:
563 FIXME("unsupported method %d\n", This->grabberMethod);
564 /* do not bother us again */
565 This->grabberMethod = -1;
570 /* SampleGrabber implementation of IBaseFilter interface */
572 /* IUnknown */
573 static HRESULT WINAPI
574 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)
576 SG_Impl *This = impl_from_IBaseFilter(iface);
577 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
580 /* IUnknown */
581 static ULONG WINAPI
582 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
584 SG_Impl *This = impl_from_IBaseFilter(iface);
585 return IUnknown_AddRef(This->outer_unk);
588 /* IUnknown */
589 static ULONG WINAPI
590 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
592 SG_Impl *This = impl_from_IBaseFilter(iface);
593 return IUnknown_Release(This->outer_unk);
596 /* IPersist */
597 static HRESULT WINAPI
598 SampleGrabber_IBaseFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID)
600 TRACE("(%p)\n", pClassID);
601 if (!pClassID)
602 return E_POINTER;
603 *pClassID = CLSID_SampleGrabber;
604 return S_OK;
607 /* IMediaFilter */
608 static HRESULT WINAPI
609 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
611 SG_Impl *This = impl_from_IBaseFilter(iface);
612 TRACE("(%p)\n", This);
613 This->state = State_Stopped;
614 return S_OK;
617 /* IMediaFilter */
618 static HRESULT WINAPI
619 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
621 SG_Impl *This = impl_from_IBaseFilter(iface);
622 TRACE("(%p)\n", This);
623 This->state = State_Paused;
624 return S_OK;
627 /* IMediaFilter */
628 static HRESULT WINAPI
629 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
631 SG_Impl *This = impl_from_IBaseFilter(iface);
632 TRACE("(%p)\n", This);
633 This->state = State_Running;
634 return S_OK;
637 /* IMediaFilter */
638 static HRESULT WINAPI
639 SampleGrabber_IBaseFilter_GetState(IBaseFilter *iface, DWORD msTout, FILTER_STATE *state)
641 SG_Impl *This = impl_from_IBaseFilter(iface);
642 TRACE("(%p)->(%u, %p)\n", This, msTout, state);
643 if (!state)
644 return E_POINTER;
645 *state = This->state;
646 return S_OK;
649 /* IMediaFilter */
650 static HRESULT WINAPI
651 SampleGrabber_IBaseFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
653 SG_Impl *This = impl_from_IBaseFilter(iface);
654 TRACE("(%p)->(%p)\n", This, clock);
655 if (clock != This->refClock)
657 if (clock)
658 IReferenceClock_AddRef(clock);
659 if (This->refClock)
660 IReferenceClock_Release(This->refClock);
661 This->refClock = clock;
663 return S_OK;
666 /* IMediaFilter */
667 static HRESULT WINAPI
668 SampleGrabber_IBaseFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock)
670 SG_Impl *This = impl_from_IBaseFilter(iface);
671 TRACE("(%p)->(%p)\n", This, clock);
672 if (!clock)
673 return E_POINTER;
674 if (This->refClock)
675 IReferenceClock_AddRef(This->refClock);
676 *clock = This->refClock;
677 return S_OK;
680 /* IBaseFilter */
681 static HRESULT WINAPI
682 SampleGrabber_IBaseFilter_EnumPins(IBaseFilter *iface, IEnumPins **pins)
684 SG_Impl *This = impl_from_IBaseFilter(iface);
685 IPin *pin[2];
686 TRACE("(%p)->(%p)\n", This, pins);
687 if (!pins)
688 return E_POINTER;
689 pin[0] = &This->pin_in.IPin_iface;
690 pin[1] = &This->pin_out.IPin_iface;
691 *pins = pinsenum_create(iface, pin, 2);
692 return *pins ? S_OK : E_OUTOFMEMORY;
695 /* IBaseFilter */
696 static HRESULT WINAPI
697 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
699 SG_Impl *This = impl_from_IBaseFilter(iface);
700 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin);
701 if (!id || !pin)
702 return E_POINTER;
703 if (!lstrcmpiW(id,pin_in_name))
705 *pin = &This->pin_in.IPin_iface;
706 IPin_AddRef(*pin);
707 return S_OK;
709 else if (!lstrcmpiW(id,pin_out_name))
711 *pin = &This->pin_out.IPin_iface;
712 IPin_AddRef(*pin);
713 return S_OK;
715 *pin = NULL;
716 return VFW_E_NOT_FOUND;
719 /* IBaseFilter */
720 static HRESULT WINAPI
721 SampleGrabber_IBaseFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info)
723 SG_Impl *This = impl_from_IBaseFilter(iface);
724 TRACE("(%p)->(%p)\n", This, info);
725 if (!info)
726 return E_POINTER;
727 if (This->info.pGraph)
728 IFilterGraph_AddRef(This->info.pGraph);
729 *info = This->info;
730 return S_OK;
733 /* IBaseFilter */
734 static HRESULT WINAPI
735 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
737 SG_Impl *This = impl_from_IBaseFilter(iface);
738 TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
739 This->info.pGraph = graph;
740 if (name)
741 lstrcpynW(This->info.achName,name,MAX_FILTER_NAME);
742 This->oneShot = OneShot_None;
743 return S_OK;
746 /* IBaseFilter */
747 static HRESULT WINAPI
748 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
750 TRACE("(%p)\n", vendor);
751 if (!vendor)
752 return E_POINTER;
753 *vendor = CoTaskMemAlloc(sizeof(vendor_name));
754 CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
755 return S_OK;
759 /* SampleGrabber implementation of ISampleGrabber interface */
761 /* IUnknown */
762 static HRESULT WINAPI
763 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv)
765 SG_Impl *This = impl_from_ISampleGrabber(iface);
766 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
769 /* IUnknown */
770 static ULONG WINAPI
771 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
773 SG_Impl *This = impl_from_ISampleGrabber(iface);
774 return IUnknown_AddRef(This->outer_unk);
777 /* IUnknown */
778 static ULONG WINAPI
779 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
781 SG_Impl *This = impl_from_ISampleGrabber(iface);
782 return IUnknown_Release(This->outer_unk);
785 /* ISampleGrabber */
786 static HRESULT WINAPI
787 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
789 SG_Impl *This = impl_from_ISampleGrabber(iface);
790 TRACE("(%p)->(%u)\n", This, oneShot);
791 This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
792 return S_OK;
795 /* ISampleGrabber */
796 static HRESULT WINAPI
797 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
799 SG_Impl *This = impl_from_ISampleGrabber(iface);
800 TRACE("(%p)->(%p)\n", This, type);
801 if (!type)
802 return E_POINTER;
803 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
804 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
805 type->lSampleSize,
806 debugstr_guid(&type->formattype), type->cbFormat);
807 if (This->mtype.pbFormat)
808 CoTaskMemFree(This->mtype.pbFormat);
809 This->mtype = *type;
810 This->mtype.pUnk = NULL;
811 if (type->cbFormat) {
812 This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
813 CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat);
815 else
816 This->mtype.pbFormat = NULL;
817 return S_OK;
820 /* ISampleGrabber */
821 static HRESULT WINAPI
822 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
824 SG_Impl *This = impl_from_ISampleGrabber(iface);
825 TRACE("(%p)->(%p)\n", This, type);
826 if (!type)
827 return E_POINTER;
828 if (!This->pin_in.pair)
829 return VFW_E_NOT_CONNECTED;
830 *type = This->mtype;
831 if (type->cbFormat) {
832 type->pbFormat = CoTaskMemAlloc(type->cbFormat);
833 CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat);
835 return S_OK;
838 /* ISampleGrabber */
839 static HRESULT WINAPI
840 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
842 SG_Impl *This = impl_from_ISampleGrabber(iface);
843 TRACE("(%p)->(%u)\n", This, bufferEm);
844 EnterCriticalSection(&This->critSect);
845 if (bufferEm) {
846 if (This->bufferLen < 0)
847 This->bufferLen = 0;
849 else
850 This->bufferLen = -1;
851 LeaveCriticalSection(&This->critSect);
852 return S_OK;
855 /* ISampleGrabber */
856 static HRESULT WINAPI
857 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
859 SG_Impl *This = impl_from_ISampleGrabber(iface);
860 HRESULT ret = S_OK;
861 TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer);
862 if (!bufSize)
863 return E_POINTER;
864 EnterCriticalSection(&This->critSect);
865 if (!This->pin_in.pair)
866 ret = VFW_E_NOT_CONNECTED;
867 else if (This->bufferLen < 0)
868 ret = E_INVALIDARG;
869 else if (This->bufferLen == 0)
870 ret = VFW_E_WRONG_STATE;
871 else {
872 if (buffer) {
873 if (*bufSize >= This->bufferLen)
874 CopyMemory(buffer, This->bufferData, This->bufferLen);
875 else
876 ret = E_OUTOFMEMORY;
878 *bufSize = This->bufferLen;
880 LeaveCriticalSection(&This->critSect);
881 return ret;
884 /* ISampleGrabber */
885 static HRESULT WINAPI
886 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
888 /* MS doesn't implement it either, no one should call it */
889 WARN("(%p): not implemented\n", sample);
890 return E_NOTIMPL;
893 /* ISampleGrabber */
894 static HRESULT WINAPI
895 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
897 SG_Impl *This = impl_from_ISampleGrabber(iface);
898 TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
899 if (This->grabberIface)
900 ISampleGrabberCB_Release(This->grabberIface);
901 This->grabberIface = cb;
902 This->grabberMethod = whichMethod;
903 if (cb)
904 ISampleGrabberCB_AddRef(cb);
905 return S_OK;
909 /* SampleGrabber implementation of IMemInputPin interface */
911 /* IUnknown */
912 static HRESULT WINAPI
913 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv)
915 SG_Impl *This = impl_from_IMemInputPin(iface);
916 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
919 /* IUnknown */
920 static ULONG WINAPI
921 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
923 SG_Impl *This = impl_from_IMemInputPin(iface);
924 return IUnknown_AddRef(This->outer_unk);
927 /* IUnknown */
928 static ULONG WINAPI
929 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
931 SG_Impl *This = impl_from_IMemInputPin(iface);
932 return IUnknown_Release(This->outer_unk);
935 /* IMemInputPin */
936 static HRESULT WINAPI
937 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
939 SG_Impl *This = impl_from_IMemInputPin(iface);
940 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
941 if (!allocator)
942 return E_POINTER;
943 *allocator = This->allocator;
944 if (!*allocator)
945 return VFW_E_NO_ALLOCATOR;
946 IMemAllocator_AddRef(*allocator);
947 return S_OK;
950 /* IMemInputPin */
951 static HRESULT WINAPI
952 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
954 SG_Impl *This = impl_from_IMemInputPin(iface);
955 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
956 if (This->allocator == allocator)
957 return S_OK;
958 if (This->allocator)
959 IMemAllocator_Release(This->allocator);
960 This->allocator = allocator;
961 if (allocator)
962 IMemAllocator_AddRef(allocator);
963 return S_OK;
966 /* IMemInputPin */
967 static HRESULT WINAPI
968 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
970 SG_Impl *This = impl_from_IMemInputPin(iface);
971 FIXME("(%p)->(%p): semi-stub\n", This, props);
972 if (!props)
973 return E_POINTER;
974 return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL;
977 /* IMemInputPin */
978 static HRESULT WINAPI
979 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
981 SG_Impl *This = impl_from_IMemInputPin(iface);
982 HRESULT hr;
983 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface);
984 if (!sample)
985 return E_POINTER;
986 if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
987 return S_FALSE;
988 SampleGrabber_callback(This, sample);
989 hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK;
990 if (This->oneShot == OneShot_Wait) {
991 This->oneShot = OneShot_Past;
992 hr = S_FALSE;
993 if (This->pin_out.pair)
994 IPin_EndOfStream(This->pin_out.pair);
996 return hr;
999 /* IMemInputPin */
1000 static HRESULT WINAPI
1001 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
1003 SG_Impl *This = impl_from_IMemInputPin(iface);
1004 LONG idx;
1005 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface);
1006 if (!samples || !nProcessed)
1007 return E_POINTER;
1008 if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
1009 return S_FALSE;
1010 for (idx = 0; idx < nSamples; idx++)
1011 SampleGrabber_callback(This, samples[idx]);
1012 return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK;
1015 /* IMemInputPin */
1016 static HRESULT WINAPI
1017 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
1019 SG_Impl *This = impl_from_IMemInputPin(iface);
1020 TRACE("(%p)\n", This);
1021 return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK;
1025 /* SampleGrabber member pin implementation */
1027 /* IUnknown */
1028 static ULONG WINAPI
1029 SampleGrabber_IPin_AddRef(IPin *iface)
1031 SG_Pin *This = impl_from_IPin(iface);
1032 return ISampleGrabber_AddRef(&This->sg->ISampleGrabber_iface);
1035 /* IUnknown */
1036 static ULONG WINAPI
1037 SampleGrabber_IPin_Release(IPin *iface)
1039 SG_Pin *This = impl_from_IPin(iface);
1040 return ISampleGrabber_Release(&This->sg->ISampleGrabber_iface);
1043 /* IUnknown */
1044 static HRESULT WINAPI
1045 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
1047 SG_Pin *This = impl_from_IPin(iface);
1048 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1050 *ppv = NULL;
1051 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
1052 *ppv = iface;
1053 else if (IsEqualIID(riid, &IID_IMemInputPin))
1054 *ppv = &This->sg->IMemInputPin_iface;
1055 else if (IsEqualIID(riid, &IID_IMediaSeeking))
1056 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
1057 else if (IsEqualIID(riid, &IID_IMediaPosition))
1058 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
1059 else {
1060 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
1061 return E_NOINTERFACE;
1064 IUnknown_AddRef((IUnknown*)*ppv);
1065 return S_OK;
1068 /* IPin - input pin */
1069 static HRESULT WINAPI
1070 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype)
1072 WARN("(%p, %p): unexpected\n", receiver, mtype);
1073 return E_UNEXPECTED;
1076 /* IPin - output pin */
1077 static HRESULT WINAPI
1078 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type)
1080 SG_Pin *This = impl_from_IPin(iface);
1081 HRESULT hr;
1083 TRACE("(%p)->(%p, %p)\n", This, receiver, type);
1084 if (!receiver)
1085 return E_POINTER;
1086 if (This->pair)
1087 return VFW_E_ALREADY_CONNECTED;
1088 if (This->sg->state != State_Stopped)
1089 return VFW_E_NOT_STOPPED;
1090 if (type) {
1091 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1092 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1093 type->lSampleSize,
1094 debugstr_guid(&type->formattype), type->cbFormat);
1095 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1096 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1097 return VFW_E_TYPE_NOT_ACCEPTED;
1098 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1099 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1100 return VFW_E_TYPE_NOT_ACCEPTED;
1101 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1102 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1103 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1104 return VFW_E_TYPE_NOT_ACCEPTED;
1106 else
1107 type = &This->sg->mtype;
1108 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
1109 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
1110 !type->pbFormat)
1111 return VFW_E_TYPE_NOT_ACCEPTED;
1112 hr = IPin_ReceiveConnection(receiver, &This->IPin_iface, type);
1113 if (FAILED(hr))
1114 return hr;
1115 This->pair = receiver;
1116 if (This->sg->memOutput) {
1117 IMemInputPin_Release(This->sg->memOutput);
1118 This->sg->memOutput = NULL;
1120 IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput));
1121 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput);
1122 return S_OK;
1125 /* IPin - input pin */
1126 static HRESULT WINAPI
1127 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type)
1129 SG_Pin *This = impl_from_IPin(iface);
1131 TRACE("(%p)->(%p, %p)\n", This, connector, type);
1132 if (!connector)
1133 return E_POINTER;
1134 if (This->pair)
1135 return VFW_E_ALREADY_CONNECTED;
1136 if (This->sg->state != State_Stopped)
1137 return VFW_E_NOT_STOPPED;
1138 if (type) {
1139 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1140 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1141 type->lSampleSize,
1142 debugstr_guid(&type->formattype), type->cbFormat);
1143 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
1144 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
1145 !type->pbFormat)
1146 return VFW_E_INVALIDMEDIATYPE;
1147 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1148 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1149 return VFW_E_TYPE_NOT_ACCEPTED;
1150 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1151 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1152 return VFW_E_TYPE_NOT_ACCEPTED;
1153 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1154 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1155 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1156 return VFW_E_TYPE_NOT_ACCEPTED;
1157 if (This->sg->mtype.pbFormat)
1158 CoTaskMemFree(This->sg->mtype.pbFormat);
1159 This->sg->mtype = *type;
1160 This->sg->mtype.pUnk = NULL;
1161 if (type->cbFormat) {
1162 This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
1163 CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat);
1165 else
1166 This->sg->mtype.pbFormat = NULL;
1168 This->pair = connector;
1169 TRACE("(%p) Accepted IPin %p\n", This, connector);
1170 return S_OK;
1173 /* IPin - output pin */
1174 static HRESULT WINAPI
1175 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype)
1177 WARN("(%p, %p): unexpected\n", connector, mtype);
1178 return E_UNEXPECTED;
1181 /* IPin - input pin */
1182 static HRESULT WINAPI
1183 SampleGrabber_In_IPin_Disconnect(IPin *iface)
1185 SG_Pin *This = impl_from_IPin(iface);
1187 TRACE("(%p)->() pair = %p\n", This, This->pair);
1188 if (This->sg->state != State_Stopped)
1189 return VFW_E_NOT_STOPPED;
1190 if (This->pair) {
1191 This->pair = NULL;
1192 return S_OK;
1194 return S_FALSE;
1197 /* IPin - output pin */
1198 static HRESULT WINAPI
1199 SampleGrabber_Out_IPin_Disconnect(IPin *iface)
1201 SG_Pin *This = impl_from_IPin(iface);
1203 TRACE("(%p)->() pair = %p\n", This, This->pair);
1204 if (This->sg->state != State_Stopped)
1205 return VFW_E_NOT_STOPPED;
1206 if (This->pair) {
1207 This->pair = NULL;
1208 if (This->sg->memOutput) {
1209 IMemInputPin_Release(This->sg->memOutput);
1210 This->sg->memOutput = NULL;
1212 return S_OK;
1214 return S_FALSE;
1217 /* IPin */
1218 static HRESULT WINAPI
1219 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin)
1221 SG_Pin *This = impl_from_IPin(iface);
1223 TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair);
1224 if (!pin)
1225 return E_POINTER;
1226 *pin = This->pair;
1227 if (*pin) {
1228 IPin_AddRef(*pin);
1229 return S_OK;
1231 return VFW_E_NOT_CONNECTED;
1234 /* IPin */
1235 static HRESULT WINAPI
1236 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype)
1238 SG_Pin *This = impl_from_IPin(iface);
1240 TRACE("(%p)->(%p)\n", This, mtype);
1241 if (!mtype)
1242 return E_POINTER;
1243 if (!This->pair)
1244 return VFW_E_NOT_CONNECTED;
1245 *mtype = This->sg->mtype;
1246 if (mtype->cbFormat) {
1247 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
1248 CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat);
1250 return S_OK;
1253 /* IPin */
1254 static HRESULT WINAPI
1255 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info)
1257 SG_Pin *This = impl_from_IPin(iface);
1259 TRACE("(%p)->(%p)\n", This, info);
1260 if (!info)
1261 return E_POINTER;
1262 IBaseFilter_AddRef(&This->sg->IBaseFilter_iface);
1263 info->pFilter = &This->sg->IBaseFilter_iface;
1264 info->dir = This->dir;
1265 lstrcpynW(info->achName,This->name,MAX_PIN_NAME);
1266 return S_OK;
1269 /* IPin */
1270 static HRESULT WINAPI
1271 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1273 SG_Pin *This = impl_from_IPin(iface);
1275 TRACE("(%p)->(%p)\n", This, dir);
1276 if (!dir)
1277 return E_POINTER;
1278 *dir = This->dir;
1279 return S_OK;
1282 /* IPin */
1283 static HRESULT WINAPI
1284 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id)
1286 SG_Pin *This = impl_from_IPin(iface);
1288 int len;
1289 TRACE("(%p)->(%p)\n", This, id);
1290 if (!id)
1291 return E_POINTER;
1292 len = sizeof(WCHAR)*(1+lstrlenW(This->name));
1293 *id = CoTaskMemAlloc(len);
1294 CopyMemory(*id, This->name, len);
1295 return S_OK;
1298 /* IPin */
1299 static HRESULT WINAPI
1300 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype)
1302 TRACE("(%p)\n", mtype);
1303 return S_OK;
1306 /* IPin */
1307 static HRESULT WINAPI
1308 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes)
1310 SG_Pin *This = impl_from_IPin(iface);
1312 TRACE("(%p)->(%p)\n", This, mtypes);
1313 if (!mtypes)
1314 return E_POINTER;
1315 *mtypes = mediaenum_create(This->sg->pin_in.pair ? &This->sg->mtype : NULL);
1316 return *mtypes ? S_OK : E_OUTOFMEMORY;
1319 /* IPin - input pin */
1320 static HRESULT WINAPI
1321 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1323 SG_Pin *This = impl_from_IPin(iface);
1325 TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0));
1326 if (!nPins)
1327 return E_POINTER;
1328 if (*nPins) {
1329 if (!pins)
1330 return E_POINTER;
1331 IPin_AddRef(&This->sg->pin_out.IPin_iface);
1332 *pins = &This->sg->pin_out.IPin_iface;
1333 *nPins = 1;
1334 return S_OK;
1336 *nPins = 1;
1337 return S_FALSE;
1340 /* IPin - output pin */
1341 static HRESULT WINAPI
1342 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1344 WARN("(%p, %p): unexpected\n", pins, nPins);
1345 if (nPins)
1346 *nPins = 0;
1347 return E_NOTIMPL;
1350 /* IPin */
1351 static HRESULT WINAPI
1352 SampleGrabber_IPin_EndOfStream(IPin *iface)
1354 FIXME(": stub\n");
1355 return S_OK;
1358 /* IPin */
1359 static HRESULT WINAPI
1360 SampleGrabber_IPin_BeginFlush(IPin *iface)
1362 FIXME(": stub\n");
1363 return S_OK;
1366 /* IPin */
1367 static HRESULT WINAPI
1368 SampleGrabber_IPin_EndFlush(IPin *iface)
1370 FIXME(": stub\n");
1371 return S_OK;
1374 /* IPin */
1375 static HRESULT WINAPI
1376 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate)
1378 FIXME(": stub\n");
1379 return S_OK;
1383 /* SampleGrabber vtables and constructor */
1385 static const IBaseFilterVtbl IBaseFilter_VTable =
1387 SampleGrabber_IBaseFilter_QueryInterface,
1388 SampleGrabber_IBaseFilter_AddRef,
1389 SampleGrabber_IBaseFilter_Release,
1390 SampleGrabber_IBaseFilter_GetClassID,
1391 SampleGrabber_IBaseFilter_Stop,
1392 SampleGrabber_IBaseFilter_Pause,
1393 SampleGrabber_IBaseFilter_Run,
1394 SampleGrabber_IBaseFilter_GetState,
1395 SampleGrabber_IBaseFilter_SetSyncSource,
1396 SampleGrabber_IBaseFilter_GetSyncSource,
1397 SampleGrabber_IBaseFilter_EnumPins,
1398 SampleGrabber_IBaseFilter_FindPin,
1399 SampleGrabber_IBaseFilter_QueryFilterInfo,
1400 SampleGrabber_IBaseFilter_JoinFilterGraph,
1401 SampleGrabber_IBaseFilter_QueryVendorInfo,
1404 static const ISampleGrabberVtbl ISampleGrabber_VTable =
1406 SampleGrabber_ISampleGrabber_QueryInterface,
1407 SampleGrabber_ISampleGrabber_AddRef,
1408 SampleGrabber_ISampleGrabber_Release,
1409 SampleGrabber_ISampleGrabber_SetOneShot,
1410 SampleGrabber_ISampleGrabber_SetMediaType,
1411 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
1412 SampleGrabber_ISampleGrabber_SetBufferSamples,
1413 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
1414 SampleGrabber_ISampleGrabber_GetCurrentSample,
1415 SampleGrabber_ISampleGrabber_SetCallback,
1418 static const IMemInputPinVtbl IMemInputPin_VTable =
1420 SampleGrabber_IMemInputPin_QueryInterface,
1421 SampleGrabber_IMemInputPin_AddRef,
1422 SampleGrabber_IMemInputPin_Release,
1423 SampleGrabber_IMemInputPin_GetAllocator,
1424 SampleGrabber_IMemInputPin_NotifyAllocator,
1425 SampleGrabber_IMemInputPin_GetAllocatorRequirements,
1426 SampleGrabber_IMemInputPin_Receive,
1427 SampleGrabber_IMemInputPin_ReceiveMultiple,
1428 SampleGrabber_IMemInputPin_ReceiveCanBlock,
1431 static const IPinVtbl IPin_In_VTable =
1433 SampleGrabber_IPin_QueryInterface,
1434 SampleGrabber_IPin_AddRef,
1435 SampleGrabber_IPin_Release,
1436 SampleGrabber_In_IPin_Connect,
1437 SampleGrabber_In_IPin_ReceiveConnection,
1438 SampleGrabber_In_IPin_Disconnect,
1439 SampleGrabber_IPin_ConnectedTo,
1440 SampleGrabber_IPin_ConnectionMediaType,
1441 SampleGrabber_IPin_QueryPinInfo,
1442 SampleGrabber_IPin_QueryDirection,
1443 SampleGrabber_IPin_QueryId,
1444 SampleGrabber_IPin_QueryAccept,
1445 SampleGrabber_IPin_EnumMediaTypes,
1446 SampleGrabber_In_IPin_QueryInternalConnections,
1447 SampleGrabber_IPin_EndOfStream,
1448 SampleGrabber_IPin_BeginFlush,
1449 SampleGrabber_IPin_EndFlush,
1450 SampleGrabber_IPin_NewSegment,
1453 static const IPinVtbl IPin_Out_VTable =
1455 SampleGrabber_IPin_QueryInterface,
1456 SampleGrabber_IPin_AddRef,
1457 SampleGrabber_IPin_Release,
1458 SampleGrabber_Out_IPin_Connect,
1459 SampleGrabber_Out_IPin_ReceiveConnection,
1460 SampleGrabber_Out_IPin_Disconnect,
1461 SampleGrabber_IPin_ConnectedTo,
1462 SampleGrabber_IPin_ConnectionMediaType,
1463 SampleGrabber_IPin_QueryPinInfo,
1464 SampleGrabber_IPin_QueryDirection,
1465 SampleGrabber_IPin_QueryId,
1466 SampleGrabber_IPin_QueryAccept,
1467 SampleGrabber_IPin_EnumMediaTypes,
1468 SampleGrabber_Out_IPin_QueryInternalConnections,
1469 SampleGrabber_IPin_EndOfStream,
1470 SampleGrabber_IPin_BeginFlush,
1471 SampleGrabber_IPin_EndFlush,
1472 SampleGrabber_IPin_NewSegment,
1475 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
1477 SG_Impl* obj = NULL;
1478 ISeekingPassThru *passthru;
1479 HRESULT hr;
1481 TRACE("(%p,%p)\n", ppv, pUnkOuter);
1483 obj = CoTaskMemAlloc(sizeof(SG_Impl));
1484 if (NULL == obj) {
1485 *ppv = NULL;
1486 return E_OUTOFMEMORY;
1488 ZeroMemory(obj, sizeof(SG_Impl));
1490 obj->ref = 1;
1491 obj->IUnknown_inner.lpVtbl = &samplegrabber_vtbl;
1492 obj->IBaseFilter_iface.lpVtbl = &IBaseFilter_VTable;
1493 obj->ISampleGrabber_iface.lpVtbl = &ISampleGrabber_VTable;
1494 obj->IMemInputPin_iface.lpVtbl = &IMemInputPin_VTable;
1495 obj->pin_in.IPin_iface.lpVtbl = &IPin_In_VTable;
1496 obj->pin_in.dir = PINDIR_INPUT;
1497 obj->pin_in.name = pin_in_name;
1498 obj->pin_in.sg = obj;
1499 obj->pin_in.pair = NULL;
1500 obj->pin_out.IPin_iface.lpVtbl = &IPin_Out_VTable;
1501 obj->pin_out.dir = PINDIR_OUTPUT;
1502 obj->pin_out.name = pin_out_name;
1503 obj->pin_out.sg = obj;
1504 obj->pin_out.pair = NULL;
1505 InitializeCriticalSection(&obj->critSect);
1506 obj->critSect.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SG_Impl.critSect");
1507 obj->info.achName[0] = 0;
1508 obj->info.pGraph = NULL;
1509 obj->state = State_Stopped;
1510 obj->mtype.majortype = GUID_NULL;
1511 obj->mtype.subtype = MEDIASUBTYPE_None;
1512 obj->mtype.formattype = FORMAT_None;
1513 obj->allocator = NULL;
1514 obj->refClock = NULL;
1515 obj->memOutput = NULL;
1516 obj->grabberIface = NULL;
1517 obj->grabberMethod = -1;
1518 obj->oneShot = OneShot_None;
1519 obj->bufferLen = -1;
1520 obj->bufferData = NULL;
1522 if (pUnkOuter)
1523 obj->outer_unk = pUnkOuter;
1524 else
1525 obj->outer_unk = &obj->IUnknown_inner;
1527 hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)obj, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&obj->seekthru_unk);
1528 if(hr)
1529 return hr;
1530 IUnknown_QueryInterface(obj->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
1531 ISeekingPassThru_Init(passthru, FALSE, &obj->pin_in.IPin_iface);
1532 ISeekingPassThru_Release(passthru);
1534 *ppv = &obj->IUnknown_inner;
1535 return S_OK;