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 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 {
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 static IEnumPins *pinsenum_create(IBaseFilter *filter, IPin **pins, ULONG pinCount)
176 ULONG len = sizeof(PE_Impl) + (pinCount * sizeof(IPin *));
177 PE_Impl *obj = CoTaskMemAlloc(len);
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))
261 if (!This->past && !IsEqualGUID(&This->mtype.majortype,&GUID_NULL)) {
262 AM_MEDIA_TYPE *mtype = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
263 *mtype = This->mtype;
264 if (mtype->cbFormat) {
265 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
266 CopyMemory(mtype->pbFormat, This->mtype.pbFormat, mtype->cbFormat);
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 static IEnumMediaTypes *mediaenum_create(const AM_MEDIA_TYPE *mtype)
329 ME_Impl *obj = CoTaskMemAlloc(sizeof(ME_Impl));
331 ZeroMemory(obj, sizeof(ME_Impl));
332 obj->me.lpVtbl = &IEnumMediaTypes_VTable;
337 obj->mtype.pUnk = NULL;
338 if (mtype->cbFormat) {
339 obj->mtype.pbFormat = CoTaskMemAlloc(mtype->cbFormat);
340 CopyMemory(obj->mtype.pbFormat, mtype->pbFormat, mtype->cbFormat);
343 obj->mtype.pbFormat = NULL;
346 obj->mtype.majortype = GUID_NULL;
352 /* Sample Grabber pin implementation */
353 typedef struct _SG_Pin {
361 static inline SG_Pin *impl_from_IPin(IPin *iface)
363 return CONTAINING_RECORD(iface, SG_Pin, IPin_iface);
366 /* Sample Grabber filter implementation */
367 typedef struct _SG_Impl {
368 IUnknown IUnknown_inner;
369 IBaseFilter IBaseFilter_iface;
370 ISampleGrabber ISampleGrabber_iface;
371 IMemInputPin IMemInputPin_iface;
372 /* TODO: IMediaPosition, IMediaSeeking, IQualityControl */
375 CRITICAL_SECTION critSect;
381 IMemAllocator *allocator;
382 IReferenceClock *refClock;
383 IMemInputPin *memOutput;
384 ISampleGrabberCB *grabberIface;
397 static inline SG_Impl *impl_from_IUnknown(IUnknown *iface)
399 return CONTAINING_RECORD(iface, SG_Impl, IUnknown_inner);
402 static inline SG_Impl *impl_from_IBaseFilter(IBaseFilter *iface)
404 return CONTAINING_RECORD(iface, SG_Impl, IBaseFilter_iface);
407 static inline SG_Impl *impl_from_ISampleGrabber(ISampleGrabber *iface)
409 return CONTAINING_RECORD(iface, SG_Impl, ISampleGrabber_iface);
412 static inline SG_Impl *impl_from_IMemInputPin(IMemInputPin *iface)
414 return CONTAINING_RECORD(iface, SG_Impl, IMemInputPin_iface);
418 /* Cleanup at end of life */
419 static void SampleGrabber_cleanup(SG_Impl *This)
421 TRACE("(%p)\n", This);
422 if (This->info.pGraph)
423 WARN("(%p) still joined to filter graph %p\n", This, This->info.pGraph);
425 IMemAllocator_Release(This->allocator);
427 IReferenceClock_Release(This->refClock);
429 IMemInputPin_Release(This->memOutput);
430 if (This->grabberIface)
431 ISampleGrabberCB_Release(This->grabberIface);
432 if (This->mtype.pbFormat)
433 CoTaskMemFree(This->mtype.pbFormat);
434 if (This->bufferData)
435 CoTaskMemFree(This->bufferData);
436 This->critSect.DebugInfo->Spare[0] = 0;
437 DeleteCriticalSection(&This->critSect);
440 /* SampleGrabber inner IUnknown */
441 static HRESULT WINAPI SampleGrabber_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
443 SG_Impl *This = impl_from_IUnknown(iface);
445 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
448 if (IsEqualIID(riid, &IID_IUnknown))
449 *ppv = &This->IUnknown_inner;
450 else if (IsEqualIID(riid, &IID_IPersist) || IsEqualIID(riid, &IID_IMediaFilter) ||
451 IsEqualIID(riid, &IID_IBaseFilter))
452 *ppv = &This->IBaseFilter_iface;
453 else if (IsEqualIID(riid, &IID_ISampleGrabber))
454 *ppv = &This->ISampleGrabber_iface;
455 else if (IsEqualIID(riid, &IID_IMemInputPin))
456 *ppv = &This->IMemInputPin_iface;
457 else if (IsEqualIID(riid, &IID_IMediaPosition))
458 FIXME("IMediaPosition not implemented\n");
459 else if (IsEqualIID(riid, &IID_IMediaSeeking))
460 FIXME("IMediaSeeking not implemented\n");
461 else if (IsEqualIID(riid, &IID_IQualityControl))
462 FIXME("IQualityControl not implemented\n");
464 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
467 return E_NOINTERFACE;
469 IUnknown_AddRef((IUnknown*)*ppv);
473 static ULONG WINAPI SampleGrabber_AddRef(IUnknown *iface)
475 SG_Impl *This = impl_from_IUnknown(iface);
476 ULONG ref = InterlockedIncrement(&This->ref);
478 TRACE("(%p) new ref = %u\n", This, ref);
483 static ULONG WINAPI SampleGrabber_Release(IUnknown *iface)
485 SG_Impl *This = impl_from_IUnknown(iface);
486 ULONG ref = InterlockedDecrement(&This->ref);
488 TRACE("(%p) new ref = %u\n", This, ref);
492 SampleGrabber_cleanup(This);
499 static const IUnknownVtbl samplegrabber_vtbl =
501 SampleGrabber_QueryInterface,
502 SampleGrabber_AddRef,
503 SampleGrabber_Release,
506 /* Helper that buffers data and/or calls installed sample callbacks */
507 static void SampleGrabber_callback(SG_Impl *This, IMediaSample *sample)
510 REFERENCE_TIME tStart, tEnd;
511 if (This->bufferLen >= 0) {
513 LONG size = IMediaSample_GetActualDataLength(sample);
514 if (size >= 0 && SUCCEEDED(IMediaSample_GetPointer(sample, &data))) {
517 EnterCriticalSection(&This->critSect);
518 if (This->bufferLen != size) {
519 if (This->bufferData)
520 CoTaskMemFree(This->bufferData);
521 This->bufferData = size ? CoTaskMemAlloc(size) : NULL;
522 This->bufferLen = size;
525 CopyMemory(This->bufferData, data, size);
526 LeaveCriticalSection(&This->critSect);
529 if (!This->grabberIface)
531 if (SUCCEEDED(IMediaSample_GetTime(sample, &tStart, &tEnd)))
532 time = 1e-7 * tStart;
533 switch (This->grabberMethod) {
536 ULONG ref = IMediaSample_AddRef(sample);
537 ISampleGrabberCB_SampleCB(This->grabberIface, time, sample);
538 ref = IMediaSample_Release(sample) + 1 - ref;
541 ERR("(%p) Callback referenced sample %p by %u\n", This, sample, ref);
542 /* ugly as hell but some apps are sooo buggy */
544 IMediaSample_Release(sample);
551 LONG size = IMediaSample_GetActualDataLength(sample);
552 if (size && SUCCEEDED(IMediaSample_GetPointer(sample, &data)) && data)
553 ISampleGrabberCB_BufferCB(This->grabberIface, time, data, size);
559 FIXME("unsupported method %d\n", This->grabberMethod);
560 /* do not bother us again */
561 This->grabberMethod = -1;
566 /* SampleGrabber implementation of IBaseFilter interface */
569 static HRESULT WINAPI
570 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter *iface, REFIID riid, void **ppv)
572 SG_Impl *This = impl_from_IBaseFilter(iface);
573 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
578 SampleGrabber_IBaseFilter_AddRef(IBaseFilter *iface)
580 SG_Impl *This = impl_from_IBaseFilter(iface);
581 return IUnknown_AddRef(This->outer_unk);
586 SampleGrabber_IBaseFilter_Release(IBaseFilter *iface)
588 SG_Impl *This = impl_from_IBaseFilter(iface);
589 return IUnknown_Release(This->outer_unk);
593 static HRESULT WINAPI
594 SampleGrabber_IBaseFilter_GetClassID(IBaseFilter *iface, CLSID *pClassID)
596 TRACE("(%p)\n", pClassID);
599 *pClassID = CLSID_SampleGrabber;
604 static HRESULT WINAPI
605 SampleGrabber_IBaseFilter_Stop(IBaseFilter *iface)
607 SG_Impl *This = impl_from_IBaseFilter(iface);
608 TRACE("(%p)\n", This);
609 This->state = State_Stopped;
614 static HRESULT WINAPI
615 SampleGrabber_IBaseFilter_Pause(IBaseFilter *iface)
617 SG_Impl *This = impl_from_IBaseFilter(iface);
618 TRACE("(%p)\n", This);
619 This->state = State_Paused;
624 static HRESULT WINAPI
625 SampleGrabber_IBaseFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
627 SG_Impl *This = impl_from_IBaseFilter(iface);
628 TRACE("(%p)\n", This);
629 This->state = State_Running;
634 static HRESULT WINAPI
635 SampleGrabber_IBaseFilter_GetState(IBaseFilter *iface, DWORD msTout, FILTER_STATE *state)
637 SG_Impl *This = impl_from_IBaseFilter(iface);
638 TRACE("(%p)->(%u, %p)\n", This, msTout, state);
641 *state = This->state;
646 static HRESULT WINAPI
647 SampleGrabber_IBaseFilter_SetSyncSource(IBaseFilter *iface, IReferenceClock *clock)
649 SG_Impl *This = impl_from_IBaseFilter(iface);
650 TRACE("(%p)->(%p)\n", This, clock);
651 if (clock != This->refClock)
654 IReferenceClock_AddRef(clock);
656 IReferenceClock_Release(This->refClock);
657 This->refClock = clock;
663 static HRESULT WINAPI
664 SampleGrabber_IBaseFilter_GetSyncSource(IBaseFilter *iface, IReferenceClock **clock)
666 SG_Impl *This = impl_from_IBaseFilter(iface);
667 TRACE("(%p)->(%p)\n", This, clock);
671 IReferenceClock_AddRef(This->refClock);
672 *clock = This->refClock;
677 static HRESULT WINAPI
678 SampleGrabber_IBaseFilter_EnumPins(IBaseFilter *iface, IEnumPins **pins)
680 SG_Impl *This = impl_from_IBaseFilter(iface);
682 TRACE("(%p)->(%p)\n", This, pins);
685 pin[0] = &This->pin_in.IPin_iface;
686 pin[1] = &This->pin_out.IPin_iface;
687 *pins = pinsenum_create(iface, pin, 2);
688 return *pins ? S_OK : E_OUTOFMEMORY;
692 static HRESULT WINAPI
693 SampleGrabber_IBaseFilter_FindPin(IBaseFilter *iface, LPCWSTR id, IPin **pin)
695 SG_Impl *This = impl_from_IBaseFilter(iface);
696 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(id), pin);
699 if (!lstrcmpiW(id,pin_in_name))
701 *pin = &This->pin_in.IPin_iface;
705 else if (!lstrcmpiW(id,pin_out_name))
707 *pin = &This->pin_out.IPin_iface;
712 return VFW_E_NOT_FOUND;
716 static HRESULT WINAPI
717 SampleGrabber_IBaseFilter_QueryFilterInfo(IBaseFilter *iface, FILTER_INFO *info)
719 SG_Impl *This = impl_from_IBaseFilter(iface);
720 TRACE("(%p)->(%p)\n", This, info);
723 if (This->info.pGraph)
724 IFilterGraph_AddRef(This->info.pGraph);
730 static HRESULT WINAPI
731 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter *iface, IFilterGraph *graph, LPCWSTR name)
733 SG_Impl *This = impl_from_IBaseFilter(iface);
734 TRACE("(%p)->(%p, %s)\n", This, graph, debugstr_w(name));
735 This->info.pGraph = graph;
737 lstrcpynW(This->info.achName,name,MAX_FILTER_NAME);
738 This->oneShot = OneShot_None;
743 static HRESULT WINAPI
744 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter *iface, LPWSTR *vendor)
746 TRACE("(%p)\n", vendor);
749 *vendor = CoTaskMemAlloc(sizeof(vendor_name));
750 CopyMemory(*vendor, vendor_name, sizeof(vendor_name));
755 /* SampleGrabber implementation of ISampleGrabber interface */
758 static HRESULT WINAPI
759 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber *iface, REFIID riid, void **ppv)
761 SG_Impl *This = impl_from_ISampleGrabber(iface);
762 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
767 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber *iface)
769 SG_Impl *This = impl_from_ISampleGrabber(iface);
770 return IUnknown_AddRef(This->outer_unk);
775 SampleGrabber_ISampleGrabber_Release(ISampleGrabber *iface)
777 SG_Impl *This = impl_from_ISampleGrabber(iface);
778 return IUnknown_Release(This->outer_unk);
782 static HRESULT WINAPI
783 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber *iface, BOOL oneShot)
785 SG_Impl *This = impl_from_ISampleGrabber(iface);
786 TRACE("(%p)->(%u)\n", This, oneShot);
787 This->oneShot = oneShot ? OneShot_Wait : OneShot_None;
792 static HRESULT WINAPI
793 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber *iface, const AM_MEDIA_TYPE *type)
795 SG_Impl *This = impl_from_ISampleGrabber(iface);
796 TRACE("(%p)->(%p)\n", This, type);
799 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
800 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
802 debugstr_guid(&type->formattype), type->cbFormat);
803 if (This->mtype.pbFormat)
804 CoTaskMemFree(This->mtype.pbFormat);
806 This->mtype.pUnk = NULL;
807 if (type->cbFormat) {
808 This->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
809 CopyMemory(This->mtype.pbFormat, type->pbFormat, type->cbFormat);
812 This->mtype.pbFormat = NULL;
817 static HRESULT WINAPI
818 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber *iface, AM_MEDIA_TYPE *type)
820 SG_Impl *This = impl_from_ISampleGrabber(iface);
821 TRACE("(%p)->(%p)\n", This, type);
824 if (!This->pin_in.pair)
825 return VFW_E_NOT_CONNECTED;
827 if (type->cbFormat) {
828 type->pbFormat = CoTaskMemAlloc(type->cbFormat);
829 CopyMemory(type->pbFormat, This->mtype.pbFormat, type->cbFormat);
835 static HRESULT WINAPI
836 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber *iface, BOOL bufferEm)
838 SG_Impl *This = impl_from_ISampleGrabber(iface);
839 TRACE("(%p)->(%u)\n", This, bufferEm);
840 EnterCriticalSection(&This->critSect);
842 if (This->bufferLen < 0)
846 This->bufferLen = -1;
847 LeaveCriticalSection(&This->critSect);
852 static HRESULT WINAPI
853 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber *iface, LONG *bufSize, LONG *buffer)
855 SG_Impl *This = impl_from_ISampleGrabber(iface);
857 TRACE("(%p)->(%p, %p)\n", This, bufSize, buffer);
860 EnterCriticalSection(&This->critSect);
861 if (!This->pin_in.pair)
862 ret = VFW_E_NOT_CONNECTED;
863 else if (This->bufferLen < 0)
865 else if (This->bufferLen == 0)
866 ret = VFW_E_WRONG_STATE;
869 if (*bufSize >= This->bufferLen)
870 CopyMemory(buffer, This->bufferData, This->bufferLen);
874 *bufSize = This->bufferLen;
876 LeaveCriticalSection(&This->critSect);
881 static HRESULT WINAPI
882 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber *iface, IMediaSample **sample)
884 /* MS doesn't implement it either, no one should call it */
885 WARN("(%p): not implemented\n", sample);
890 static HRESULT WINAPI
891 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber *iface, ISampleGrabberCB *cb, LONG whichMethod)
893 SG_Impl *This = impl_from_ISampleGrabber(iface);
894 TRACE("(%p)->(%p, %u)\n", This, cb, whichMethod);
895 if (This->grabberIface)
896 ISampleGrabberCB_Release(This->grabberIface);
897 This->grabberIface = cb;
898 This->grabberMethod = whichMethod;
900 ISampleGrabberCB_AddRef(cb);
905 /* SampleGrabber implementation of IMemInputPin interface */
908 static HRESULT WINAPI
909 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin *iface, REFIID riid, void **ppv)
911 SG_Impl *This = impl_from_IMemInputPin(iface);
912 return IUnknown_QueryInterface(This->outer_unk, riid, ppv);
917 SampleGrabber_IMemInputPin_AddRef(IMemInputPin *iface)
919 SG_Impl *This = impl_from_IMemInputPin(iface);
920 return IUnknown_AddRef(This->outer_unk);
925 SampleGrabber_IMemInputPin_Release(IMemInputPin *iface)
927 SG_Impl *This = impl_from_IMemInputPin(iface);
928 return IUnknown_Release(This->outer_unk);
932 static HRESULT WINAPI
933 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin *iface, IMemAllocator **allocator)
935 SG_Impl *This = impl_from_IMemInputPin(iface);
936 TRACE("(%p)->(%p) allocator = %p\n", This, allocator, This->allocator);
939 *allocator = This->allocator;
941 return VFW_E_NO_ALLOCATOR;
942 IMemAllocator_AddRef(*allocator);
947 static HRESULT WINAPI
948 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin *iface, IMemAllocator *allocator, BOOL readOnly)
950 SG_Impl *This = impl_from_IMemInputPin(iface);
951 TRACE("(%p)->(%p, %u) allocator = %p\n", This, allocator, readOnly, This->allocator);
952 if (This->allocator == allocator)
955 IMemAllocator_Release(This->allocator);
956 This->allocator = allocator;
958 IMemAllocator_AddRef(allocator);
963 static HRESULT WINAPI
964 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin *iface, ALLOCATOR_PROPERTIES *props)
966 SG_Impl *This = impl_from_IMemInputPin(iface);
967 FIXME("(%p)->(%p): semi-stub\n", This, props);
970 return This->memOutput ? IMemInputPin_GetAllocatorRequirements(This->memOutput, props) : E_NOTIMPL;
974 static HRESULT WINAPI
975 SampleGrabber_IMemInputPin_Receive(IMemInputPin *iface, IMediaSample *sample)
977 SG_Impl *This = impl_from_IMemInputPin(iface);
979 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This, sample, This->memOutput, This->grabberIface);
982 if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
984 SampleGrabber_callback(This, sample);
985 hr = This->memOutput ? IMemInputPin_Receive(This->memOutput, sample) : S_OK;
986 if (This->oneShot == OneShot_Wait) {
987 This->oneShot = OneShot_Past;
989 if (This->pin_out.pair)
990 IPin_EndOfStream(This->pin_out.pair);
996 static HRESULT WINAPI
997 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin *iface, IMediaSample **samples, LONG nSamples, LONG *nProcessed)
999 SG_Impl *This = impl_from_IMemInputPin(iface);
1001 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This, samples, nSamples, nProcessed, This->memOutput, This->grabberIface);
1002 if (!samples || !nProcessed)
1004 if ((This->state != State_Running) || (This->oneShot == OneShot_Past))
1006 for (idx = 0; idx < nSamples; idx++)
1007 SampleGrabber_callback(This, samples[idx]);
1008 return This->memOutput ? IMemInputPin_ReceiveMultiple(This->memOutput, samples, nSamples, nProcessed) : S_OK;
1012 static HRESULT WINAPI
1013 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
1015 SG_Impl *This = impl_from_IMemInputPin(iface);
1016 TRACE("(%p)\n", This);
1017 return This->memOutput ? IMemInputPin_ReceiveCanBlock(This->memOutput) : S_OK;
1021 /* SampleGrabber member pin implementation */
1025 SampleGrabber_IPin_AddRef(IPin *iface)
1027 SG_Pin *This = impl_from_IPin(iface);
1028 return ISampleGrabber_AddRef(&This->sg->ISampleGrabber_iface);
1033 SampleGrabber_IPin_Release(IPin *iface)
1035 SG_Pin *This = impl_from_IPin(iface);
1036 return ISampleGrabber_Release(&This->sg->ISampleGrabber_iface);
1040 static HRESULT WINAPI
1041 SampleGrabber_IPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
1043 SG_Pin *This = impl_from_IPin(iface);
1044 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1047 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IPin))
1049 else if (IsEqualIID(riid, &IID_IMemInputPin))
1050 *ppv = &This->sg->IMemInputPin_iface;
1052 WARN("(%p, %s,%p): not found\n", This, debugstr_guid(riid), ppv);
1053 return E_NOINTERFACE;
1056 IUnknown_AddRef((IUnknown*)*ppv);
1060 /* IPin - input pin */
1061 static HRESULT WINAPI
1062 SampleGrabber_In_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *mtype)
1064 WARN("(%p, %p): unexpected\n", receiver, mtype);
1065 return E_UNEXPECTED;
1068 /* IPin - output pin */
1069 static HRESULT WINAPI
1070 SampleGrabber_Out_IPin_Connect(IPin *iface, IPin *receiver, const AM_MEDIA_TYPE *type)
1072 SG_Pin *This = impl_from_IPin(iface);
1075 TRACE("(%p)->(%p, %p)\n", This, receiver, type);
1079 return VFW_E_ALREADY_CONNECTED;
1080 if (This->sg->state != State_Stopped)
1081 return VFW_E_NOT_STOPPED;
1083 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1084 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1086 debugstr_guid(&type->formattype), type->cbFormat);
1087 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1088 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1089 return VFW_E_TYPE_NOT_ACCEPTED;
1090 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1091 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1092 return VFW_E_TYPE_NOT_ACCEPTED;
1093 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1094 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1095 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1096 return VFW_E_TYPE_NOT_ACCEPTED;
1099 type = &This->sg->mtype;
1100 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
1101 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
1103 return VFW_E_TYPE_NOT_ACCEPTED;
1104 hr = IPin_ReceiveConnection(receiver, &This->IPin_iface, type);
1107 This->pair = receiver;
1108 if (This->sg->memOutput) {
1109 IMemInputPin_Release(This->sg->memOutput);
1110 This->sg->memOutput = NULL;
1112 IPin_QueryInterface(receiver,&IID_IMemInputPin,(void **)&(This->sg->memOutput));
1113 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This, receiver, This->sg->memOutput);
1117 /* IPin - input pin */
1118 static HRESULT WINAPI
1119 SampleGrabber_In_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *type)
1121 SG_Pin *This = impl_from_IPin(iface);
1123 TRACE("(%p)->(%p, %p)\n", This, connector, type);
1127 return VFW_E_ALREADY_CONNECTED;
1128 if (This->sg->state != State_Stopped)
1129 return VFW_E_NOT_STOPPED;
1131 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
1132 debugstr_guid(&type->majortype), debugstr_guid(&type->subtype),
1134 debugstr_guid(&type->formattype), type->cbFormat);
1135 if (!IsEqualGUID(&type->formattype, &FORMAT_None) &&
1136 !IsEqualGUID(&type->formattype, &GUID_NULL) &&
1138 return VFW_E_INVALIDMEDIATYPE;
1139 if (!IsEqualGUID(&This->sg->mtype.majortype,&GUID_NULL) &&
1140 !IsEqualGUID(&This->sg->mtype.majortype,&type->majortype))
1141 return VFW_E_TYPE_NOT_ACCEPTED;
1142 if (!IsEqualGUID(&This->sg->mtype.subtype,&MEDIASUBTYPE_None) &&
1143 !IsEqualGUID(&This->sg->mtype.subtype,&type->subtype))
1144 return VFW_E_TYPE_NOT_ACCEPTED;
1145 if (!IsEqualGUID(&This->sg->mtype.formattype,&GUID_NULL) &&
1146 !IsEqualGUID(&This->sg->mtype.formattype,&FORMAT_None) &&
1147 !IsEqualGUID(&This->sg->mtype.formattype,&type->formattype))
1148 return VFW_E_TYPE_NOT_ACCEPTED;
1149 if (This->sg->mtype.pbFormat)
1150 CoTaskMemFree(This->sg->mtype.pbFormat);
1151 This->sg->mtype = *type;
1152 This->sg->mtype.pUnk = NULL;
1153 if (type->cbFormat) {
1154 This->sg->mtype.pbFormat = CoTaskMemAlloc(type->cbFormat);
1155 CopyMemory(This->sg->mtype.pbFormat, type->pbFormat, type->cbFormat);
1158 This->sg->mtype.pbFormat = NULL;
1160 This->pair = connector;
1161 TRACE("(%p) Accepted IPin %p\n", This, connector);
1165 /* IPin - output pin */
1166 static HRESULT WINAPI
1167 SampleGrabber_Out_IPin_ReceiveConnection(IPin *iface, IPin *connector, const AM_MEDIA_TYPE *mtype)
1169 WARN("(%p, %p): unexpected\n", connector, mtype);
1170 return E_UNEXPECTED;
1173 /* IPin - input pin */
1174 static HRESULT WINAPI
1175 SampleGrabber_In_IPin_Disconnect(IPin *iface)
1177 SG_Pin *This = impl_from_IPin(iface);
1179 TRACE("(%p)->() pair = %p\n", This, This->pair);
1180 if (This->sg->state != State_Stopped)
1181 return VFW_E_NOT_STOPPED;
1189 /* IPin - output pin */
1190 static HRESULT WINAPI
1191 SampleGrabber_Out_IPin_Disconnect(IPin *iface)
1193 SG_Pin *This = impl_from_IPin(iface);
1195 TRACE("(%p)->() pair = %p\n", This, This->pair);
1196 if (This->sg->state != State_Stopped)
1197 return VFW_E_NOT_STOPPED;
1200 if (This->sg->memOutput) {
1201 IMemInputPin_Release(This->sg->memOutput);
1202 This->sg->memOutput = NULL;
1210 static HRESULT WINAPI
1211 SampleGrabber_IPin_ConnectedTo(IPin *iface, IPin **pin)
1213 SG_Pin *This = impl_from_IPin(iface);
1215 TRACE("(%p)->(%p) pair = %p\n", This, pin, This->pair);
1223 return VFW_E_NOT_CONNECTED;
1227 static HRESULT WINAPI
1228 SampleGrabber_IPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *mtype)
1230 SG_Pin *This = impl_from_IPin(iface);
1232 TRACE("(%p)->(%p)\n", This, mtype);
1236 return VFW_E_NOT_CONNECTED;
1237 *mtype = This->sg->mtype;
1238 if (mtype->cbFormat) {
1239 mtype->pbFormat = CoTaskMemAlloc(mtype->cbFormat);
1240 CopyMemory(mtype->pbFormat, This->sg->mtype.pbFormat, mtype->cbFormat);
1246 static HRESULT WINAPI
1247 SampleGrabber_IPin_QueryPinInfo(IPin *iface, PIN_INFO *info)
1249 SG_Pin *This = impl_from_IPin(iface);
1251 TRACE("(%p)->(%p)\n", This, info);
1254 IBaseFilter_AddRef(&This->sg->IBaseFilter_iface);
1255 info->pFilter = &This->sg->IBaseFilter_iface;
1256 info->dir = This->dir;
1257 lstrcpynW(info->achName,This->name,MAX_PIN_NAME);
1262 static HRESULT WINAPI
1263 SampleGrabber_IPin_QueryDirection(IPin *iface, PIN_DIRECTION *dir)
1265 SG_Pin *This = impl_from_IPin(iface);
1267 TRACE("(%p)->(%p)\n", This, dir);
1275 static HRESULT WINAPI
1276 SampleGrabber_IPin_QueryId(IPin *iface, LPWSTR *id)
1278 SG_Pin *This = impl_from_IPin(iface);
1281 TRACE("(%p)->(%p)\n", This, id);
1284 len = sizeof(WCHAR)*(1+lstrlenW(This->name));
1285 *id = CoTaskMemAlloc(len);
1286 CopyMemory(*id, This->name, len);
1291 static HRESULT WINAPI
1292 SampleGrabber_IPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *mtype)
1294 TRACE("(%p)\n", mtype);
1299 static HRESULT WINAPI
1300 SampleGrabber_IPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **mtypes)
1302 SG_Pin *This = impl_from_IPin(iface);
1304 TRACE("(%p)->(%p)\n", This, mtypes);
1307 *mtypes = mediaenum_create(This->sg->pin_in.pair ? &This->sg->mtype : NULL);
1308 return *mtypes ? S_OK : E_OUTOFMEMORY;
1311 /* IPin - input pin */
1312 static HRESULT WINAPI
1313 SampleGrabber_In_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1315 SG_Pin *This = impl_from_IPin(iface);
1317 TRACE("(%p)->(%p, %p) size = %u\n", This, pins, nPins, (nPins ? *nPins : 0));
1323 IPin_AddRef(&This->sg->pin_out.IPin_iface);
1324 *pins = &This->sg->pin_out.IPin_iface;
1332 /* IPin - output pin */
1333 static HRESULT WINAPI
1334 SampleGrabber_Out_IPin_QueryInternalConnections(IPin *iface, IPin **pins, ULONG *nPins)
1336 WARN("(%p, %p): unexpected\n", pins, nPins);
1343 static HRESULT WINAPI
1344 SampleGrabber_IPin_EndOfStream(IPin *iface)
1351 static HRESULT WINAPI
1352 SampleGrabber_IPin_BeginFlush(IPin *iface)
1359 static HRESULT WINAPI
1360 SampleGrabber_IPin_EndFlush(IPin *iface)
1367 static HRESULT WINAPI
1368 SampleGrabber_IPin_NewSegment(IPin *iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double rate)
1375 /* SampleGrabber vtables and constructor */
1377 static const IBaseFilterVtbl IBaseFilter_VTable =
1379 SampleGrabber_IBaseFilter_QueryInterface,
1380 SampleGrabber_IBaseFilter_AddRef,
1381 SampleGrabber_IBaseFilter_Release,
1382 SampleGrabber_IBaseFilter_GetClassID,
1383 SampleGrabber_IBaseFilter_Stop,
1384 SampleGrabber_IBaseFilter_Pause,
1385 SampleGrabber_IBaseFilter_Run,
1386 SampleGrabber_IBaseFilter_GetState,
1387 SampleGrabber_IBaseFilter_SetSyncSource,
1388 SampleGrabber_IBaseFilter_GetSyncSource,
1389 SampleGrabber_IBaseFilter_EnumPins,
1390 SampleGrabber_IBaseFilter_FindPin,
1391 SampleGrabber_IBaseFilter_QueryFilterInfo,
1392 SampleGrabber_IBaseFilter_JoinFilterGraph,
1393 SampleGrabber_IBaseFilter_QueryVendorInfo,
1396 static const ISampleGrabberVtbl ISampleGrabber_VTable =
1398 SampleGrabber_ISampleGrabber_QueryInterface,
1399 SampleGrabber_ISampleGrabber_AddRef,
1400 SampleGrabber_ISampleGrabber_Release,
1401 SampleGrabber_ISampleGrabber_SetOneShot,
1402 SampleGrabber_ISampleGrabber_SetMediaType,
1403 SampleGrabber_ISampleGrabber_GetConnectedMediaType,
1404 SampleGrabber_ISampleGrabber_SetBufferSamples,
1405 SampleGrabber_ISampleGrabber_GetCurrentBuffer,
1406 SampleGrabber_ISampleGrabber_GetCurrentSample,
1407 SampleGrabber_ISampleGrabber_SetCallback,
1410 static const IMemInputPinVtbl IMemInputPin_VTable =
1412 SampleGrabber_IMemInputPin_QueryInterface,
1413 SampleGrabber_IMemInputPin_AddRef,
1414 SampleGrabber_IMemInputPin_Release,
1415 SampleGrabber_IMemInputPin_GetAllocator,
1416 SampleGrabber_IMemInputPin_NotifyAllocator,
1417 SampleGrabber_IMemInputPin_GetAllocatorRequirements,
1418 SampleGrabber_IMemInputPin_Receive,
1419 SampleGrabber_IMemInputPin_ReceiveMultiple,
1420 SampleGrabber_IMemInputPin_ReceiveCanBlock,
1423 static const IPinVtbl IPin_In_VTable =
1425 SampleGrabber_IPin_QueryInterface,
1426 SampleGrabber_IPin_AddRef,
1427 SampleGrabber_IPin_Release,
1428 SampleGrabber_In_IPin_Connect,
1429 SampleGrabber_In_IPin_ReceiveConnection,
1430 SampleGrabber_In_IPin_Disconnect,
1431 SampleGrabber_IPin_ConnectedTo,
1432 SampleGrabber_IPin_ConnectionMediaType,
1433 SampleGrabber_IPin_QueryPinInfo,
1434 SampleGrabber_IPin_QueryDirection,
1435 SampleGrabber_IPin_QueryId,
1436 SampleGrabber_IPin_QueryAccept,
1437 SampleGrabber_IPin_EnumMediaTypes,
1438 SampleGrabber_In_IPin_QueryInternalConnections,
1439 SampleGrabber_IPin_EndOfStream,
1440 SampleGrabber_IPin_BeginFlush,
1441 SampleGrabber_IPin_EndFlush,
1442 SampleGrabber_IPin_NewSegment,
1445 static const IPinVtbl IPin_Out_VTable =
1447 SampleGrabber_IPin_QueryInterface,
1448 SampleGrabber_IPin_AddRef,
1449 SampleGrabber_IPin_Release,
1450 SampleGrabber_Out_IPin_Connect,
1451 SampleGrabber_Out_IPin_ReceiveConnection,
1452 SampleGrabber_Out_IPin_Disconnect,
1453 SampleGrabber_IPin_ConnectedTo,
1454 SampleGrabber_IPin_ConnectionMediaType,
1455 SampleGrabber_IPin_QueryPinInfo,
1456 SampleGrabber_IPin_QueryDirection,
1457 SampleGrabber_IPin_QueryId,
1458 SampleGrabber_IPin_QueryAccept,
1459 SampleGrabber_IPin_EnumMediaTypes,
1460 SampleGrabber_Out_IPin_QueryInternalConnections,
1461 SampleGrabber_IPin_EndOfStream,
1462 SampleGrabber_IPin_BeginFlush,
1463 SampleGrabber_IPin_EndFlush,
1464 SampleGrabber_IPin_NewSegment,
1467 HRESULT SampleGrabber_create(IUnknown *pUnkOuter, LPVOID *ppv)
1469 SG_Impl* obj = NULL;
1471 TRACE("(%p,%p)\n", ppv, pUnkOuter);
1473 obj = CoTaskMemAlloc(sizeof(SG_Impl));
1476 return E_OUTOFMEMORY;
1478 ZeroMemory(obj, sizeof(SG_Impl));
1481 obj->IUnknown_inner.lpVtbl = &samplegrabber_vtbl;
1482 obj->IBaseFilter_iface.lpVtbl = &IBaseFilter_VTable;
1483 obj->ISampleGrabber_iface.lpVtbl = &ISampleGrabber_VTable;
1484 obj->IMemInputPin_iface.lpVtbl = &IMemInputPin_VTable;
1485 obj->pin_in.IPin_iface.lpVtbl = &IPin_In_VTable;
1486 obj->pin_in.dir = PINDIR_INPUT;
1487 obj->pin_in.name = pin_in_name;
1488 obj->pin_in.sg = obj;
1489 obj->pin_in.pair = NULL;
1490 obj->pin_out.IPin_iface.lpVtbl = &IPin_Out_VTable;
1491 obj->pin_out.dir = PINDIR_OUTPUT;
1492 obj->pin_out.name = pin_out_name;
1493 obj->pin_out.sg = obj;
1494 obj->pin_out.pair = NULL;
1495 InitializeCriticalSection(&obj->critSect);
1496 obj->critSect.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SG_Impl.critSect");
1497 obj->info.achName[0] = 0;
1498 obj->info.pGraph = NULL;
1499 obj->state = State_Stopped;
1500 obj->mtype.majortype = GUID_NULL;
1501 obj->mtype.subtype = MEDIASUBTYPE_None;
1502 obj->mtype.formattype = FORMAT_None;
1503 obj->allocator = NULL;
1504 obj->refClock = NULL;
1505 obj->memOutput = NULL;
1506 obj->grabberIface = NULL;
1507 obj->grabberMethod = -1;
1508 obj->oneShot = OneShot_None;
1509 obj->bufferLen = -1;
1510 obj->bufferData = NULL;
1513 obj->outer_unk = pUnkOuter;
1515 obj->outer_unk = &obj->IUnknown_inner;
1517 *ppv = &obj->IUnknown_inner;