qedit: Use offsetof for the size of a struct with a varlen array.
[wine/multimedia.git] / dlls / qedit / samplegrabber.c
blob15a34715c16739c82c80853139c0ff1aefb0d59b
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[1];
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 PE_Impl *obj;
177 ULONG len = offsetof(PE_Impl, pins[pinCount]);
178 ULONG i;
180 obj = CoTaskMemAlloc(len);
181 if (!obj)
182 return NULL;
184 ZeroMemory(obj, len);
185 obj->pe.lpVtbl = &IEnumPins_VTable;
186 obj->refCount = 1;
187 obj->filter = filter;
188 obj->numPins = pinCount;
189 obj->index = 0;
190 for (i = 0; i < pinCount; i++)
191 obj->pins[i] = pins[i];
192 IBaseFilter_AddRef(filter);
194 return &obj->pe;
198 /* Single media type enumerator */
199 typedef struct _ME_Impl {
200 IEnumMediaTypes me;
201 LONG refCount;
202 BOOL past;
203 AM_MEDIA_TYPE mtype;
204 } ME_Impl;
207 /* IEnumMediaTypes interface implementation */
209 /* IUnknown */
210 static ULONG WINAPI
211 Single_IEnumMediaTypes_AddRef(IEnumMediaTypes *iface)
213 ME_Impl *This = (ME_Impl *)iface;
214 ULONG refCount = InterlockedIncrement(&This->refCount);
215 TRACE("(%p) new ref = %u\n", This, refCount);
216 return refCount;
219 /* IUnknown */
220 static ULONG WINAPI
221 Single_IEnumMediaTypes_Release(IEnumMediaTypes *iface)
223 ME_Impl *This = (ME_Impl *)iface;
224 ULONG refCount = InterlockedDecrement(&This->refCount);
225 TRACE("(%p) new ref = %u\n", This, refCount);
226 if (refCount == 0)
228 if (This->mtype.pbFormat)
229 CoTaskMemFree(This->mtype.pbFormat);
230 CoTaskMemFree(This);
231 return 0;
233 return refCount;
236 /* IUnknown */
237 static HRESULT WINAPI
238 Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes *iface, REFIID riid, void **ppvObject)
240 ME_Impl *This = (ME_Impl *)iface;
241 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
243 if (IsEqualIID(riid, &IID_IUnknown) ||
244 IsEqualIID(riid, &IID_IEnumMediaTypes)) {
245 Single_IEnumMediaTypes_AddRef(iface);
246 *ppvObject = &(This->me);
247 return S_OK;
249 *ppvObject = NULL;
250 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
251 return E_NOINTERFACE;
254 /* IEnumMediaTypes */
255 static HRESULT WINAPI
256 Single_IEnumMediaTypes_Next(IEnumMediaTypes *iface, ULONG nTypes, AM_MEDIA_TYPE **types, ULONG *fetched)
258 ME_Impl *This = (ME_Impl *)iface;
259 ULONG count = 0;
260 TRACE("(%p)->(%u, %p, %p)\n", This, nTypes, types, fetched);
261 if (!nTypes)
262 return E_INVALIDARG;
263 if (!types || ((nTypes != 1) && !fetched))
264 return E_POINTER;
265 if (!This->past && !IsEqualGUID(&This->mtype.majortype,&GUID_NULL)) {
266 AM_MEDIA_TYPE *mtype = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
267 *mtype = This->mtype;
268 if (mtype->cbFormat) {
269 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
270 CopyMemory(mtype->pbFormat, This->mtype.pbFormat, mtype->cbFormat);
272 *types = mtype;
273 This->past = TRUE;
274 count = 1;
276 if (fetched)
277 *fetched = count;
278 return (count == nTypes) ? S_OK : S_FALSE;
281 /* IEnumMediaTypes */
282 static HRESULT WINAPI
283 Single_IEnumMediaTypes_Skip(IEnumMediaTypes *iface, ULONG nTypes)
285 ME_Impl *This = (ME_Impl *)iface;
286 TRACE("(%p)->(%u)\n", This, nTypes);
287 if (nTypes)
288 This->past = TRUE;
289 return This->past ? S_FALSE : S_OK;
292 /* IEnumMediaTypes */
293 static HRESULT WINAPI
294 Single_IEnumMediaTypes_Reset(IEnumMediaTypes *iface)
296 ME_Impl *This = (ME_Impl *)iface;
297 TRACE("(%p)->()\n", This);
298 This->past = FALSE;
299 return S_OK;
302 /* IEnumMediaTypes */
303 static HRESULT WINAPI
304 Single_IEnumMediaTypes_Clone(IEnumMediaTypes *iface, IEnumMediaTypes **me)
306 ME_Impl *This = (ME_Impl *)iface;
307 TRACE("(%p)->(%p)\n", This, me);
308 if (!me)
309 return E_POINTER;
310 *me = mediaenum_create(&This->mtype);
311 if (!*me)
312 return E_OUTOFMEMORY;
313 ((ME_Impl *)*me)->past = This->past;
314 return S_OK;
318 /* Virtual tables and constructor */
320 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable =
322 Single_IEnumMediaTypes_QueryInterface,
323 Single_IEnumMediaTypes_AddRef,
324 Single_IEnumMediaTypes_Release,
325 Single_IEnumMediaTypes_Next,
326 Single_IEnumMediaTypes_Skip,
327 Single_IEnumMediaTypes_Reset,
328 Single_IEnumMediaTypes_Clone,
331 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype)
333 ME_Impl *obj = CoTaskMemAlloc(sizeof(ME_Impl));
334 if (obj) {
335 ZeroMemory(obj, sizeof(ME_Impl));
336 obj->me.lpVtbl = &IEnumMediaTypes_VTable;
337 obj->refCount = 1;
338 obj->past = FALSE;
339 if (mtype) {
340 obj->mtype = *mtype;
341 obj->mtype.pUnk = NULL;
342 if (mtype->cbFormat) {
343 obj->mtype.pbFormat = CoTaskMemAlloc(mtype->cbFormat);
344 CopyMemory(obj->mtype.pbFormat, mtype->pbFormat, mtype->cbFormat);
346 else
347 obj->mtype.pbFormat = NULL;
349 else
350 obj->mtype.majortype = GUID_NULL;
352 return &obj->me;
356 /* Sample Grabber pin implementation */
357 typedef struct _SG_Pin {
358 IPin IPin_iface;
359 PIN_DIRECTION dir;
360 WCHAR const *name;
361 struct _SG_Impl *sg;
362 IPin *pair;
363 } SG_Pin;
365 static inline SG_Pin *impl_from_IPin(IPin *iface)
367 return CONTAINING_RECORD(iface, SG_Pin, IPin_iface);
370 /* Sample Grabber filter implementation */
371 typedef struct _SG_Impl {
372 IUnknown IUnknown_inner;
373 IBaseFilter IBaseFilter_iface;
374 ISampleGrabber ISampleGrabber_iface;
375 IMemInputPin IMemInputPin_iface;
376 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
377 IUnknown* seekthru_unk;
378 /* TODO: IQualityControl */
379 IUnknown *outer_unk;
380 LONG ref;
381 CRITICAL_SECTION critSect;
382 FILTER_INFO info;
383 FILTER_STATE state;
384 AM_MEDIA_TYPE mtype;
385 SG_Pin pin_in;
386 SG_Pin pin_out;
387 IMemAllocator *allocator;
388 IReferenceClock *refClock;
389 IMemInputPin *memOutput;
390 ISampleGrabberCB *grabberIface;
391 LONG grabberMethod;
392 LONG oneShot;
393 LONG bufferLen;
394 void* bufferData;
395 } SG_Impl;
397 enum {
398 OneShot_None,
399 OneShot_Wait,
400 OneShot_Past,
403 static inline SG_Impl *impl_from_IUnknown(IUnknown *iface)
405 return CONTAINING_RECORD(iface, SG_Impl, IUnknown_inner);
408 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
410 return CONTAINING_RECORD(iface, SG_Impl, IBaseFilter_iface);
413 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
415 return CONTAINING_RECORD(iface, SG_Impl, ISampleGrabber_iface);
418 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface)
420 return CONTAINING_RECORD(iface, SG_Impl, IMemInputPin_iface);
424 /* Cleanup at end of life */
425 static void SampleGrabber_cleanup(SG_Impl *This)
427 TRACE("(%p)\n", This);
428 if (This->info.pGraph)
429 WARN("(%p) still joined to filter graph %p\n", This, This->info.pGraph);
430 if (This->allocator)
431 IMemAllocator_Release(This->allocator);
432 if (This->refClock)
433 IReferenceClock_Release(This->refClock);
434 if (This->memOutput)
435 IMemInputPin_Release(This->memOutput);
436 if (This->grabberIface)
437 ISampleGrabberCB_Release(This->grabberIface);
438 if (This->mtype.pbFormat)
439 CoTaskMemFree(This->mtype.pbFormat);
440 if (This->bufferData)
441 CoTaskMemFree(This->bufferData);
442 if(This->seekthru_unk)
443 IUnknown_Release(This->seekthru_unk);
444 This->critSect.DebugInfo->Spare[0] = 0;
445 DeleteCriticalSection(&This->critSect);
448 /* SampleGrabber inner IUnknown */
449 static HRESULT WINAPI SampleGrabber_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
451 SG_Impl *This = impl_from_IUnknown(iface);
453 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
455 *ppv = NULL;
456 if (IsEqualIID(riid, &IID_IUnknown))
457 *ppv = &This->IUnknown_inner;
458 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IMediaFilter) ||
459 IsEqualIID(riid, &IID_IBaseFilter))
460 *ppv = &This->IBaseFilter_iface;
461 else if (IsEqualIID(riid, &IID_ISampleGrabber))
462 *ppv = &This->ISampleGrabber_iface;
463 else if (IsEqualIID(riid, &IID_IMemInputPin))
464 *ppv = &This->IMemInputPin_iface;
465 else if (IsEqualIID(riid, &IID_IMediaPosition))
466 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
467 else if (IsEqualIID(riid, &IID_IMediaSeeking))
468 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
469 else if (IsEqualIID(riid, &IID_IQualityControl))
470 FIXME("IQualityControl not implemented\n");
471 else
472 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
474 if (!*ppv)
475 return E_NOINTERFACE;
477 IUnknown_AddRef((IUnknown*)*ppv);
478 return S_OK;
481 static ULONG WINAPI SampleGrabber_AddRef(IUnknown *iface)
483 SG_Impl *This = impl_from_IUnknown(iface);
484 ULONG ref = InterlockedIncrement(&This->ref);
486 TRACE("(%p) new ref = %u\n", This, ref);
488 return ref;
491 static ULONG WINAPI SampleGrabber_Release(IUnknown *iface)
493 SG_Impl *This = impl_from_IUnknown(iface);
494 ULONG ref = InterlockedDecrement(&This->ref);
496 TRACE("(%p) new ref = %u\n", This, ref);
498 if (ref == 0)
500 SampleGrabber_cleanup(This);
501 CoTaskMemFree(This);
502 return 0;
504 return ref;
507 static const IUnknownVtbl samplegrabber_vtbl =
509 SampleGrabber_QueryInterface,
510 SampleGrabber_AddRef,
511 SampleGrabber_Release,
514 /* Helper that buffers data and/or calls installed sample callbacks */
515 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
517 double time = 0.0;
518 REFERENCE_TIME tStart, tEnd;
519 if (This->bufferLen >= 0) {
520 BYTE *data = 0;
521 LONG size = IMediaSample_GetActualDataLength(sample);
522 if (size >= 0 && SUCCEEDED(IMediaSample_GetPointer(sample, &data))) {
523 if (!data)
524 size = 0;
525 EnterCriticalSection(&This->critSect);
526 if (This->bufferLen != size) {
527 if (This->bufferData)
528 CoTaskMemFree(This->bufferData);
529 This->bufferData = size ? CoTaskMemAlloc(size) : NULL;
530 This->bufferLen = size;
532 if (size)
533 CopyMemory(This->bufferData, data, size);
534 LeaveCriticalSection(&This->critSect);
537 if (!This->grabberIface)
538 return;
539 if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
540 time = 1e-7 * tStart;
541 switch (This->grabberMethod) {
542 case 0:
544 ULONG ref = IMediaSample_AddRef(sample);
545 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
546 ref = IMediaSample_Release(sample) + 1 - ref;
547 if (ref)
549 ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref);
550 /* ugly as hell but some apps are sooo buggy */
551 while (ref--)
552 IMediaSample_Release(sample);
555 break;
556 case 1:
558 BYTE *data = 0;
559 LONG size = IMediaSample_GetActualDataLength(sample);
560 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
561 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
563 break;
564 case -1:
565 break;
566 default:
567 FIXME("unsupported method %d\n", This->grabberMethod);
568 /* do not bother us again */
569 This->grabberMethod = -1;
574 /* SampleGrabber implementation of IBaseFilter interface */
576 /* IUnknown */
577 static HRESULT WINAPI
578 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)
580 SG_Impl *This = impl_from_IBaseFilter(iface);
581 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
584 /* IUnknown */
585 static ULONG WINAPI
586 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
588 SG_Impl *This = impl_from_IBaseFilter(iface);
589 return IUnknown_AddRef(This->outer_unk);
592 /* IUnknown */
593 static ULONG WINAPI
594 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
596 SG_Impl *This = impl_from_IBaseFilter(iface);
597 return IUnknown_Release(This->outer_unk);
600 /* IPersist */
601 static HRESULT WINAPI
602 SampleGrabber_IBaseFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID)
604 TRACE("(%p)\n", pClassID);
605 if (!pClassID)
606 return E_POINTER;
607 *pClassID = CLSID_SampleGrabber;
608 return S_OK;
611 /* IMediaFilter */
612 static HRESULT WINAPI
613 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
615 SG_Impl *This = impl_from_IBaseFilter(iface);
616 TRACE("(%p)\n", This);
617 This->state = State_Stopped;
618 return S_OK;
621 /* IMediaFilter */
622 static HRESULT WINAPI
623 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
625 SG_Impl *This = impl_from_IBaseFilter(iface);
626 TRACE("(%p)\n", This);
627 This->state = State_Paused;
628 return S_OK;
631 /* IMediaFilter */
632 static HRESULT WINAPI
633 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
635 SG_Impl *This = impl_from_IBaseFilter(iface);
636 TRACE("(%p)\n", This);
637 This->state = State_Running;
638 return S_OK;
641 /* IMediaFilter */
642 static HRESULT WINAPI
643 SampleGrabber_IBaseFilter_GetState(IBaseFilter *iface, DWORD msTout, FILTER_STATE *state)
645 SG_Impl *This = impl_from_IBaseFilter(iface);
646 TRACE("(%p)->(%u, %p)\n", This, msTout, state);
647 if (!state)
648 return E_POINTER;
649 *state = This->state;
650 return S_OK;
653 /* IMediaFilter */
654 static HRESULT WINAPI
655 SampleGrabber_IBaseFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
657 SG_Impl *This = impl_from_IBaseFilter(iface);
658 TRACE("(%p)->(%p)\n", This, clock);
659 if (clock != This->refClock)
661 if (clock)
662 IReferenceClock_AddRef(clock);
663 if (This->refClock)
664 IReferenceClock_Release(This->refClock);
665 This->refClock = clock;
667 return S_OK;
670 /* IMediaFilter */
671 static HRESULT WINAPI
672 SampleGrabber_IBaseFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock)
674 SG_Impl *This = impl_from_IBaseFilter(iface);
675 TRACE("(%p)->(%p)\n", This, clock);
676 if (!clock)
677 return E_POINTER;
678 if (This->refClock)
679 IReferenceClock_AddRef(This->refClock);
680 *clock = This->refClock;
681 return S_OK;
684 /* IBaseFilter */
685 static HRESULT WINAPI
686 SampleGrabber_IBaseFilter_EnumPins(IBaseFilter *iface, IEnumPins **pins)
688 SG_Impl *This = impl_from_IBaseFilter(iface);
689 IPin *pin[2];
690 TRACE("(%p)->(%p)\n", This, pins);
691 if (!pins)
692 return E_POINTER;
693 pin[0] = &This->pin_in.IPin_iface;
694 pin[1] = &This->pin_out.IPin_iface;
695 *pins = pinsenum_create(iface, pin, 2);
696 return *pins ? S_OK : E_OUTOFMEMORY;
699 /* IBaseFilter */
700 static HRESULT WINAPI
701 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
703 SG_Impl *This = impl_from_IBaseFilter(iface);
704 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin);
705 if (!id || !pin)
706 return E_POINTER;
707 if (!lstrcmpiW(id,pin_in_name))
709 *pin = &This->pin_in.IPin_iface;
710 IPin_AddRef(*pin);
711 return S_OK;
713 else if (!lstrcmpiW(id,pin_out_name))
715 *pin = &This->pin_out.IPin_iface;
716 IPin_AddRef(*pin);
717 return S_OK;
719 *pin = NULL;
720 return VFW_E_NOT_FOUND;
723 /* IBaseFilter */
724 static HRESULT WINAPI
725 SampleGrabber_IBaseFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info)
727 SG_Impl *This = impl_from_IBaseFilter(iface);
728 TRACE("(%p)->(%p)\n", This, info);
729 if (!info)
730 return E_POINTER;
731 if (This->info.pGraph)
732 IFilterGraph_AddRef(This->info.pGraph);
733 *info = This->info;
734 return S_OK;
737 /* IBaseFilter */
738 static HRESULT WINAPI
739 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
741 SG_Impl *This = impl_from_IBaseFilter(iface);
742 TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
743 This->info.pGraph = graph;
744 if (name)
745 lstrcpynW(This->info.achName,name,MAX_FILTER_NAME);
746 This->oneShot = OneShot_None;
747 return S_OK;
750 /* IBaseFilter */
751 static HRESULT WINAPI
752 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
754 TRACE("(%p)\n", vendor);
755 if (!vendor)
756 return E_POINTER;
757 *vendor = CoTaskMemAlloc(sizeof(vendor_name));
758 CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
759 return S_OK;
763 /* SampleGrabber implementation of ISampleGrabber interface */
765 /* IUnknown */
766 static HRESULT WINAPI
767 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv)
769 SG_Impl *This = impl_from_ISampleGrabber(iface);
770 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
773 /* IUnknown */
774 static ULONG WINAPI
775 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
777 SG_Impl *This = impl_from_ISampleGrabber(iface);
778 return IUnknown_AddRef(This->outer_unk);
781 /* IUnknown */
782 static ULONG WINAPI
783 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
785 SG_Impl *This = impl_from_ISampleGrabber(iface);
786 return IUnknown_Release(This->outer_unk);
789 /* ISampleGrabber */
790 static HRESULT WINAPI
791 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
793 SG_Impl *This = impl_from_ISampleGrabber(iface);
794 TRACE("(%p)->(%u)\n", This, oneShot);
795 This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
796 return S_OK;
799 /* ISampleGrabber */
800 static HRESULT WINAPI
801 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
803 SG_Impl *This = impl_from_ISampleGrabber(iface);
804 TRACE("(%p)->(%p)\n", This, type);
805 if (!type)
806 return E_POINTER;
807 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
808 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
809 type->lSampleSize,
810 debugstr_guid(&type->formattype), type->cbFormat);
811 if (This->mtype.pbFormat)
812 CoTaskMemFree(This->mtype.pbFormat);
813 This->mtype = *type;
814 This->mtype.pUnk = NULL;
815 if (type->cbFormat) {
816 This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
817 CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat);
819 else
820 This->mtype.pbFormat = NULL;
821 return S_OK;
824 /* ISampleGrabber */
825 static HRESULT WINAPI
826 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
828 SG_Impl *This = impl_from_ISampleGrabber(iface);
829 TRACE("(%p)->(%p)\n", This, type);
830 if (!type)
831 return E_POINTER;
832 if (!This->pin_in.pair)
833 return VFW_E_NOT_CONNECTED;
834 *type = This->mtype;
835 if (type->cbFormat) {
836 type->pbFormat = CoTaskMemAlloc(type->cbFormat);
837 CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat);
839 return S_OK;
842 /* ISampleGrabber */
843 static HRESULT WINAPI
844 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
846 SG_Impl *This = impl_from_ISampleGrabber(iface);
847 TRACE("(%p)->(%u)\n", This, bufferEm);
848 EnterCriticalSection(&This->critSect);
849 if (bufferEm) {
850 if (This->bufferLen < 0)
851 This->bufferLen = 0;
853 else
854 This->bufferLen = -1;
855 LeaveCriticalSection(&This->critSect);
856 return S_OK;
859 /* ISampleGrabber */
860 static HRESULT WINAPI
861 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
863 SG_Impl *This = impl_from_ISampleGrabber(iface);
864 HRESULT ret = S_OK;
865 TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer);
866 if (!bufSize)
867 return E_POINTER;
868 EnterCriticalSection(&This->critSect);
869 if (!This->pin_in.pair)
870 ret = VFW_E_NOT_CONNECTED;
871 else if (This->bufferLen < 0)
872 ret = E_INVALIDARG;
873 else if (This->bufferLen == 0)
874 ret = VFW_E_WRONG_STATE;
875 else {
876 if (buffer) {
877 if (*bufSize >= This->bufferLen)
878 CopyMemory(buffer, This->bufferData, This->bufferLen);
879 else
880 ret = E_OUTOFMEMORY;
882 *bufSize = This->bufferLen;
884 LeaveCriticalSection(&This->critSect);
885 return ret;
888 /* ISampleGrabber */
889 static HRESULT WINAPI
890 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
892 /* MS doesn't implement it either, no one should call it */
893 WARN("(%p): not implemented\n", sample);
894 return E_NOTIMPL;
897 /* ISampleGrabber */
898 static HRESULT WINAPI
899 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
901 SG_Impl *This = impl_from_ISampleGrabber(iface);
902 TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
903 if (This->grabberIface)
904 ISampleGrabberCB_Release(This->grabberIface);
905 This->grabberIface = cb;
906 This->grabberMethod = whichMethod;
907 if (cb)
908 ISampleGrabberCB_AddRef(cb);
909 return S_OK;
913 /* SampleGrabber implementation of IMemInputPin interface */
915 /* IUnknown */
916 static HRESULT WINAPI
917 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv)
919 SG_Impl *This = impl_from_IMemInputPin(iface);
920 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
923 /* IUnknown */
924 static ULONG WINAPI
925 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
927 SG_Impl *This = impl_from_IMemInputPin(iface);
928 return IUnknown_AddRef(This->outer_unk);
931 /* IUnknown */
932 static ULONG WINAPI
933 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
935 SG_Impl *This = impl_from_IMemInputPin(iface);
936 return IUnknown_Release(This->outer_unk);
939 /* IMemInputPin */
940 static HRESULT WINAPI
941 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
943 SG_Impl *This = impl_from_IMemInputPin(iface);
944 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
945 if (!allocator)
946 return E_POINTER;
947 *allocator = This->allocator;
948 if (!*allocator)
949 return VFW_E_NO_ALLOCATOR;
950 IMemAllocator_AddRef(*allocator);
951 return S_OK;
954 /* IMemInputPin */
955 static HRESULT WINAPI
956 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
958 SG_Impl *This = impl_from_IMemInputPin(iface);
959 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
960 if (This->allocator == allocator)
961 return S_OK;
962 if (This->allocator)
963 IMemAllocator_Release(This->allocator);
964 This->allocator = allocator;
965 if (allocator)
966 IMemAllocator_AddRef(allocator);
967 return S_OK;
970 /* IMemInputPin */
971 static HRESULT WINAPI
972 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
974 SG_Impl *This = impl_from_IMemInputPin(iface);
975 FIXME("(%p)->(%p): semi-stub\n", This, props);
976 if (!props)
977 return E_POINTER;
978 return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL;
981 /* IMemInputPin */
982 static HRESULT WINAPI
983 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
985 SG_Impl *This = impl_from_IMemInputPin(iface);
986 HRESULT hr;
987 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface);
988 if (!sample)
989 return E_POINTER;
990 if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
991 return S_FALSE;
992 SampleGrabber_callback(This, sample);
993 hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK;
994 if (This->oneShot == OneShot_Wait) {
995 This->oneShot = OneShot_Past;
996 hr = S_FALSE;
997 if (This->pin_out.pair)
998 IPin_EndOfStream(This->pin_out.pair);
1000 return hr;
1003 /* IMemInputPin */
1004 static HRESULT WINAPI
1005 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
1007 SG_Impl *This = impl_from_IMemInputPin(iface);
1008 LONG idx;
1009 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface);
1010 if (!samples || !nProcessed)
1011 return E_POINTER;
1012 if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
1013 return S_FALSE;
1014 for (idx = 0; idx < nSamples; idx++)
1015 SampleGrabber_callback(This, samples[idx]);
1016 return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK;
1019 /* IMemInputPin */
1020 static HRESULT WINAPI
1021 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
1023 SG_Impl *This = impl_from_IMemInputPin(iface);
1024 TRACE("(%p)\n", This);
1025 return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK;
1029 /* SampleGrabber member pin implementation */
1031 /* IUnknown */
1032 static ULONG WINAPI
1033 SampleGrabber_IPin_AddRef(IPin *iface)
1035 SG_Pin *This = impl_from_IPin(iface);
1036 return ISampleGrabber_AddRef(&This->sg->ISampleGrabber_iface);
1039 /* IUnknown */
1040 static ULONG WINAPI
1041 SampleGrabber_IPin_Release(IPin *iface)
1043 SG_Pin *This = impl_from_IPin(iface);
1044 return ISampleGrabber_Release(&This->sg->ISampleGrabber_iface);
1047 /* IUnknown */
1048 static HRESULT WINAPI
1049 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
1051 SG_Pin *This = impl_from_IPin(iface);
1052 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1054 *ppv = NULL;
1055 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
1056 *ppv = iface;
1057 else if (IsEqualIID(riid, &IID_IMemInputPin))
1058 *ppv = &This->sg->IMemInputPin_iface;
1059 else if (IsEqualIID(riid, &IID_IMediaSeeking))
1060 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
1061 else if (IsEqualIID(riid, &IID_IMediaPosition))
1062 return IUnknown_QueryInterface(&This->sg->IUnknown_inner, riid, ppv);
1063 else {
1064 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
1065 return E_NOINTERFACE;
1068 IUnknown_AddRef((IUnknown*)*ppv);
1069 return S_OK;
1072 /* IPin - input pin */
1073 static HRESULT WINAPI
1074 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype)
1076 WARN("(%p, %p): unexpected\n", receiver, mtype);
1077 return E_UNEXPECTED;
1080 /* IPin - output pin */
1081 static HRESULT WINAPI
1082 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type)
1084 SG_Pin *This = impl_from_IPin(iface);
1085 HRESULT hr;
1087 TRACE("(%p)->(%p, %p)\n", This, receiver, type);
1088 if (!receiver)
1089 return E_POINTER;
1090 if (This->pair)
1091 return VFW_E_ALREADY_CONNECTED;
1092 if (This->sg->state != State_Stopped)
1093 return VFW_E_NOT_STOPPED;
1094 if (type) {
1095 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1096 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1097 type->lSampleSize,
1098 debugstr_guid(&type->formattype), type->cbFormat);
1099 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1100 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1101 return VFW_E_TYPE_NOT_ACCEPTED;
1102 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1103 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1104 return VFW_E_TYPE_NOT_ACCEPTED;
1105 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1106 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1107 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1108 return VFW_E_TYPE_NOT_ACCEPTED;
1110 else
1111 type = &This->sg->mtype;
1112 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
1113 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
1114 !type->pbFormat)
1115 return VFW_E_TYPE_NOT_ACCEPTED;
1116 hr = IPin_ReceiveConnection(receiver, &This->IPin_iface, type);
1117 if (FAILED(hr))
1118 return hr;
1119 This->pair = receiver;
1120 if (This->sg->memOutput) {
1121 IMemInputPin_Release(This->sg->memOutput);
1122 This->sg->memOutput = NULL;
1124 IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput));
1125 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput);
1126 return S_OK;
1129 /* IPin - input pin */
1130 static HRESULT WINAPI
1131 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type)
1133 SG_Pin *This = impl_from_IPin(iface);
1135 TRACE("(%p)->(%p, %p)\n", This, connector, type);
1136 if (!connector)
1137 return E_POINTER;
1138 if (This->pair)
1139 return VFW_E_ALREADY_CONNECTED;
1140 if (This->sg->state != State_Stopped)
1141 return VFW_E_NOT_STOPPED;
1142 if (type) {
1143 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1144 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1145 type->lSampleSize,
1146 debugstr_guid(&type->formattype), type->cbFormat);
1147 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
1148 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
1149 !type->pbFormat)
1150 return VFW_E_INVALIDMEDIATYPE;
1151 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1152 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1153 return VFW_E_TYPE_NOT_ACCEPTED;
1154 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1155 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1156 return VFW_E_TYPE_NOT_ACCEPTED;
1157 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1158 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1159 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1160 return VFW_E_TYPE_NOT_ACCEPTED;
1161 if (This->sg->mtype.pbFormat)
1162 CoTaskMemFree(This->sg->mtype.pbFormat);
1163 This->sg->mtype = *type;
1164 This->sg->mtype.pUnk = NULL;
1165 if (type->cbFormat) {
1166 This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
1167 CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat);
1169 else
1170 This->sg->mtype.pbFormat = NULL;
1172 This->pair = connector;
1173 TRACE("(%p) Accepted IPin %p\n", This, connector);
1174 return S_OK;
1177 /* IPin - output pin */
1178 static HRESULT WINAPI
1179 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype)
1181 WARN("(%p, %p): unexpected\n", connector, mtype);
1182 return E_UNEXPECTED;
1185 /* IPin - input pin */
1186 static HRESULT WINAPI
1187 SampleGrabber_In_IPin_Disconnect(IPin *iface)
1189 SG_Pin *This = impl_from_IPin(iface);
1191 TRACE("(%p)->() pair = %p\n", This, This->pair);
1192 if (This->sg->state != State_Stopped)
1193 return VFW_E_NOT_STOPPED;
1194 if (This->pair) {
1195 This->pair = NULL;
1196 return S_OK;
1198 return S_FALSE;
1201 /* IPin - output pin */
1202 static HRESULT WINAPI
1203 SampleGrabber_Out_IPin_Disconnect(IPin *iface)
1205 SG_Pin *This = impl_from_IPin(iface);
1207 TRACE("(%p)->() pair = %p\n", This, This->pair);
1208 if (This->sg->state != State_Stopped)
1209 return VFW_E_NOT_STOPPED;
1210 if (This->pair) {
1211 This->pair = NULL;
1212 if (This->sg->memOutput) {
1213 IMemInputPin_Release(This->sg->memOutput);
1214 This->sg->memOutput = NULL;
1216 return S_OK;
1218 return S_FALSE;
1221 /* IPin */
1222 static HRESULT WINAPI
1223 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin)
1225 SG_Pin *This = impl_from_IPin(iface);
1227 TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair);
1228 if (!pin)
1229 return E_POINTER;
1230 *pin = This->pair;
1231 if (*pin) {
1232 IPin_AddRef(*pin);
1233 return S_OK;
1235 return VFW_E_NOT_CONNECTED;
1238 /* IPin */
1239 static HRESULT WINAPI
1240 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype)
1242 SG_Pin *This = impl_from_IPin(iface);
1244 TRACE("(%p)->(%p)\n", This, mtype);
1245 if (!mtype)
1246 return E_POINTER;
1247 if (!This->pair)
1248 return VFW_E_NOT_CONNECTED;
1249 *mtype = This->sg->mtype;
1250 if (mtype->cbFormat) {
1251 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
1252 CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat);
1254 return S_OK;
1257 /* IPin */
1258 static HRESULT WINAPI
1259 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info)
1261 SG_Pin *This = impl_from_IPin(iface);
1263 TRACE("(%p)->(%p)\n", This, info);
1264 if (!info)
1265 return E_POINTER;
1266 IBaseFilter_AddRef(&This->sg->IBaseFilter_iface);
1267 info->pFilter = &This->sg->IBaseFilter_iface;
1268 info->dir = This->dir;
1269 lstrcpynW(info->achName,This->name,MAX_PIN_NAME);
1270 return S_OK;
1273 /* IPin */
1274 static HRESULT WINAPI
1275 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1277 SG_Pin *This = impl_from_IPin(iface);
1279 TRACE("(%p)->(%p)\n", This, dir);
1280 if (!dir)
1281 return E_POINTER;
1282 *dir = This->dir;
1283 return S_OK;
1286 /* IPin */
1287 static HRESULT WINAPI
1288 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id)
1290 SG_Pin *This = impl_from_IPin(iface);
1292 int len;
1293 TRACE("(%p)->(%p)\n", This, id);
1294 if (!id)
1295 return E_POINTER;
1296 len = sizeof(WCHAR)*(1+lstrlenW(This->name));
1297 *id = CoTaskMemAlloc(len);
1298 CopyMemory(*id, This->name, len);
1299 return S_OK;
1302 /* IPin */
1303 static HRESULT WINAPI
1304 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype)
1306 TRACE("(%p)\n", mtype);
1307 return S_OK;
1310 /* IPin */
1311 static HRESULT WINAPI
1312 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes)
1314 SG_Pin *This = impl_from_IPin(iface);
1316 TRACE("(%p)->(%p)\n", This, mtypes);
1317 if (!mtypes)
1318 return E_POINTER;
1319 *mtypes = mediaenum_create(This->sg->pin_in.pair ? &This->sg->mtype : NULL);
1320 return *mtypes ? S_OK : E_OUTOFMEMORY;
1323 /* IPin - input pin */
1324 static HRESULT WINAPI
1325 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1327 SG_Pin *This = impl_from_IPin(iface);
1329 TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0));
1330 if (!nPins)
1331 return E_POINTER;
1332 if (*nPins) {
1333 if (!pins)
1334 return E_POINTER;
1335 IPin_AddRef(&This->sg->pin_out.IPin_iface);
1336 *pins = &This->sg->pin_out.IPin_iface;
1337 *nPins = 1;
1338 return S_OK;
1340 *nPins = 1;
1341 return S_FALSE;
1344 /* IPin - output pin */
1345 static HRESULT WINAPI
1346 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1348 WARN("(%p, %p): unexpected\n", pins, nPins);
1349 if (nPins)
1350 *nPins = 0;
1351 return E_NOTIMPL;
1354 /* IPin */
1355 static HRESULT WINAPI
1356 SampleGrabber_IPin_EndOfStream(IPin *iface)
1358 FIXME(": stub\n");
1359 return S_OK;
1362 /* IPin */
1363 static HRESULT WINAPI
1364 SampleGrabber_IPin_BeginFlush(IPin *iface)
1366 FIXME(": stub\n");
1367 return S_OK;
1370 /* IPin */
1371 static HRESULT WINAPI
1372 SampleGrabber_IPin_EndFlush(IPin *iface)
1374 FIXME(": stub\n");
1375 return S_OK;
1378 /* IPin */
1379 static HRESULT WINAPI
1380 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate)
1382 FIXME(": stub\n");
1383 return S_OK;
1387 /* SampleGrabber vtables and constructor */
1389 static const IBaseFilterVtbl IBaseFilter_VTable =
1391 SampleGrabber_IBaseFilter_QueryInterface,
1392 SampleGrabber_IBaseFilter_AddRef,
1393 SampleGrabber_IBaseFilter_Release,
1394 SampleGrabber_IBaseFilter_GetClassID,
1395 SampleGrabber_IBaseFilter_Stop,
1396 SampleGrabber_IBaseFilter_Pause,
1397 SampleGrabber_IBaseFilter_Run,
1398 SampleGrabber_IBaseFilter_GetState,
1399 SampleGrabber_IBaseFilter_SetSyncSource,
1400 SampleGrabber_IBaseFilter_GetSyncSource,
1401 SampleGrabber_IBaseFilter_EnumPins,
1402 SampleGrabber_IBaseFilter_FindPin,
1403 SampleGrabber_IBaseFilter_QueryFilterInfo,
1404 SampleGrabber_IBaseFilter_JoinFilterGraph,
1405 SampleGrabber_IBaseFilter_QueryVendorInfo,
1408 static const ISampleGrabberVtbl ISampleGrabber_VTable =
1410 SampleGrabber_ISampleGrabber_QueryInterface,
1411 SampleGrabber_ISampleGrabber_AddRef,
1412 SampleGrabber_ISampleGrabber_Release,
1413 SampleGrabber_ISampleGrabber_SetOneShot,
1414 SampleGrabber_ISampleGrabber_SetMediaType,
1415 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
1416 SampleGrabber_ISampleGrabber_SetBufferSamples,
1417 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
1418 SampleGrabber_ISampleGrabber_GetCurrentSample,
1419 SampleGrabber_ISampleGrabber_SetCallback,
1422 static const IMemInputPinVtbl IMemInputPin_VTable =
1424 SampleGrabber_IMemInputPin_QueryInterface,
1425 SampleGrabber_IMemInputPin_AddRef,
1426 SampleGrabber_IMemInputPin_Release,
1427 SampleGrabber_IMemInputPin_GetAllocator,
1428 SampleGrabber_IMemInputPin_NotifyAllocator,
1429 SampleGrabber_IMemInputPin_GetAllocatorRequirements,
1430 SampleGrabber_IMemInputPin_Receive,
1431 SampleGrabber_IMemInputPin_ReceiveMultiple,
1432 SampleGrabber_IMemInputPin_ReceiveCanBlock,
1435 static const IPinVtbl IPin_In_VTable =
1437 SampleGrabber_IPin_QueryInterface,
1438 SampleGrabber_IPin_AddRef,
1439 SampleGrabber_IPin_Release,
1440 SampleGrabber_In_IPin_Connect,
1441 SampleGrabber_In_IPin_ReceiveConnection,
1442 SampleGrabber_In_IPin_Disconnect,
1443 SampleGrabber_IPin_ConnectedTo,
1444 SampleGrabber_IPin_ConnectionMediaType,
1445 SampleGrabber_IPin_QueryPinInfo,
1446 SampleGrabber_IPin_QueryDirection,
1447 SampleGrabber_IPin_QueryId,
1448 SampleGrabber_IPin_QueryAccept,
1449 SampleGrabber_IPin_EnumMediaTypes,
1450 SampleGrabber_In_IPin_QueryInternalConnections,
1451 SampleGrabber_IPin_EndOfStream,
1452 SampleGrabber_IPin_BeginFlush,
1453 SampleGrabber_IPin_EndFlush,
1454 SampleGrabber_IPin_NewSegment,
1457 static const IPinVtbl IPin_Out_VTable =
1459 SampleGrabber_IPin_QueryInterface,
1460 SampleGrabber_IPin_AddRef,
1461 SampleGrabber_IPin_Release,
1462 SampleGrabber_Out_IPin_Connect,
1463 SampleGrabber_Out_IPin_ReceiveConnection,
1464 SampleGrabber_Out_IPin_Disconnect,
1465 SampleGrabber_IPin_ConnectedTo,
1466 SampleGrabber_IPin_ConnectionMediaType,
1467 SampleGrabber_IPin_QueryPinInfo,
1468 SampleGrabber_IPin_QueryDirection,
1469 SampleGrabber_IPin_QueryId,
1470 SampleGrabber_IPin_QueryAccept,
1471 SampleGrabber_IPin_EnumMediaTypes,
1472 SampleGrabber_Out_IPin_QueryInternalConnections,
1473 SampleGrabber_IPin_EndOfStream,
1474 SampleGrabber_IPin_BeginFlush,
1475 SampleGrabber_IPin_EndFlush,
1476 SampleGrabber_IPin_NewSegment,
1479 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
1481 SG_Impl* obj = NULL;
1482 ISeekingPassThru *passthru;
1483 HRESULT hr;
1485 TRACE("(%p,%p)\n", ppv, pUnkOuter);
1487 obj = CoTaskMemAlloc(sizeof(SG_Impl));
1488 if (NULL == obj) {
1489 *ppv = NULL;
1490 return E_OUTOFMEMORY;
1492 ZeroMemory(obj, sizeof(SG_Impl));
1494 obj->ref = 1;
1495 obj->IUnknown_inner.lpVtbl = &samplegrabber_vtbl;
1496 obj->IBaseFilter_iface.lpVtbl = &IBaseFilter_VTable;
1497 obj->ISampleGrabber_iface.lpVtbl = &ISampleGrabber_VTable;
1498 obj->IMemInputPin_iface.lpVtbl = &IMemInputPin_VTable;
1499 obj->pin_in.IPin_iface.lpVtbl = &IPin_In_VTable;
1500 obj->pin_in.dir = PINDIR_INPUT;
1501 obj->pin_in.name = pin_in_name;
1502 obj->pin_in.sg = obj;
1503 obj->pin_in.pair = NULL;
1504 obj->pin_out.IPin_iface.lpVtbl = &IPin_Out_VTable;
1505 obj->pin_out.dir = PINDIR_OUTPUT;
1506 obj->pin_out.name = pin_out_name;
1507 obj->pin_out.sg = obj;
1508 obj->pin_out.pair = NULL;
1509 InitializeCriticalSection(&obj->critSect);
1510 obj->critSect.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SG_Impl.critSect");
1511 obj->info.achName[0] = 0;
1512 obj->info.pGraph = NULL;
1513 obj->state = State_Stopped;
1514 obj->mtype.majortype = GUID_NULL;
1515 obj->mtype.subtype = MEDIASUBTYPE_None;
1516 obj->mtype.formattype = FORMAT_None;
1517 obj->allocator = NULL;
1518 obj->refClock = NULL;
1519 obj->memOutput = NULL;
1520 obj->grabberIface = NULL;
1521 obj->grabberMethod = -1;
1522 obj->oneShot = OneShot_None;
1523 obj->bufferLen = -1;
1524 obj->bufferData = NULL;
1526 if (pUnkOuter)
1527 obj->outer_unk = pUnkOuter;
1528 else
1529 obj->outer_unk = &obj->IUnknown_inner;
1531 hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)obj, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&obj->seekthru_unk);
1532 if(hr)
1533 return hr;
1534 IUnknown_QueryInterface(obj->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
1535 ISeekingPassThru_Init(passthru, FALSE, &obj->pin_in.IPin_iface);
1536 ISeekingPassThru_Release(passthru);
1538 *ppv = &obj->IUnknown_inner;
1539 return S_OK;