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
30 #include "qedit_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(qedit);
35 static WCHAR const vendor_name[] = { 'W', 'i', 'n', 'e', 0 };
36 static WCHAR const pin_in_name[] = { 'I', 'n', 0 };
37 static WCHAR const pin_out_name[] = { 'O', 'u', 't', 0 };
39 IEnumPins *pinsenum_create(IBaseFilter *filter, IPin **pins, ULONG pinCount);
40 IEnumMediaTypes *mediaenum_create(AM_MEDIA_TYPE *mtype);
42 /* Fixed pins enumerator, holds filter referenced */
43 typedef struct _PE_Impl {
53 /* IEnumPins interface implementation */
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);
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);
74 IBaseFilter_Release(This->filter);
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);
95 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
100 static HRESULT WINAPI
101 Fixed_IEnumPins_Next(IEnumPins *iface, ULONG nPins, IPin **pins, ULONG *fetched)
103 PE_Impl *This = (PE_Impl *)iface;
105 TRACE("(%p)->(%u, %p, %p) index = %u\n", This, nPins, pins, fetched, This->index);
108 if (!pins || ((nPins != 1) && !fetched))
110 while ((count < nPins) && (This->index < This->numPins)) {
111 IPin *pin = This->pins[This->index++];
117 return (count == nPins) ? S_OK : S_FALSE;
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;
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);
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);
153 *pins = pinsenum_create(This->filter, This->pins, This->numPins);
155 return E_OUTOFMEMORY;
156 ((PE_Impl *)*pins)->index = This->index;
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 IEnumPins *pinsenum_create(IBaseFilter *filter, IPin **pins, ULONG pinCount)
176 ULONG len = sizeof(PE_Impl) + (pinCount * sizeof(IPin *));
177 PE_Impl *obj = CoTaskMemAlloc(len);
180 ZeroMemory(obj, len);
181 obj->pe.lpVtbl = &IEnumPins_VTable;
183 obj->filter = filter;
184 obj->numPins = pinCount;
186 for (i=0; i<pinCount; i++)
187 obj->pins[i] = pins[i];
188 IBaseFilter_AddRef(filter);
194 /* Single media type enumerator */
195 typedef struct _ME_Impl {
203 /* IEnumMediaTypes interface implementation */
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);
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);
224 if (This->mtype.pbFormat)
225 CoTaskMemFree(This->mtype.pbFormat);
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);
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;
256 TRACE("(%p)->(%u, %p, %p)\n", This, nTypes, types, fetched);
259 if (!types || ((nTypes != 1) && !fetched))
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);
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);
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);
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);
306 *me = mediaenum_create(&This->mtype);
308 return E_OUTOFMEMORY;
309 ((ME_Impl *)*me)->past = This->past;
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 IEnumMediaTypes *mediaenum_create(AM_MEDIA_TYPE *mtype)
329 ME_Impl *obj = CoTaskMemAlloc(sizeof(ME_Impl));
331 ZeroMemory(obj, sizeof(ME_Impl));
332 obj->me.lpVtbl = &IEnumMediaTypes_VTable;
336 obj->mtype.pUnk = NULL;
337 if (mtype->cbFormat) {
338 obj->mtype.pbFormat = CoTaskMemAlloc(mtype->cbFormat);
339 CopyMemory(obj->mtype.pbFormat, mtype->pbFormat, mtype->cbFormat);
342 obj->mtype.pbFormat = NULL;
348 /* Sample Grabber pin implementation */
349 typedef struct _SG_Pin {
350 const IPinVtbl* lpVtbl;
357 /* Sample Grabber filter implementation */
358 typedef struct _SG_Impl {
359 const IBaseFilterVtbl* IBaseFilter_Vtbl;
360 const ISampleGrabberVtbl* ISampleGrabber_Vtbl;
361 const IMemInputPinVtbl* IMemInputPin_Vtbl;
362 /* TODO: IMediaPosition, IMediaSeeking, IQualityControl */
369 IMemAllocator *allocator;
370 IReferenceClock *refClock;
371 IMemInputPin *memOutput;
372 ISampleGrabberCB *grabberIface;
383 /* Get the SampleGrabber implementation This pointer from various interface pointers */
384 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
386 return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, IBaseFilter_Vtbl));
389 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
391 return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, ISampleGrabber_Vtbl));
394 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface)
396 return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, IMemInputPin_Vtbl));
400 /* Cleanup at end of life */
401 static void SampleGrabber_cleanup(SG_Impl *This)
403 TRACE("(%p)\n", This);
404 if (This->info.pGraph)
405 WARN("(%p) still joined to filter graph %p\n", This, This->info.pGraph);
407 IMemAllocator_Release(This->allocator);
409 IReferenceClock_Release(This->refClock);
411 IMemInputPin_Release(This->memOutput);
412 if (This->grabberIface)
413 ISampleGrabberCB_Release(This->grabberIface);
414 if (This->mtype.pbFormat)
415 CoTaskMemFree(This->mtype.pbFormat);
418 /* Common helper AddRef called from all interfaces */
419 static ULONG SampleGrabber_addref(SG_Impl *This)
421 ULONG refCount = InterlockedIncrement(&This->refCount);
422 TRACE("(%p) new ref = %u\n", This, refCount);
426 /* Common helper Release called from all interfaces */
427 static ULONG SampleGrabber_release(SG_Impl *This)
429 ULONG refCount = InterlockedDecrement(&This->refCount);
430 TRACE("(%p) new ref = %u\n", This, refCount);
433 SampleGrabber_cleanup(This);
440 /* Common helper QueryInterface called from all interfaces */
441 static HRESULT SampleGrabber_query(SG_Impl *This, REFIID riid, void **ppvObject)
443 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
445 if (IsEqualIID(riid, &IID_IUnknown) ||
446 IsEqualIID(riid, &IID_IPersist) ||
447 IsEqualIID(riid, &IID_IMediaFilter) ||
448 IsEqualIID(riid, &IID_IBaseFilter)) {
449 SampleGrabber_addref(This);
450 *ppvObject = &(This->IBaseFilter_Vtbl);
453 else if (IsEqualIID(riid, &IID_ISampleGrabber)) {
454 SampleGrabber_addref(This);
455 *ppvObject = &(This->ISampleGrabber_Vtbl);
458 else if (IsEqualIID(riid, &IID_IMemInputPin)) {
459 SampleGrabber_addref(This);
460 *ppvObject = &(This->IMemInputPin_Vtbl);
463 else if (IsEqualIID(riid, &IID_IMediaPosition))
464 FIXME("IMediaPosition not implemented\n");
465 else if (IsEqualIID(riid, &IID_IMediaSeeking))
466 FIXME("IMediaSeeking not implemented\n");
467 else if (IsEqualIID(riid, &IID_IQualityControl))
468 FIXME("IQualityControl not implemented\n");
470 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
471 return E_NOINTERFACE;
474 /* Helper that calls installed sample callbacks */
475 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
478 REFERENCE_TIME tStart, tEnd;
479 if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
480 time = 1e-7 * tStart;
481 switch (This->grabberMethod) {
484 ULONG ref = IMediaSample_AddRef(sample);
485 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
486 ref = IMediaSample_Release(sample) + 1 - ref;
489 ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref);
490 /* ugly as hell but some apps are sooo buggy */
492 IMediaSample_Release(sample);
499 long size = IMediaSample_GetActualDataLength(sample);
500 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
501 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
507 FIXME("unsupported method %ld\n", (long int)This->grabberMethod);
508 /* do not bother us again */
509 This->grabberMethod = -1;
514 /* SampleGrabber implementation of IBaseFilter interface */
517 static HRESULT WINAPI
518 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppvObject)
520 return SampleGrabber_query(impl_from_IBaseFilter(iface), riid, ppvObject);
525 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
527 return SampleGrabber_addref(impl_from_IBaseFilter(iface));
532 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
534 return SampleGrabber_release(impl_from_IBaseFilter(iface));
538 static HRESULT WINAPI
539 SampleGrabber_IBaseFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID)
541 TRACE("(%p)\n", pClassID);
544 *pClassID = CLSID_SampleGrabber;
549 static HRESULT WINAPI
550 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
552 SG_Impl *This = impl_from_IBaseFilter(iface);
553 TRACE("(%p)\n", This);
554 This->state = State_Stopped;
559 static HRESULT WINAPI
560 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
562 SG_Impl *This = impl_from_IBaseFilter(iface);
563 TRACE("(%p)\n", This);
564 This->state = State_Paused;
569 static HRESULT WINAPI
570 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
572 SG_Impl *This = impl_from_IBaseFilter(iface);
573 TRACE("(%p)\n", This);
574 This->state = State_Running;
579 static HRESULT WINAPI
580 SampleGrabber_IBaseFilter_GetState(IBaseFilter *iface, DWORD msTout, FILTER_STATE *state)
582 SG_Impl *This = impl_from_IBaseFilter(iface);
583 TRACE("(%p)->(%u, %p)\n", This, msTout, state);
586 *state = This->state;
591 static HRESULT WINAPI
592 SampleGrabber_IBaseFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
594 SG_Impl *This = impl_from_IBaseFilter(iface);
595 TRACE("(%p)->(%p)\n", This, clock);
596 if (clock != This->refClock)
599 IReferenceClock_AddRef(clock);
601 IReferenceClock_Release(This->refClock);
602 This->refClock = clock;
608 static HRESULT WINAPI
609 SampleGrabber_IBaseFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock)
611 SG_Impl *This = impl_from_IBaseFilter(iface);
612 TRACE("(%p)->(%p)\n", This, clock);
616 IReferenceClock_AddRef(This->refClock);
617 *clock = This->refClock;
622 static HRESULT WINAPI
623 SampleGrabber_IBaseFilter_EnumPins(IBaseFilter *iface, IEnumPins **pins)
625 SG_Impl *This = impl_from_IBaseFilter(iface);
627 TRACE("(%p)->(%p)\n", This, pins);
630 pin[0] = (IPin*)&This->pin_in.lpVtbl;
631 pin[1] = (IPin*)&This->pin_out.lpVtbl;
632 *pins = pinsenum_create(iface, pin, 2);
633 return *pins ? S_OK : E_OUTOFMEMORY;
637 static HRESULT WINAPI
638 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
640 SG_Impl *This = impl_from_IBaseFilter(iface);
641 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin);
644 if (!lstrcmpiW(id,pin_in_name))
646 SampleGrabber_addref(This);
647 *pin = (IPin*)&(This->pin_in.lpVtbl);
650 else if (!lstrcmpiW(id,pin_out_name))
652 SampleGrabber_addref(This);
653 *pin = (IPin*)&(This->pin_out.lpVtbl);
657 return VFW_E_NOT_FOUND;
661 static HRESULT WINAPI
662 SampleGrabber_IBaseFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info)
664 SG_Impl *This = impl_from_IBaseFilter(iface);
665 TRACE("(%p)->(%p)\n", This, info);
668 if (This->info.pGraph)
669 IFilterGraph_AddRef(This->info.pGraph);
675 static HRESULT WINAPI
676 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
678 SG_Impl *This = impl_from_IBaseFilter(iface);
679 TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
680 This->info.pGraph = graph;
682 lstrcpynW(This->info.achName,name,MAX_FILTER_NAME);
683 This->oneShot = OneShot_None;
688 static HRESULT WINAPI
689 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
691 TRACE("(%p)\n", vendor);
694 *vendor = CoTaskMemAlloc(sizeof(vendor_name));
695 CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
700 /* SampleGrabber implementation of ISampleGrabber interface */
703 static HRESULT WINAPI
704 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppvObject)
706 return SampleGrabber_query(impl_from_ISampleGrabber(iface), riid, ppvObject);
711 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
713 return SampleGrabber_addref(impl_from_ISampleGrabber(iface));
718 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
720 return SampleGrabber_release(impl_from_ISampleGrabber(iface));
724 static HRESULT WINAPI
725 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
727 SG_Impl *This = impl_from_ISampleGrabber(iface);
728 TRACE("(%p)->(%u)\n", This, oneShot);
729 This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
734 static HRESULT WINAPI
735 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
737 SG_Impl *This = impl_from_ISampleGrabber(iface);
738 TRACE("(%p)->(%p)\n", This, type);
741 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
742 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
744 debugstr_guid(&type->formattype), type->cbFormat);
745 if (This->mtype.pbFormat)
746 CoTaskMemFree(This->mtype.pbFormat);
748 This->mtype.pUnk = NULL;
749 if (type->cbFormat) {
750 This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
751 CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat);
754 This->mtype.pbFormat = NULL;
759 static HRESULT WINAPI
760 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
762 SG_Impl *This = impl_from_ISampleGrabber(iface);
763 TRACE("(%p)->(%p)\n", This, type);
766 if (!This->pin_in.pair)
767 return VFW_E_NOT_CONNECTED;
769 if (type->cbFormat) {
770 type->pbFormat = CoTaskMemAlloc(type->cbFormat);
771 CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat);
777 static HRESULT WINAPI
778 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
780 TRACE("(%u)\n", bufferEm);
782 FIXME("buffering not implemented\n");
789 static HRESULT WINAPI
790 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
792 FIXME("(%p, %p): stub\n", bufSize, buffer);
799 static HRESULT WINAPI
800 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
802 /* MS doesn't implement it either, noone should call it */
803 WARN("(%p): not implemented\n", sample);
808 static HRESULT WINAPI
809 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
811 SG_Impl *This = impl_from_ISampleGrabber(iface);
812 TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
813 if (This->grabberIface)
814 ISampleGrabberCB_Release(This->grabberIface);
815 This->grabberIface = cb;
816 This->grabberMethod = whichMethod;
818 ISampleGrabberCB_AddRef(cb);
823 /* SampleGrabber implementation of IMemInputPin interface */
826 static HRESULT WINAPI
827 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppvObject)
829 return SampleGrabber_query(impl_from_IMemInputPin(iface), riid, ppvObject);
834 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
836 return SampleGrabber_addref(impl_from_IMemInputPin(iface));
841 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
843 return SampleGrabber_release(impl_from_IMemInputPin(iface));
847 static HRESULT WINAPI
848 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
850 SG_Impl *This = impl_from_IMemInputPin(iface);
851 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
854 *allocator = This->allocator;
856 return VFW_E_NO_ALLOCATOR;
857 IMemAllocator_AddRef(*allocator);
862 static HRESULT WINAPI
863 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
865 SG_Impl *This = impl_from_IMemInputPin(iface);
866 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
867 if (This->allocator == allocator)
870 IMemAllocator_Release(This->allocator);
871 This->allocator = allocator;
873 IMemAllocator_AddRef(allocator);
878 static HRESULT WINAPI
879 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
881 SG_Impl *This = impl_from_IMemInputPin(iface);
882 FIXME("(%p)->(%p): semi-stub\n", This, props);
885 return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL;
889 static HRESULT WINAPI
890 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
892 SG_Impl *This = impl_from_IMemInputPin(iface);
894 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface);
897 if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
899 if (This->grabberIface)
900 SampleGrabber_callback(This, sample);
901 hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK;
902 if (This->oneShot == OneShot_Wait) {
903 This->oneShot = OneShot_Past;
905 if (This->pin_out.pair)
906 IPin_EndOfStream(This->pin_out.pair);
912 static HRESULT WINAPI
913 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
915 SG_Impl *This = impl_from_IMemInputPin(iface);
916 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface);
917 if (!samples || !nProcessed)
919 if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
921 if (This->grabberIface) {
923 for (idx = 0; idx < nSamples; idx++)
924 SampleGrabber_callback(This, samples[idx]);
926 return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK;
930 static HRESULT WINAPI
931 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
933 SG_Impl *This = impl_from_IMemInputPin(iface);
934 TRACE("(%p)\n", This);
935 return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK;
939 /* SampleGrabber member pin implementation */
943 SampleGrabber_IPin_AddRef(IPin *iface)
945 return SampleGrabber_addref(((SG_Pin *)iface)->sg);
950 SampleGrabber_IPin_Release(IPin *iface)
952 return SampleGrabber_release(((SG_Pin *)iface)->sg);
956 static HRESULT WINAPI
957 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppvObject)
959 SG_Pin *This = (SG_Pin *)iface;
960 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
962 if (IsEqualIID(riid, &IID_IUnknown) ||
963 IsEqualIID(riid, &IID_IPin)) {
964 SampleGrabber_addref(This->sg);
968 else if (IsEqualIID(riid, &IID_IMemInputPin)) {
969 SampleGrabber_addref(This->sg);
970 *ppvObject = &(This->sg->IMemInputPin_Vtbl);
974 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
975 return E_NOINTERFACE;
978 /* IPin - input pin */
979 static HRESULT WINAPI
980 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype)
982 WARN("(%p, %p): unexpected\n", receiver, mtype);
986 /* IPin - output pin */
987 static HRESULT WINAPI
988 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type)
990 SG_Pin *This = (SG_Pin *)iface;
992 TRACE("(%p)->(%p, %p)\n", This, receiver, type);
996 return VFW_E_ALREADY_CONNECTED;
997 if (This->sg->state != State_Stopped)
998 return VFW_E_NOT_STOPPED;
1000 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1001 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1003 debugstr_guid(&type->formattype), type->cbFormat);
1004 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1005 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1006 return VFW_E_TYPE_NOT_ACCEPTED;
1007 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1008 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1009 return VFW_E_TYPE_NOT_ACCEPTED;
1010 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1011 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1012 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1013 return VFW_E_TYPE_NOT_ACCEPTED;
1016 type = &This->sg->mtype;
1017 hr = IPin_ReceiveConnection(receiver,(IPin*)&This->lpVtbl,type);
1020 This->pair = receiver;
1021 if (This->sg->memOutput) {
1022 IMemInputPin_Release(This->sg->memOutput);
1023 This->sg->memOutput = NULL;
1025 IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput));
1026 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput);
1030 /* IPin - input pin */
1031 static HRESULT WINAPI
1032 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type)
1034 SG_Pin *This = (SG_Pin *)iface;
1035 TRACE("(%p)->(%p, %p)\n", This, connector, type);
1039 return VFW_E_ALREADY_CONNECTED;
1040 if (This->sg->state != State_Stopped)
1041 return VFW_E_NOT_STOPPED;
1043 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1044 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1046 debugstr_guid(&type->formattype), type->cbFormat);
1047 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1048 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1049 return VFW_E_TYPE_NOT_ACCEPTED;
1050 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1051 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1052 return VFW_E_TYPE_NOT_ACCEPTED;
1053 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1054 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1055 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1056 return VFW_E_TYPE_NOT_ACCEPTED;
1057 if (This->sg->mtype.pbFormat)
1058 CoTaskMemFree(This->sg->mtype.pbFormat);
1059 This->sg->mtype = *type;
1060 This->sg->mtype.pUnk = NULL;
1061 if (type->cbFormat) {
1062 This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
1063 CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat);
1066 This->sg->mtype.pbFormat = NULL;
1068 This->pair = connector;
1069 TRACE("(%p) Accepted IPin %p\n", This, connector);
1073 /* IPin - output pin */
1074 static HRESULT WINAPI
1075 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype)
1077 WARN("(%p, %p): unexpected\n", connector, mtype);
1078 return E_UNEXPECTED;
1081 /* IPin - input pin */
1082 static HRESULT WINAPI
1083 SampleGrabber_In_IPin_Disconnect(IPin *iface)
1085 SG_Pin *This = (SG_Pin *)iface;
1086 TRACE("(%p)->() pair = %p\n", This, This->pair);
1087 if (This->sg->state != State_Stopped)
1088 return VFW_E_NOT_STOPPED;
1096 /* IPin - output pin */
1097 static HRESULT WINAPI
1098 SampleGrabber_Out_IPin_Disconnect(IPin *iface)
1100 SG_Pin *This = (SG_Pin *)iface;
1101 TRACE("(%p)->() pair = %p\n", This, This->pair);
1102 if (This->sg->state != State_Stopped)
1103 return VFW_E_NOT_STOPPED;
1106 if (This->sg->memOutput) {
1107 IMemInputPin_Release(This->sg->memOutput);
1108 This->sg->memOutput = NULL;
1116 static HRESULT WINAPI
1117 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin)
1119 SG_Pin *This = (SG_Pin *)iface;
1120 TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair);
1128 return VFW_E_NOT_CONNECTED;
1132 static HRESULT WINAPI
1133 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype)
1135 SG_Pin *This = (SG_Pin *)iface;
1136 TRACE("(%p)->(%p)\n", This, mtype);
1140 return VFW_E_NOT_CONNECTED;
1141 *mtype = This->sg->mtype;
1142 if (mtype->cbFormat) {
1143 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
1144 CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat);
1150 static HRESULT WINAPI
1151 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info)
1153 SG_Pin *This = (SG_Pin *)iface;
1154 TRACE("(%p)->(%p)\n", This, info);
1157 SampleGrabber_addref(This->sg);
1158 info->pFilter = (IBaseFilter *)This->sg;
1159 info->dir = This->dir;
1160 lstrcpynW(info->achName,This->name,MAX_PIN_NAME);
1165 static HRESULT WINAPI
1166 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1168 SG_Pin *This = (SG_Pin *)iface;
1169 TRACE("(%p)->(%p)\n", This, dir);
1177 static HRESULT WINAPI
1178 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id)
1180 SG_Pin *This = (SG_Pin *)iface;
1182 TRACE("(%p)->(%p)\n", This, id);
1185 len = sizeof(WCHAR)*(1+lstrlenW(This->name));
1186 *id = CoTaskMemAlloc(len);
1187 CopyMemory(*id, This->name, len);
1192 static HRESULT WINAPI
1193 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype)
1195 TRACE("(%p)\n", mtype);
1200 static HRESULT WINAPI
1201 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes)
1203 SG_Pin *This = (SG_Pin *)iface;
1204 TRACE("(%p)->(%p)\n", This, mtypes);
1207 *mtypes = mediaenum_create(&This->sg->mtype);
1208 return *mtypes ? S_OK : E_OUTOFMEMORY;
1211 /* IPin - input pin */
1212 static HRESULT WINAPI
1213 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1215 SG_Pin *This = (SG_Pin *)iface;
1216 TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0));
1222 IPin_AddRef((IPin*)&This->sg->pin_out.lpVtbl);
1223 *pins = (IPin*)&This->sg->pin_out.lpVtbl;
1231 /* IPin - output pin */
1232 static HRESULT WINAPI
1233 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1235 WARN("(%p, %p): unexpected\n", pins, nPins);
1242 static HRESULT WINAPI
1243 SampleGrabber_IPin_EndOfStream(IPin *iface)
1250 static HRESULT WINAPI
1251 SampleGrabber_IPin_BeginFlush(IPin *iface)
1258 static HRESULT WINAPI
1259 SampleGrabber_IPin_EndFlush(IPin *iface)
1266 static HRESULT WINAPI
1267 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate)
1274 /* SampleGrabber vtables and constructor */
1276 static const IBaseFilterVtbl IBaseFilter_VTable =
1278 SampleGrabber_IBaseFilter_QueryInterface,
1279 SampleGrabber_IBaseFilter_AddRef,
1280 SampleGrabber_IBaseFilter_Release,
1281 SampleGrabber_IBaseFilter_GetClassID,
1282 SampleGrabber_IBaseFilter_Stop,
1283 SampleGrabber_IBaseFilter_Pause,
1284 SampleGrabber_IBaseFilter_Run,
1285 SampleGrabber_IBaseFilter_GetState,
1286 SampleGrabber_IBaseFilter_SetSyncSource,
1287 SampleGrabber_IBaseFilter_GetSyncSource,
1288 SampleGrabber_IBaseFilter_EnumPins,
1289 SampleGrabber_IBaseFilter_FindPin,
1290 SampleGrabber_IBaseFilter_QueryFilterInfo,
1291 SampleGrabber_IBaseFilter_JoinFilterGraph,
1292 SampleGrabber_IBaseFilter_QueryVendorInfo,
1295 static const ISampleGrabberVtbl ISampleGrabber_VTable =
1297 SampleGrabber_ISampleGrabber_QueryInterface,
1298 SampleGrabber_ISampleGrabber_AddRef,
1299 SampleGrabber_ISampleGrabber_Release,
1300 SampleGrabber_ISampleGrabber_SetOneShot,
1301 SampleGrabber_ISampleGrabber_SetMediaType,
1302 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
1303 SampleGrabber_ISampleGrabber_SetBufferSamples,
1304 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
1305 SampleGrabber_ISampleGrabber_GetCurrentSample,
1306 SampleGrabber_ISampleGrabber_SetCallback,
1309 static const IMemInputPinVtbl IMemInputPin_VTable =
1311 SampleGrabber_IMemInputPin_QueryInterface,
1312 SampleGrabber_IMemInputPin_AddRef,
1313 SampleGrabber_IMemInputPin_Release,
1314 SampleGrabber_IMemInputPin_GetAllocator,
1315 SampleGrabber_IMemInputPin_NotifyAllocator,
1316 SampleGrabber_IMemInputPin_GetAllocatorRequirements,
1317 SampleGrabber_IMemInputPin_Receive,
1318 SampleGrabber_IMemInputPin_ReceiveMultiple,
1319 SampleGrabber_IMemInputPin_ReceiveCanBlock,
1322 static const IPinVtbl IPin_In_VTable =
1324 SampleGrabber_IPin_QueryInterface,
1325 SampleGrabber_IPin_AddRef,
1326 SampleGrabber_IPin_Release,
1327 SampleGrabber_In_IPin_Connect,
1328 SampleGrabber_In_IPin_ReceiveConnection,
1329 SampleGrabber_In_IPin_Disconnect,
1330 SampleGrabber_IPin_ConnectedTo,
1331 SampleGrabber_IPin_ConnectionMediaType,
1332 SampleGrabber_IPin_QueryPinInfo,
1333 SampleGrabber_IPin_QueryDirection,
1334 SampleGrabber_IPin_QueryId,
1335 SampleGrabber_IPin_QueryAccept,
1336 SampleGrabber_IPin_EnumMediaTypes,
1337 SampleGrabber_In_IPin_QueryInternalConnections,
1338 SampleGrabber_IPin_EndOfStream,
1339 SampleGrabber_IPin_BeginFlush,
1340 SampleGrabber_IPin_EndFlush,
1341 SampleGrabber_IPin_NewSegment,
1344 static const IPinVtbl IPin_Out_VTable =
1346 SampleGrabber_IPin_QueryInterface,
1347 SampleGrabber_IPin_AddRef,
1348 SampleGrabber_IPin_Release,
1349 SampleGrabber_Out_IPin_Connect,
1350 SampleGrabber_Out_IPin_ReceiveConnection,
1351 SampleGrabber_Out_IPin_Disconnect,
1352 SampleGrabber_IPin_ConnectedTo,
1353 SampleGrabber_IPin_ConnectionMediaType,
1354 SampleGrabber_IPin_QueryPinInfo,
1355 SampleGrabber_IPin_QueryDirection,
1356 SampleGrabber_IPin_QueryId,
1357 SampleGrabber_IPin_QueryAccept,
1358 SampleGrabber_IPin_EnumMediaTypes,
1359 SampleGrabber_Out_IPin_QueryInternalConnections,
1360 SampleGrabber_IPin_EndOfStream,
1361 SampleGrabber_IPin_BeginFlush,
1362 SampleGrabber_IPin_EndFlush,
1363 SampleGrabber_IPin_NewSegment,
1366 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
1368 SG_Impl* obj = NULL;
1370 TRACE("(%p,%p)\n", ppv, pUnkOuter);
1373 return CLASS_E_NOAGGREGATION;
1375 obj = CoTaskMemAlloc(sizeof(SG_Impl));
1378 return E_OUTOFMEMORY;
1380 ZeroMemory(obj, sizeof(SG_Impl));
1383 obj->IBaseFilter_Vtbl = &IBaseFilter_VTable;
1384 obj->ISampleGrabber_Vtbl = &ISampleGrabber_VTable;
1385 obj->IMemInputPin_Vtbl = &IMemInputPin_VTable;
1386 obj->pin_in.lpVtbl = &IPin_In_VTable;
1387 obj->pin_in.dir = PINDIR_INPUT;
1388 obj->pin_in.name = pin_in_name;
1389 obj->pin_in.sg = obj;
1390 obj->pin_in.pair = NULL;
1391 obj->pin_out.lpVtbl = &IPin_Out_VTable;
1392 obj->pin_out.dir = PINDIR_OUTPUT;
1393 obj->pin_out.name = pin_out_name;
1394 obj->pin_out.sg = obj;
1395 obj->pin_out.pair = NULL;
1396 obj->info.achName[0] = 0;
1397 obj->info.pGraph = NULL;
1398 obj->state = State_Stopped;
1399 obj->mtype.majortype = GUID_NULL;
1400 obj->mtype.subtype = MEDIASUBTYPE_None;
1401 obj->mtype.formattype = FORMAT_None;
1402 obj->allocator = NULL;
1403 obj->refClock = NULL;
1404 obj->memOutput = NULL;
1405 obj->grabberIface = NULL;
1406 obj->grabberMethod = -1;
1407 obj->oneShot = OneShot_None;