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);
41 /* Fixed pins enumerator, holds filter referenced */
42 typedef struct _PE_Impl {
52 /* IEnumPins interface implementation */
56 Fixed_IEnumPins_AddRef(IEnumPins *iface)
58 PE_Impl *This = (PE_Impl *)iface;
59 ULONG refCount = InterlockedIncrement(&This->refCount);
60 TRACE("(%p) new ref = %u\n", This, refCount);
66 Fixed_IEnumPins_Release(IEnumPins *iface)
68 PE_Impl *This = (PE_Impl *)iface;
69 ULONG refCount = InterlockedDecrement(&This->refCount);
70 TRACE("(%p) new ref = %u\n", This, refCount);
73 IBaseFilter_Release(This->filter);
82 Fixed_IEnumPins_QueryInterface(IEnumPins *iface, REFIID riid, void **ppvObject)
84 PE_Impl *This = (PE_Impl *)iface;
85 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
87 if (IsEqualIID(riid, &IID_IUnknown) ||
88 IsEqualIID(riid, &IID_IEnumPins)) {
89 Fixed_IEnumPins_AddRef(iface);
90 *ppvObject = &(This->pins);
94 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
100 Fixed_IEnumPins_Next(IEnumPins *iface, ULONG nPins, IPin **pins, ULONG *fetched)
102 PE_Impl *This = (PE_Impl *)iface;
104 TRACE("(%p)->(%u, %p, %p) index = %u\n", This, nPins, pins, fetched, This->index);
107 if (!pins || ((nPins != 1) && !fetched))
109 while ((count < nPins) && (This->index < This->numPins)) {
110 IPin *pin = This->pins[This->index++];
116 return (count == nPins) ? S_OK : S_FALSE;
120 static HRESULT WINAPI
121 Fixed_IEnumPins_Skip(IEnumPins *iface, ULONG nPins)
123 PE_Impl *This = (PE_Impl *)iface;
124 TRACE("(%p)->(%u) index = %u\n", This, nPins, This->index);
125 nPins += This->index;
126 if (nPins >= This->numPins) {
127 This->index = This->numPins;
135 static HRESULT WINAPI
136 Fixed_IEnumPins_Reset(IEnumPins *iface)
138 PE_Impl *This = (PE_Impl *)iface;
139 TRACE("(%p)->() index = %u\n", This, This->index);
145 static HRESULT WINAPI
146 Fixed_IEnumPins_Clone(IEnumPins *iface, IEnumPins **pins)
148 PE_Impl *This = (PE_Impl *)iface;
149 TRACE("(%p)->(%p) index = %u\n", This, pins, This->index);
152 *pins = pinsenum_create(This->filter, This->pins, This->numPins);
154 return E_OUTOFMEMORY;
155 ((PE_Impl *)*pins)->index = This->index;
160 /* Virtual tables and constructor */
162 static const IEnumPinsVtbl IEnumPins_VTable =
164 Fixed_IEnumPins_QueryInterface,
165 Fixed_IEnumPins_AddRef,
166 Fixed_IEnumPins_Release,
167 Fixed_IEnumPins_Next,
168 Fixed_IEnumPins_Skip,
169 Fixed_IEnumPins_Reset,
170 Fixed_IEnumPins_Clone,
173 IEnumPins *pinsenum_create(IBaseFilter *filter, IPin **pins, ULONG pinCount)
175 ULONG len = sizeof(PE_Impl) + (pinCount * sizeof(IPin *));
176 PE_Impl *obj = CoTaskMemAlloc(len);
179 ZeroMemory(obj, len);
180 obj->pe.lpVtbl = &IEnumPins_VTable;
182 obj->filter = filter;
183 obj->numPins = pinCount;
185 for (i=0; i<pinCount; i++)
186 obj->pins[i] = pins[i];
187 IBaseFilter_AddRef(filter);
193 /* Sample Grabber pin implementation */
194 typedef struct _SG_Pin {
195 const IPinVtbl* lpVtbl;
202 /* Sample Grabber filter implementation */
203 typedef struct _SG_Impl {
204 const IBaseFilterVtbl* IBaseFilter_Vtbl;
205 const ISampleGrabberVtbl* ISampleGrabber_Vtbl;
206 const IMemInputPinVtbl* IMemInputPin_Vtbl;
207 /* TODO: IMediaPosition, IMediaSeeking, IQualityControl */
214 IMemAllocator *allocator;
215 IReferenceClock *refClock;
216 IMemInputPin *memOutput;
217 ISampleGrabberCB *grabberIface;
228 /* Get the SampleGrabber implementation This pointer from various interface pointers */
229 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
231 return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, IBaseFilter_Vtbl));
234 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
236 return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, ISampleGrabber_Vtbl));
239 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface)
241 return (SG_Impl *)((char*)iface - FIELD_OFFSET(SG_Impl, IMemInputPin_Vtbl));
245 /* Cleanup at end of life */
246 static void SampleGrabber_cleanup(SG_Impl *This)
248 TRACE("(%p)\n", This);
249 if (This->info.pGraph)
250 WARN("(%p) still joined to filter graph %p\n", This, This->info.pGraph);
252 IMemAllocator_Release(This->allocator);
254 IReferenceClock_Release(This->refClock);
256 IMemInputPin_Release(This->memOutput);
257 if (This->grabberIface)
258 ISampleGrabberCB_Release(This->grabberIface);
259 if (This->mtype.pbFormat)
260 CoTaskMemFree(This->mtype.pbFormat);
263 /* Common helper AddRef called from all interfaces */
264 static ULONG SampleGrabber_addref(SG_Impl *This)
266 ULONG refCount = InterlockedIncrement(&This->refCount);
267 TRACE("(%p) new ref = %u\n", This, refCount);
271 /* Common helper Release called from all interfaces */
272 static ULONG SampleGrabber_release(SG_Impl *This)
274 ULONG refCount = InterlockedDecrement(&This->refCount);
275 TRACE("(%p) new ref = %u\n", This, refCount);
278 SampleGrabber_cleanup(This);
285 /* Common helper QueryInterface called from all interfaces */
286 static HRESULT SampleGrabber_query(SG_Impl *This, REFIID riid, void **ppvObject)
288 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
290 if (IsEqualIID(riid, &IID_IUnknown) ||
291 IsEqualIID(riid, &IID_IPersist) ||
292 IsEqualIID(riid, &IID_IMediaFilter) ||
293 IsEqualIID(riid, &IID_IBaseFilter)) {
294 SampleGrabber_addref(This);
295 *ppvObject = &(This->IBaseFilter_Vtbl);
298 else if (IsEqualIID(riid, &IID_ISampleGrabber)) {
299 SampleGrabber_addref(This);
300 *ppvObject = &(This->ISampleGrabber_Vtbl);
303 else if (IsEqualIID(riid, &IID_IMemInputPin)) {
304 SampleGrabber_addref(This);
305 *ppvObject = &(This->IMemInputPin_Vtbl);
308 else if (IsEqualIID(riid, &IID_IMediaPosition))
309 FIXME("IMediaPosition not implemented\n");
310 else if (IsEqualIID(riid, &IID_IMediaSeeking))
311 FIXME("IMediaSeeking not implemented\n");
312 else if (IsEqualIID(riid, &IID_IQualityControl))
313 FIXME("IQualityControl not implemented\n");
315 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
316 return E_NOINTERFACE;
319 /* Helper that calls installed sample callbacks */
320 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
323 REFERENCE_TIME tStart, tEnd;
324 if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
325 time = 1e-7 * tStart;
326 switch (This->grabberMethod) {
329 ULONG ref = IMediaSample_AddRef(sample);
330 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
331 ref = IMediaSample_Release(sample) + 1 - ref;
334 ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref);
335 /* ugly as hell but some apps are sooo buggy */
337 IMediaSample_Release(sample);
344 long size = IMediaSample_GetActualDataLength(sample);
345 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
346 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
352 FIXME("unsupported method %ld\n", (long int)This->grabberMethod);
353 /* do not bother us again */
354 This->grabberMethod = -1;
359 /* SampleGrabber implementation of IBaseFilter interface */
362 static HRESULT WINAPI
363 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppvObject)
365 return SampleGrabber_query(impl_from_IBaseFilter(iface), riid, ppvObject);
370 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
372 return SampleGrabber_addref(impl_from_IBaseFilter(iface));
377 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
379 return SampleGrabber_release(impl_from_IBaseFilter(iface));
383 static HRESULT WINAPI
384 SampleGrabber_IBaseFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID)
386 TRACE("(%p)\n", pClassID);
389 *pClassID = CLSID_SampleGrabber;
394 static HRESULT WINAPI
395 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
397 SG_Impl *This = impl_from_IBaseFilter(iface);
398 TRACE("(%p)\n", This);
399 This->state = State_Stopped;
404 static HRESULT WINAPI
405 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
407 SG_Impl *This = impl_from_IBaseFilter(iface);
408 TRACE("(%p)\n", This);
409 This->state = State_Paused;
414 static HRESULT WINAPI
415 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
417 SG_Impl *This = impl_from_IBaseFilter(iface);
418 TRACE("(%p)\n", This);
419 This->state = State_Running;
424 static HRESULT WINAPI
425 SampleGrabber_IBaseFilter_GetState(IBaseFilter *iface, DWORD msTout, FILTER_STATE *state)
427 SG_Impl *This = impl_from_IBaseFilter(iface);
428 TRACE("(%p)->(%u, %p)\n", This, msTout, state);
431 *state = This->state;
436 static HRESULT WINAPI
437 SampleGrabber_IBaseFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
439 SG_Impl *This = impl_from_IBaseFilter(iface);
440 TRACE("(%p)->(%p)\n", This, clock);
441 if (clock != This->refClock)
444 IReferenceClock_AddRef(clock);
446 IReferenceClock_Release(This->refClock);
447 This->refClock = clock;
453 static HRESULT WINAPI
454 SampleGrabber_IBaseFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock)
456 SG_Impl *This = impl_from_IBaseFilter(iface);
457 TRACE("(%p)->(%p)\n", This, clock);
461 IReferenceClock_AddRef(This->refClock);
462 *clock = This->refClock;
467 static HRESULT WINAPI
468 SampleGrabber_IBaseFilter_EnumPins(IBaseFilter *iface, IEnumPins **pins)
470 SG_Impl *This = impl_from_IBaseFilter(iface);
472 TRACE("(%p)->(%p)\n", This, pins);
475 pin[0] = (IPin*)&This->pin_in.lpVtbl;
476 pin[1] = (IPin*)&This->pin_out.lpVtbl;
477 *pins = pinsenum_create(iface, pin, 2);
478 return *pins ? S_OK : E_OUTOFMEMORY;
482 static HRESULT WINAPI
483 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
485 SG_Impl *This = impl_from_IBaseFilter(iface);
486 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin);
489 if (!lstrcmpiW(id,pin_in_name))
491 SampleGrabber_addref(This);
492 *pin = (IPin*)&(This->pin_in.lpVtbl);
495 else if (!lstrcmpiW(id,pin_out_name))
497 SampleGrabber_addref(This);
498 *pin = (IPin*)&(This->pin_out.lpVtbl);
502 return VFW_E_NOT_FOUND;
506 static HRESULT WINAPI
507 SampleGrabber_IBaseFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info)
509 SG_Impl *This = impl_from_IBaseFilter(iface);
510 TRACE("(%p)->(%p)\n", This, info);
513 if (This->info.pGraph)
514 IFilterGraph_AddRef(This->info.pGraph);
520 static HRESULT WINAPI
521 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
523 SG_Impl *This = impl_from_IBaseFilter(iface);
524 TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
525 This->info.pGraph = graph;
527 lstrcpynW(This->info.achName,name,MAX_FILTER_NAME);
528 This->oneShot = OneShot_None;
533 static HRESULT WINAPI
534 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
536 TRACE("(%p)\n", vendor);
539 *vendor = CoTaskMemAlloc(sizeof(vendor_name));
540 CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
545 /* SampleGrabber implementation of ISampleGrabber interface */
548 static HRESULT WINAPI
549 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppvObject)
551 return SampleGrabber_query(impl_from_ISampleGrabber(iface), riid, ppvObject);
556 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
558 return SampleGrabber_addref(impl_from_ISampleGrabber(iface));
563 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
565 return SampleGrabber_release(impl_from_ISampleGrabber(iface));
569 static HRESULT WINAPI
570 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
572 SG_Impl *This = impl_from_ISampleGrabber(iface);
573 TRACE("(%p)->(%u)\n", This, oneShot);
574 This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
579 static HRESULT WINAPI
580 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
582 SG_Impl *This = impl_from_ISampleGrabber(iface);
583 TRACE("(%p)->(%p)\n", This, type);
586 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
587 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
589 debugstr_guid(&type->formattype), type->cbFormat);
590 if (This->mtype.pbFormat)
591 CoTaskMemFree(This->mtype.pbFormat);
593 This->mtype.pUnk = NULL;
594 if (type->cbFormat) {
595 This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
596 CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat);
599 This->mtype.pbFormat = NULL;
604 static HRESULT WINAPI
605 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
607 SG_Impl *This = impl_from_ISampleGrabber(iface);
608 TRACE("(%p)->(%p)\n", This, type);
611 if (!This->pin_in.pair)
612 return VFW_E_NOT_CONNECTED;
614 if (type->cbFormat) {
615 type->pbFormat = CoTaskMemAlloc(type->cbFormat);
616 CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat);
622 static HRESULT WINAPI
623 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
625 TRACE("(%u)\n", bufferEm);
627 FIXME("buffering not implemented\n");
634 static HRESULT WINAPI
635 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
637 FIXME("(%p, %p): stub\n", bufSize, buffer);
644 static HRESULT WINAPI
645 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
647 /* MS doesn't implement it either, noone should call it */
648 WARN("(%p): not implemented\n", sample);
653 static HRESULT WINAPI
654 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
656 SG_Impl *This = impl_from_ISampleGrabber(iface);
657 TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
658 if (This->grabberIface)
659 ISampleGrabberCB_Release(This->grabberIface);
660 This->grabberIface = cb;
661 This->grabberMethod = whichMethod;
663 ISampleGrabberCB_AddRef(cb);
668 /* SampleGrabber implementation of IMemInputPin interface */
671 static HRESULT WINAPI
672 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppvObject)
674 return SampleGrabber_query(impl_from_IMemInputPin(iface), riid, ppvObject);
679 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
681 return SampleGrabber_addref(impl_from_IMemInputPin(iface));
686 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
688 return SampleGrabber_release(impl_from_IMemInputPin(iface));
692 static HRESULT WINAPI
693 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
695 SG_Impl *This = impl_from_IMemInputPin(iface);
696 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
699 *allocator = This->allocator;
701 return VFW_E_NO_ALLOCATOR;
702 IMemAllocator_AddRef(*allocator);
707 static HRESULT WINAPI
708 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
710 SG_Impl *This = impl_from_IMemInputPin(iface);
711 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
712 if (This->allocator == allocator)
715 IMemAllocator_Release(This->allocator);
716 This->allocator = allocator;
718 IMemAllocator_AddRef(allocator);
723 static HRESULT WINAPI
724 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
726 SG_Impl *This = impl_from_IMemInputPin(iface);
727 FIXME("(%p)->(%p): semi-stub\n", This, props);
730 return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL;
734 static HRESULT WINAPI
735 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
737 SG_Impl *This = impl_from_IMemInputPin(iface);
739 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface);
742 if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
744 if (This->grabberIface)
745 SampleGrabber_callback(This, sample);
746 hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK;
747 if (This->oneShot == OneShot_Wait) {
748 This->oneShot = OneShot_Past;
750 if (This->pin_out.pair)
751 IPin_EndOfStream(This->pin_out.pair);
757 static HRESULT WINAPI
758 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
760 SG_Impl *This = impl_from_IMemInputPin(iface);
761 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface);
762 if (!samples || !nProcessed)
764 if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
766 if (This->grabberIface) {
768 for (idx = 0; idx < nSamples; idx++)
769 SampleGrabber_callback(This, samples[idx]);
771 return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK;
775 static HRESULT WINAPI
776 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
778 SG_Impl *This = impl_from_IMemInputPin(iface);
779 TRACE("(%p)\n", This);
780 return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK;
784 /* SampleGrabber member pin implementation */
788 SampleGrabber_IPin_AddRef(IPin *iface)
790 return SampleGrabber_addref(((SG_Pin *)iface)->sg);
795 SampleGrabber_IPin_Release(IPin *iface)
797 return SampleGrabber_release(((SG_Pin *)iface)->sg);
801 static HRESULT WINAPI
802 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppvObject)
804 SG_Pin *This = (SG_Pin *)iface;
805 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
807 if (IsEqualIID(riid, &IID_IUnknown) ||
808 IsEqualIID(riid, &IID_IPin)) {
809 SampleGrabber_addref(This->sg);
813 else if (IsEqualIID(riid, &IID_IMemInputPin)) {
814 SampleGrabber_addref(This->sg);
815 *ppvObject = &(This->sg->IMemInputPin_Vtbl);
819 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppvObject);
820 return E_NOINTERFACE;
823 /* IPin - input pin */
824 static HRESULT WINAPI
825 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype)
827 WARN("(%p, %p): unexpected\n", receiver, mtype);
831 /* IPin - output pin */
832 static HRESULT WINAPI
833 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type)
835 SG_Pin *This = (SG_Pin *)iface;
836 TRACE("(%p)->(%p, %p)\n", This, receiver, type);
840 return VFW_E_ALREADY_CONNECTED;
841 if (This->sg->state != State_Stopped)
842 return VFW_E_NOT_STOPPED;
844 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
845 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
847 debugstr_guid(&type->formattype), type->cbFormat);
848 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
849 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
850 return VFW_E_TYPE_NOT_ACCEPTED;
851 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
852 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
853 return VFW_E_TYPE_NOT_ACCEPTED;
854 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
855 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
856 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
857 return VFW_E_TYPE_NOT_ACCEPTED;
859 This->pair = receiver;
860 if (This->sg->memOutput) {
861 IMemInputPin_Release(This->sg->memOutput);
862 This->sg->memOutput = NULL;
864 if (SUCCEEDED(IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput))))
865 TRACE("pair IMemInputPin %p\n", This->sg->memOutput);
869 /* IPin - input pin */
870 static HRESULT WINAPI
871 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type)
873 SG_Pin *This = (SG_Pin *)iface;
874 TRACE("(%p)->(%p, %p)\n", This, connector, type);
878 return VFW_E_ALREADY_CONNECTED;
879 if (This->sg->state != State_Stopped)
880 return VFW_E_NOT_STOPPED;
882 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
883 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
885 debugstr_guid(&type->formattype), type->cbFormat);
886 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
887 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
888 return VFW_E_TYPE_NOT_ACCEPTED;
889 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
890 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
891 return VFW_E_TYPE_NOT_ACCEPTED;
892 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
893 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
894 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
895 return VFW_E_TYPE_NOT_ACCEPTED;
896 if (This->sg->mtype.pbFormat)
897 CoTaskMemFree(This->sg->mtype.pbFormat);
898 This->sg->mtype = *type;
899 This->sg->mtype.pUnk = NULL;
900 if (type->cbFormat) {
901 This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
902 CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat);
905 This->sg->mtype.pbFormat = NULL;
907 This->pair = connector;
911 /* IPin - output pin */
912 static HRESULT WINAPI
913 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype)
915 WARN("(%p, %p): unexpected\n", connector, mtype);
919 /* IPin - input pin */
920 static HRESULT WINAPI
921 SampleGrabber_In_IPin_Disconnect(IPin *iface)
923 SG_Pin *This = (SG_Pin *)iface;
924 TRACE("(%p)->() pair = %p\n", This, This->pair);
925 if (This->sg->state != State_Stopped)
926 return VFW_E_NOT_STOPPED;
934 /* IPin - output pin */
935 static HRESULT WINAPI
936 SampleGrabber_Out_IPin_Disconnect(IPin *iface)
938 SG_Pin *This = (SG_Pin *)iface;
939 TRACE("(%p)->() pair = %p\n", This, This->pair);
940 if (This->sg->state != State_Stopped)
941 return VFW_E_NOT_STOPPED;
944 if (This->sg->memOutput) {
945 IMemInputPin_Release(This->sg->memOutput);
946 This->sg->memOutput = NULL;
954 static HRESULT WINAPI
955 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin)
957 SG_Pin *This = (SG_Pin *)iface;
958 TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair);
966 return VFW_E_NOT_CONNECTED;
970 static HRESULT WINAPI
971 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype)
973 SG_Pin *This = (SG_Pin *)iface;
974 TRACE("(%p)->(%p)\n", This, mtype);
978 return VFW_E_NOT_CONNECTED;
979 *mtype = This->sg->mtype;
980 if (mtype->cbFormat) {
981 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
982 CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat);
988 static HRESULT WINAPI
989 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info)
991 SG_Pin *This = (SG_Pin *)iface;
992 TRACE("(%p)->(%p)\n", This, info);
995 SampleGrabber_addref(This->sg);
996 info->pFilter = (IBaseFilter *)This->sg;
997 info->dir = This->dir;
998 lstrcpynW(info->achName,This->name,MAX_PIN_NAME);
1003 static HRESULT WINAPI
1004 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1006 SG_Pin *This = (SG_Pin *)iface;
1007 TRACE("(%p)->(%p)\n", This, dir);
1015 static HRESULT WINAPI
1016 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id)
1018 SG_Pin *This = (SG_Pin *)iface;
1020 TRACE("(%p)->(%p)\n", This, id);
1023 len = sizeof(WCHAR)*(1+lstrlenW(This->name));
1024 *id = CoTaskMemAlloc(len);
1025 CopyMemory(*id, This->name, len);
1030 static HRESULT WINAPI
1031 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype)
1033 TRACE("(%p)\n", mtype);
1038 static HRESULT WINAPI
1039 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes)
1041 SG_Pin *This = (SG_Pin *)iface;
1042 FIXME("(%p)->(%p): stub\n", This, mtypes);
1045 return E_OUTOFMEMORY;
1048 /* IPin - input pin */
1049 static HRESULT WINAPI
1050 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1052 SG_Pin *This = (SG_Pin *)iface;
1053 TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0));
1059 IPin_AddRef((IPin*)&This->sg->pin_out.lpVtbl);
1060 *pins = (IPin*)&This->sg->pin_out.lpVtbl;
1068 /* IPin - output pin */
1069 static HRESULT WINAPI
1070 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1072 WARN("(%p, %p): unexpected\n", pins, nPins);
1079 static HRESULT WINAPI
1080 SampleGrabber_IPin_EndOfStream(IPin *iface)
1087 static HRESULT WINAPI
1088 SampleGrabber_IPin_BeginFlush(IPin *iface)
1095 static HRESULT WINAPI
1096 SampleGrabber_IPin_EndFlush(IPin *iface)
1103 static HRESULT WINAPI
1104 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate)
1111 /* SampleGrabber vtables and constructor */
1113 static const IBaseFilterVtbl IBaseFilter_VTable =
1115 SampleGrabber_IBaseFilter_QueryInterface,
1116 SampleGrabber_IBaseFilter_AddRef,
1117 SampleGrabber_IBaseFilter_Release,
1118 SampleGrabber_IBaseFilter_GetClassID,
1119 SampleGrabber_IBaseFilter_Stop,
1120 SampleGrabber_IBaseFilter_Pause,
1121 SampleGrabber_IBaseFilter_Run,
1122 SampleGrabber_IBaseFilter_GetState,
1123 SampleGrabber_IBaseFilter_SetSyncSource,
1124 SampleGrabber_IBaseFilter_GetSyncSource,
1125 SampleGrabber_IBaseFilter_EnumPins,
1126 SampleGrabber_IBaseFilter_FindPin,
1127 SampleGrabber_IBaseFilter_QueryFilterInfo,
1128 SampleGrabber_IBaseFilter_JoinFilterGraph,
1129 SampleGrabber_IBaseFilter_QueryVendorInfo,
1132 static const ISampleGrabberVtbl ISampleGrabber_VTable =
1134 SampleGrabber_ISampleGrabber_QueryInterface,
1135 SampleGrabber_ISampleGrabber_AddRef,
1136 SampleGrabber_ISampleGrabber_Release,
1137 SampleGrabber_ISampleGrabber_SetOneShot,
1138 SampleGrabber_ISampleGrabber_SetMediaType,
1139 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
1140 SampleGrabber_ISampleGrabber_SetBufferSamples,
1141 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
1142 SampleGrabber_ISampleGrabber_GetCurrentSample,
1143 SampleGrabber_ISampleGrabber_SetCallback,
1146 static const IMemInputPinVtbl IMemInputPin_VTable =
1148 SampleGrabber_IMemInputPin_QueryInterface,
1149 SampleGrabber_IMemInputPin_AddRef,
1150 SampleGrabber_IMemInputPin_Release,
1151 SampleGrabber_IMemInputPin_GetAllocator,
1152 SampleGrabber_IMemInputPin_NotifyAllocator,
1153 SampleGrabber_IMemInputPin_GetAllocatorRequirements,
1154 SampleGrabber_IMemInputPin_Receive,
1155 SampleGrabber_IMemInputPin_ReceiveMultiple,
1156 SampleGrabber_IMemInputPin_ReceiveCanBlock,
1159 static const IPinVtbl IPin_In_VTable =
1161 SampleGrabber_IPin_QueryInterface,
1162 SampleGrabber_IPin_AddRef,
1163 SampleGrabber_IPin_Release,
1164 SampleGrabber_In_IPin_Connect,
1165 SampleGrabber_In_IPin_ReceiveConnection,
1166 SampleGrabber_In_IPin_Disconnect,
1167 SampleGrabber_IPin_ConnectedTo,
1168 SampleGrabber_IPin_ConnectionMediaType,
1169 SampleGrabber_IPin_QueryPinInfo,
1170 SampleGrabber_IPin_QueryDirection,
1171 SampleGrabber_IPin_QueryId,
1172 SampleGrabber_IPin_QueryAccept,
1173 SampleGrabber_IPin_EnumMediaTypes,
1174 SampleGrabber_In_IPin_QueryInternalConnections,
1175 SampleGrabber_IPin_EndOfStream,
1176 SampleGrabber_IPin_BeginFlush,
1177 SampleGrabber_IPin_EndFlush,
1178 SampleGrabber_IPin_NewSegment,
1181 static const IPinVtbl IPin_Out_VTable =
1183 SampleGrabber_IPin_QueryInterface,
1184 SampleGrabber_IPin_AddRef,
1185 SampleGrabber_IPin_Release,
1186 SampleGrabber_Out_IPin_Connect,
1187 SampleGrabber_Out_IPin_ReceiveConnection,
1188 SampleGrabber_Out_IPin_Disconnect,
1189 SampleGrabber_IPin_ConnectedTo,
1190 SampleGrabber_IPin_ConnectionMediaType,
1191 SampleGrabber_IPin_QueryPinInfo,
1192 SampleGrabber_IPin_QueryDirection,
1193 SampleGrabber_IPin_QueryId,
1194 SampleGrabber_IPin_QueryAccept,
1195 SampleGrabber_IPin_EnumMediaTypes,
1196 SampleGrabber_Out_IPin_QueryInternalConnections,
1197 SampleGrabber_IPin_EndOfStream,
1198 SampleGrabber_IPin_BeginFlush,
1199 SampleGrabber_IPin_EndFlush,
1200 SampleGrabber_IPin_NewSegment,
1203 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
1205 SG_Impl* obj = NULL;
1207 TRACE("(%p,%p)\n", ppv, pUnkOuter);
1210 return CLASS_E_NOAGGREGATION;
1212 obj = CoTaskMemAlloc(sizeof(SG_Impl));
1215 return E_OUTOFMEMORY;
1217 ZeroMemory(obj, sizeof(SG_Impl));
1220 obj->IBaseFilter_Vtbl = &IBaseFilter_VTable;
1221 obj->ISampleGrabber_Vtbl = &ISampleGrabber_VTable;
1222 obj->IMemInputPin_Vtbl = &IMemInputPin_VTable;
1223 obj->pin_in.lpVtbl = &IPin_In_VTable;
1224 obj->pin_in.dir = PINDIR_INPUT;
1225 obj->pin_in.name = pin_in_name;
1226 obj->pin_in.sg = obj;
1227 obj->pin_in.pair = NULL;
1228 obj->pin_out.lpVtbl = &IPin_Out_VTable;
1229 obj->pin_out.dir = PINDIR_OUTPUT;
1230 obj->pin_out.name = pin_out_name;
1231 obj->pin_out.sg = obj;
1232 obj->pin_out.pair = NULL;
1233 obj->info.achName[0] = 0;
1234 obj->info.pGraph = NULL;
1235 obj->state = State_Stopped;
1236 obj->mtype.majortype = GUID_NULL;
1237 obj->mtype.subtype = MEDIASUBTYPE_None;
1238 obj->mtype.formattype = FORMAT_None;
1239 obj->allocator = NULL;
1240 obj->refClock = NULL;
1241 obj->memOutput = NULL;
1242 obj->grabberIface = NULL;
1243 obj->grabberMethod = -1;
1244 obj->oneShot = OneShot_None;