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"
32 #include "wine/strmbase.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(qedit
);
36 static const WCHAR vendor_name
[] = { 'W', 'i', 'n', 'e', 0 };
37 static const WCHAR pin_in_name
[] = { 'I', 'n', 0 };
38 static const WCHAR pin_out_name
[] = { 'O', 'u', 't', 0 };
40 static IEnumMediaTypes
*mediaenum_create(const AM_MEDIA_TYPE
*mtype
, BOOL past
);
42 /* Single media type enumerator */
43 typedef struct _ME_Impl
{
44 IEnumMediaTypes IEnumMediaTypes_iface
;
51 /* IEnumMediaTypes interface implementation */
53 static inline ME_Impl
*impl_from_IEnumMediaTypes(IEnumMediaTypes
*iface
)
55 return CONTAINING_RECORD(iface
, ME_Impl
, IEnumMediaTypes_iface
);
58 static HRESULT WINAPI
Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes
*iface
, REFIID riid
,
61 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
63 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ret_iface
);
65 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IEnumMediaTypes
)) {
67 IEnumMediaTypes_AddRef(iface
);
71 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ret_iface
);
75 static ULONG WINAPI
Single_IEnumMediaTypes_AddRef(IEnumMediaTypes
*iface
)
77 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
78 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
80 TRACE("(%p) new ref = %u\n", This
, refCount
);
84 static ULONG WINAPI
Single_IEnumMediaTypes_Release(IEnumMediaTypes
*iface
)
86 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
87 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
89 TRACE("(%p) new ref = %u\n", This
, refCount
);
92 CoTaskMemFree(This
->mtype
.pbFormat
);
99 static HRESULT WINAPI
Single_IEnumMediaTypes_Next(IEnumMediaTypes
*iface
, ULONG nTypes
,
100 AM_MEDIA_TYPE
**types
, ULONG
*fetched
)
102 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
105 TRACE("(%p)->(%u, %p, %p)\n", This
, nTypes
, types
, fetched
);
108 if (!types
|| ((nTypes
!= 1) && !fetched
))
110 if (!This
->past
&& !IsEqualGUID(&This
->mtype
.majortype
,&GUID_NULL
)) {
111 AM_MEDIA_TYPE
*mtype
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
112 *mtype
= This
->mtype
;
113 if (mtype
->cbFormat
) {
114 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
115 CopyMemory(mtype
->pbFormat
, This
->mtype
.pbFormat
, mtype
->cbFormat
);
123 return (count
== nTypes
) ? S_OK
: S_FALSE
;
126 static HRESULT WINAPI
Single_IEnumMediaTypes_Skip(IEnumMediaTypes
*iface
, ULONG nTypes
)
128 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
130 TRACE("(%p)->(%u)\n", This
, nTypes
);
133 return This
->past
? S_FALSE
: S_OK
;
136 static HRESULT WINAPI
Single_IEnumMediaTypes_Reset(IEnumMediaTypes
*iface
)
138 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
140 TRACE("(%p)->()\n", This
);
145 static HRESULT WINAPI
Single_IEnumMediaTypes_Clone(IEnumMediaTypes
*iface
, IEnumMediaTypes
**me
)
147 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
149 TRACE("(%p)->(%p)\n", This
, me
);
152 *me
= mediaenum_create(&This
->mtype
, This
->past
);
154 return E_OUTOFMEMORY
;
159 /* Virtual tables and constructor */
161 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable
=
163 Single_IEnumMediaTypes_QueryInterface
,
164 Single_IEnumMediaTypes_AddRef
,
165 Single_IEnumMediaTypes_Release
,
166 Single_IEnumMediaTypes_Next
,
167 Single_IEnumMediaTypes_Skip
,
168 Single_IEnumMediaTypes_Reset
,
169 Single_IEnumMediaTypes_Clone
,
172 static IEnumMediaTypes
*mediaenum_create(const AM_MEDIA_TYPE
*mtype
, BOOL past
)
174 ME_Impl
*obj
= CoTaskMemAlloc(sizeof(ME_Impl
));
178 ZeroMemory(obj
, sizeof(*obj
));
179 obj
->IEnumMediaTypes_iface
.lpVtbl
= &IEnumMediaTypes_VTable
;
184 obj
->mtype
.pUnk
= NULL
;
185 if (mtype
->cbFormat
) {
186 obj
->mtype
.pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
187 CopyMemory(obj
->mtype
.pbFormat
, mtype
->pbFormat
, mtype
->cbFormat
);
190 obj
->mtype
.pbFormat
= NULL
;
193 obj
->mtype
.majortype
= GUID_NULL
;
195 return &obj
->IEnumMediaTypes_iface
;
199 /* Sample Grabber pin implementation */
200 typedef struct _SG_Pin
{
208 static inline SG_Pin
*impl_from_IPin(IPin
*iface
)
210 return CONTAINING_RECORD(iface
, SG_Pin
, IPin_iface
);
213 /* Sample Grabber filter implementation */
214 typedef struct _SG_Impl
{
215 IUnknown IUnknown_inner
;
217 ISampleGrabber ISampleGrabber_iface
;
218 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
219 IUnknown
* seekthru_unk
;
224 IMemInputPin IMemInputPin_iface
;
225 IMemAllocator
*allocator
;
226 IMemInputPin
*memOutput
;
227 ISampleGrabberCB
*grabberIface
;
240 static inline SG_Impl
*impl_from_IUnknown(IUnknown
*iface
)
242 return CONTAINING_RECORD(iface
, SG_Impl
, IUnknown_inner
);
245 static inline SG_Impl
*impl_from_BaseFilter(BaseFilter
*iface
)
247 return CONTAINING_RECORD(iface
, SG_Impl
, filter
);
250 static inline SG_Impl
*impl_from_IBaseFilter(IBaseFilter
*iface
)
252 return CONTAINING_RECORD(iface
, SG_Impl
, filter
.IBaseFilter_iface
);
255 static inline SG_Impl
*impl_from_ISampleGrabber(ISampleGrabber
*iface
)
257 return CONTAINING_RECORD(iface
, SG_Impl
, ISampleGrabber_iface
);
260 static inline SG_Impl
*impl_from_IMemInputPin(IMemInputPin
*iface
)
262 return CONTAINING_RECORD(iface
, SG_Impl
, IMemInputPin_iface
);
266 /* Cleanup at end of life */
267 static void SampleGrabber_cleanup(SG_Impl
*This
)
269 TRACE("(%p)\n", This
);
270 if (This
->filter
.filterInfo
.pGraph
)
271 WARN("(%p) still joined to filter graph %p\n", This
, This
->filter
.filterInfo
.pGraph
);
273 IMemAllocator_Release(This
->allocator
);
275 IMemInputPin_Release(This
->memOutput
);
276 if (This
->grabberIface
)
277 ISampleGrabberCB_Release(This
->grabberIface
);
278 CoTaskMemFree(This
->mtype
.pbFormat
);
279 CoTaskMemFree(This
->bufferData
);
280 if(This
->seekthru_unk
)
281 IUnknown_Release(This
->seekthru_unk
);
284 /* SampleGrabber inner IUnknown */
285 static HRESULT WINAPI
SampleGrabber_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
287 SG_Impl
*This
= impl_from_IUnknown(iface
);
289 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
292 if (IsEqualIID(riid
, &IID_IUnknown
))
293 *ppv
= &This
->IUnknown_inner
;
294 else if (IsEqualIID(riid
, &IID_IPersist
) || IsEqualIID(riid
, &IID_IMediaFilter
) ||
295 IsEqualIID(riid
, &IID_IBaseFilter
))
296 *ppv
= &This
->filter
.IBaseFilter_iface
;
297 else if (IsEqualIID(riid
, &IID_ISampleGrabber
))
298 *ppv
= &This
->ISampleGrabber_iface
;
299 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
300 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
301 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
302 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
304 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
307 return E_NOINTERFACE
;
309 IUnknown_AddRef((IUnknown
*)*ppv
);
313 static ULONG WINAPI
SampleGrabber_AddRef(IUnknown
*iface
)
315 SG_Impl
*This
= impl_from_IUnknown(iface
);
316 ULONG ref
= BaseFilterImpl_AddRef(&This
->filter
.IBaseFilter_iface
);
318 TRACE("(%p) ref=%d\n", This
, ref
);
323 static ULONG WINAPI
SampleGrabber_Release(IUnknown
*iface
)
325 SG_Impl
*This
= impl_from_IUnknown(iface
);
326 ULONG ref
= BaseFilterImpl_Release(&This
->filter
.IBaseFilter_iface
);
328 TRACE("(%p) ref=%d\n", This
, ref
);
332 SampleGrabber_cleanup(This
);
338 static const IUnknownVtbl samplegrabber_vtbl
=
340 SampleGrabber_QueryInterface
,
341 SampleGrabber_AddRef
,
342 SampleGrabber_Release
,
345 static IPin
*WINAPI
SampleGrabber_GetPin(BaseFilter
*iface
, int pos
)
347 SG_Impl
*This
= impl_from_BaseFilter(iface
);
351 pin
= &This
->pin_in
.IPin_iface
;
353 pin
= &This
->pin_out
.IPin_iface
;
361 static LONG WINAPI
SampleGrabber_GetPinCount(BaseFilter
*iface
)
366 static const BaseFilterFuncTable basefunc_vtbl
= {
367 SampleGrabber_GetPin
,
368 SampleGrabber_GetPinCount
371 /* Helper that buffers data and/or calls installed sample callbacks */
372 static void SampleGrabber_callback(SG_Impl
*This
, IMediaSample
*sample
)
375 REFERENCE_TIME tStart
, tEnd
;
376 if (This
->bufferLen
>= 0) {
378 LONG size
= IMediaSample_GetActualDataLength(sample
);
379 if (size
>= 0 && SUCCEEDED(IMediaSample_GetPointer(sample
, &data
))) {
382 EnterCriticalSection(&This
->filter
.csFilter
);
383 if (This
->bufferLen
!= size
) {
384 CoTaskMemFree(This
->bufferData
);
385 This
->bufferData
= size
? CoTaskMemAlloc(size
) : NULL
;
386 This
->bufferLen
= size
;
389 CopyMemory(This
->bufferData
, data
, size
);
390 LeaveCriticalSection(&This
->filter
.csFilter
);
393 if (!This
->grabberIface
)
395 if (SUCCEEDED(IMediaSample_GetTime(sample
, &tStart
, &tEnd
)))
396 time
= 1e-7 * tStart
;
397 switch (This
->grabberMethod
) {
400 ULONG ref
= IMediaSample_AddRef(sample
);
401 ISampleGrabberCB_SampleCB(This
->grabberIface
, time
, sample
);
402 ref
= IMediaSample_Release(sample
) + 1 - ref
;
405 ERR("(%p) Callback referenced sample %p by %u\n", This
, sample
, ref
);
406 /* ugly as hell but some apps are sooo buggy */
408 IMediaSample_Release(sample
);
415 LONG size
= IMediaSample_GetActualDataLength(sample
);
416 if (size
&& SUCCEEDED(IMediaSample_GetPointer(sample
, &data
)) && data
)
417 ISampleGrabberCB_BufferCB(This
->grabberIface
, time
, data
, size
);
423 FIXME("unsupported method %d\n", This
->grabberMethod
);
424 /* do not bother us again */
425 This
->grabberMethod
= -1;
430 /* SampleGrabber implementation of IBaseFilter interface */
433 static HRESULT WINAPI
434 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
436 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
437 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
442 SampleGrabber_IBaseFilter_AddRef(IBaseFilter
*iface
)
444 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
445 return IUnknown_AddRef(This
->outer_unk
);
450 SampleGrabber_IBaseFilter_Release(IBaseFilter
*iface
)
452 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
453 return IUnknown_Release(This
->outer_unk
);
457 static HRESULT WINAPI
458 SampleGrabber_IBaseFilter_Stop(IBaseFilter
*iface
)
460 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
461 TRACE("(%p)\n", This
);
462 This
->filter
.state
= State_Stopped
;
467 static HRESULT WINAPI
468 SampleGrabber_IBaseFilter_Pause(IBaseFilter
*iface
)
470 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
471 TRACE("(%p)\n", This
);
472 This
->filter
.state
= State_Paused
;
477 static HRESULT WINAPI
478 SampleGrabber_IBaseFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
480 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
481 TRACE("(%p)\n", This
);
482 This
->filter
.state
= State_Running
;
487 static HRESULT WINAPI
488 SampleGrabber_IBaseFilter_FindPin(IBaseFilter
*iface
, LPCWSTR id
, IPin
**pin
)
490 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
491 TRACE("(%p)->(%s, %p)\n", This
, debugstr_w(id
), pin
);
494 if (!lstrcmpiW(id
,pin_in_name
))
496 *pin
= &This
->pin_in
.IPin_iface
;
500 else if (!lstrcmpiW(id
,pin_out_name
))
502 *pin
= &This
->pin_out
.IPin_iface
;
507 return VFW_E_NOT_FOUND
;
511 static HRESULT WINAPI
512 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*graph
, LPCWSTR name
)
514 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
516 TRACE("(%p)->(%p, %s)\n", This
, graph
, debugstr_w(name
));
518 BaseFilterImpl_JoinFilterGraph(iface
, graph
, name
);
519 This
->oneShot
= OneShot_None
;
525 static HRESULT WINAPI
526 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter
*iface
, LPWSTR
*vendor
)
528 TRACE("(%p)\n", vendor
);
531 *vendor
= CoTaskMemAlloc(sizeof(vendor_name
));
532 CopyMemory(*vendor
, vendor_name
, sizeof(vendor_name
));
537 /* SampleGrabber implementation of ISampleGrabber interface */
540 static HRESULT WINAPI
541 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber
*iface
, REFIID riid
, void **ppv
)
543 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
544 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
549 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber
*iface
)
551 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
552 return IUnknown_AddRef(This
->outer_unk
);
557 SampleGrabber_ISampleGrabber_Release(ISampleGrabber
*iface
)
559 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
560 return IUnknown_Release(This
->outer_unk
);
564 static HRESULT WINAPI
565 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber
*iface
, BOOL oneShot
)
567 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
568 TRACE("(%p)->(%u)\n", This
, oneShot
);
569 This
->oneShot
= oneShot
? OneShot_Wait
: OneShot_None
;
574 static HRESULT WINAPI
575 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber
*iface
, const AM_MEDIA_TYPE
*type
)
577 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
578 TRACE("(%p)->(%p)\n", This
, type
);
581 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
582 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
584 debugstr_guid(&type
->formattype
), type
->cbFormat
);
585 CoTaskMemFree(This
->mtype
.pbFormat
);
587 This
->mtype
.pUnk
= NULL
;
588 if (type
->cbFormat
) {
589 This
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
590 CopyMemory(This
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
593 This
->mtype
.pbFormat
= NULL
;
598 static HRESULT WINAPI
599 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber
*iface
, AM_MEDIA_TYPE
*type
)
601 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
602 TRACE("(%p)->(%p)\n", This
, type
);
605 if (!This
->pin_in
.pair
)
606 return VFW_E_NOT_CONNECTED
;
608 if (type
->cbFormat
) {
609 type
->pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
610 CopyMemory(type
->pbFormat
, This
->mtype
.pbFormat
, type
->cbFormat
);
616 static HRESULT WINAPI
617 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber
*iface
, BOOL bufferEm
)
619 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
620 TRACE("(%p)->(%u)\n", This
, bufferEm
);
621 EnterCriticalSection(&This
->filter
.csFilter
);
623 if (This
->bufferLen
< 0)
627 This
->bufferLen
= -1;
628 LeaveCriticalSection(&This
->filter
.csFilter
);
633 static HRESULT WINAPI
634 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber
*iface
, LONG
*bufSize
, LONG
*buffer
)
636 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
638 TRACE("(%p)->(%p, %p)\n", This
, bufSize
, buffer
);
641 EnterCriticalSection(&This
->filter
.csFilter
);
642 if (!This
->pin_in
.pair
)
643 ret
= VFW_E_NOT_CONNECTED
;
644 else if (This
->bufferLen
< 0)
646 else if (This
->bufferLen
== 0)
647 ret
= VFW_E_WRONG_STATE
;
650 if (*bufSize
>= This
->bufferLen
)
651 CopyMemory(buffer
, This
->bufferData
, This
->bufferLen
);
655 *bufSize
= This
->bufferLen
;
657 LeaveCriticalSection(&This
->filter
.csFilter
);
662 static HRESULT WINAPI
663 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber
*iface
, IMediaSample
**sample
)
665 /* MS doesn't implement it either, no one should call it */
666 WARN("(%p): not implemented\n", sample
);
671 static HRESULT WINAPI
672 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber
*iface
, ISampleGrabberCB
*cb
, LONG whichMethod
)
674 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
675 TRACE("(%p)->(%p, %u)\n", This
, cb
, whichMethod
);
676 if (This
->grabberIface
)
677 ISampleGrabberCB_Release(This
->grabberIface
);
678 This
->grabberIface
= cb
;
679 This
->grabberMethod
= whichMethod
;
681 ISampleGrabberCB_AddRef(cb
);
686 /* SampleGrabber implementation of IMemInputPin interface */
689 static HRESULT WINAPI
690 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin
*iface
, REFIID riid
, void **ppv
)
692 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
693 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
698 SampleGrabber_IMemInputPin_AddRef(IMemInputPin
*iface
)
700 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
701 return IUnknown_AddRef(This
->outer_unk
);
706 SampleGrabber_IMemInputPin_Release(IMemInputPin
*iface
)
708 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
709 return IUnknown_Release(This
->outer_unk
);
713 static HRESULT WINAPI
714 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin
*iface
, IMemAllocator
**allocator
)
716 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
717 TRACE("(%p)->(%p) allocator = %p\n", This
, allocator
, This
->allocator
);
720 *allocator
= This
->allocator
;
722 return VFW_E_NO_ALLOCATOR
;
723 IMemAllocator_AddRef(*allocator
);
728 static HRESULT WINAPI
729 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin
*iface
, IMemAllocator
*allocator
, BOOL readOnly
)
731 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
732 TRACE("(%p)->(%p, %u) allocator = %p\n", This
, allocator
, readOnly
, This
->allocator
);
733 if (This
->allocator
== allocator
)
736 IMemAllocator_Release(This
->allocator
);
737 This
->allocator
= allocator
;
739 IMemAllocator_AddRef(allocator
);
744 static HRESULT WINAPI
745 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
747 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
748 FIXME("(%p)->(%p): semi-stub\n", This
, props
);
751 return This
->memOutput
? IMemInputPin_GetAllocatorRequirements(This
->memOutput
, props
) : E_NOTIMPL
;
755 static HRESULT WINAPI
756 SampleGrabber_IMemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*sample
)
758 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
760 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This
, sample
, This
->memOutput
, This
->grabberIface
);
763 if (This
->oneShot
== OneShot_Past
)
765 SampleGrabber_callback(This
, sample
);
766 hr
= This
->memOutput
? IMemInputPin_Receive(This
->memOutput
, sample
) : S_OK
;
767 if (This
->oneShot
== OneShot_Wait
) {
768 This
->oneShot
= OneShot_Past
;
770 if (This
->pin_out
.pair
)
771 IPin_EndOfStream(This
->pin_out
.pair
);
777 static HRESULT WINAPI
778 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin
*iface
, IMediaSample
**samples
, LONG nSamples
, LONG
*nProcessed
)
780 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
782 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This
, samples
, nSamples
, nProcessed
, This
->memOutput
, This
->grabberIface
);
783 if (!samples
|| !nProcessed
)
785 if ((This
->filter
.state
!= State_Running
) || (This
->oneShot
== OneShot_Past
))
787 for (idx
= 0; idx
< nSamples
; idx
++)
788 SampleGrabber_callback(This
, samples
[idx
]);
789 return This
->memOutput
? IMemInputPin_ReceiveMultiple(This
->memOutput
, samples
, nSamples
, nProcessed
) : S_OK
;
793 static HRESULT WINAPI
794 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
796 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
797 TRACE("(%p)\n", This
);
798 return This
->memOutput
? IMemInputPin_ReceiveCanBlock(This
->memOutput
) : S_OK
;
802 /* SampleGrabber member pin implementation */
806 SampleGrabber_IPin_AddRef(IPin
*iface
)
808 SG_Pin
*This
= impl_from_IPin(iface
);
809 return ISampleGrabber_AddRef(&This
->sg
->ISampleGrabber_iface
);
814 SampleGrabber_IPin_Release(IPin
*iface
)
816 SG_Pin
*This
= impl_from_IPin(iface
);
817 return ISampleGrabber_Release(&This
->sg
->ISampleGrabber_iface
);
821 static HRESULT WINAPI
822 SampleGrabber_IPin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
824 SG_Pin
*This
= impl_from_IPin(iface
);
825 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
828 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPin
))
830 else if (IsEqualIID(riid
, &IID_IMemInputPin
))
831 *ppv
= &This
->sg
->IMemInputPin_iface
;
832 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
833 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
834 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
835 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
837 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
838 return E_NOINTERFACE
;
841 IUnknown_AddRef((IUnknown
*)*ppv
);
845 /* IPin - input pin */
846 static HRESULT WINAPI
847 SampleGrabber_In_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*mtype
)
849 WARN("(%p, %p): unexpected\n", receiver
, mtype
);
853 /* IPin - output pin */
854 static HRESULT WINAPI
855 SampleGrabber_Out_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*type
)
857 SG_Pin
*This
= impl_from_IPin(iface
);
860 TRACE("(%p)->(%p, %p)\n", This
, receiver
, type
);
864 return VFW_E_ALREADY_CONNECTED
;
865 if (This
->sg
->filter
.state
!= State_Stopped
)
866 return VFW_E_NOT_STOPPED
;
868 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
869 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
871 debugstr_guid(&type
->formattype
), type
->cbFormat
);
872 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
873 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
874 return VFW_E_TYPE_NOT_ACCEPTED
;
875 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
876 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
877 return VFW_E_TYPE_NOT_ACCEPTED
;
878 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
879 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
880 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
881 return VFW_E_TYPE_NOT_ACCEPTED
;
884 type
= &This
->sg
->mtype
;
885 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
886 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
888 return VFW_E_TYPE_NOT_ACCEPTED
;
889 hr
= IPin_ReceiveConnection(receiver
, &This
->IPin_iface
, type
);
892 This
->pair
= receiver
;
893 if (This
->sg
->memOutput
) {
894 IMemInputPin_Release(This
->sg
->memOutput
);
895 This
->sg
->memOutput
= NULL
;
897 IPin_QueryInterface(receiver
,&IID_IMemInputPin
,(void **)&(This
->sg
->memOutput
));
898 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This
, receiver
, This
->sg
->memOutput
);
902 /* IPin - input pin */
903 static HRESULT WINAPI
904 SampleGrabber_In_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*type
)
906 SG_Pin
*This
= impl_from_IPin(iface
);
908 TRACE("(%p)->(%p, %p)\n", This
, connector
, type
);
912 return VFW_E_ALREADY_CONNECTED
;
913 if (This
->sg
->filter
.state
!= State_Stopped
)
914 return VFW_E_NOT_STOPPED
;
916 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
917 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
919 debugstr_guid(&type
->formattype
), type
->cbFormat
);
920 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
921 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
923 return VFW_E_INVALIDMEDIATYPE
;
924 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
925 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
926 return VFW_E_TYPE_NOT_ACCEPTED
;
927 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
928 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
929 return VFW_E_TYPE_NOT_ACCEPTED
;
930 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
931 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
932 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
933 return VFW_E_TYPE_NOT_ACCEPTED
;
934 CoTaskMemFree(This
->sg
->mtype
.pbFormat
);
935 This
->sg
->mtype
= *type
;
936 This
->sg
->mtype
.pUnk
= NULL
;
937 if (type
->cbFormat
) {
938 This
->sg
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
939 CopyMemory(This
->sg
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
942 This
->sg
->mtype
.pbFormat
= NULL
;
944 This
->pair
= connector
;
945 TRACE("(%p) Accepted IPin %p\n", This
, connector
);
949 /* IPin - output pin */
950 static HRESULT WINAPI
951 SampleGrabber_Out_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*mtype
)
953 WARN("(%p, %p): unexpected\n", connector
, mtype
);
957 /* IPin - input pin */
958 static HRESULT WINAPI
959 SampleGrabber_In_IPin_Disconnect(IPin
*iface
)
961 SG_Pin
*This
= impl_from_IPin(iface
);
963 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
964 if (This
->sg
->filter
.state
!= State_Stopped
)
965 return VFW_E_NOT_STOPPED
;
973 /* IPin - output pin */
974 static HRESULT WINAPI
975 SampleGrabber_Out_IPin_Disconnect(IPin
*iface
)
977 SG_Pin
*This
= impl_from_IPin(iface
);
979 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
980 if (This
->sg
->filter
.state
!= State_Stopped
)
981 return VFW_E_NOT_STOPPED
;
984 if (This
->sg
->memOutput
) {
985 IMemInputPin_Release(This
->sg
->memOutput
);
986 This
->sg
->memOutput
= NULL
;
994 static HRESULT WINAPI
995 SampleGrabber_IPin_ConnectedTo(IPin
*iface
, IPin
**pin
)
997 SG_Pin
*This
= impl_from_IPin(iface
);
999 TRACE("(%p)->(%p) pair = %p\n", This
, pin
, This
->pair
);
1007 return VFW_E_NOT_CONNECTED
;
1011 static HRESULT WINAPI
1012 SampleGrabber_IPin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*mtype
)
1014 SG_Pin
*This
= impl_from_IPin(iface
);
1016 TRACE("(%p)->(%p)\n", This
, mtype
);
1020 return VFW_E_NOT_CONNECTED
;
1021 *mtype
= This
->sg
->mtype
;
1022 if (mtype
->cbFormat
) {
1023 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
1024 CopyMemory(mtype
->pbFormat
, This
->sg
->mtype
.pbFormat
, mtype
->cbFormat
);
1030 static HRESULT WINAPI
1031 SampleGrabber_IPin_QueryPinInfo(IPin
*iface
, PIN_INFO
*info
)
1033 SG_Pin
*This
= impl_from_IPin(iface
);
1035 TRACE("(%p)->(%p)\n", This
, info
);
1038 info
->pFilter
= &This
->sg
->filter
.IBaseFilter_iface
;
1039 IBaseFilter_AddRef(info
->pFilter
);
1040 info
->dir
= This
->dir
;
1041 lstrcpynW(info
->achName
,This
->name
,MAX_PIN_NAME
);
1046 static HRESULT WINAPI
1047 SampleGrabber_IPin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*dir
)
1049 SG_Pin
*This
= impl_from_IPin(iface
);
1051 TRACE("(%p)->(%p)\n", This
, dir
);
1059 static HRESULT WINAPI
1060 SampleGrabber_IPin_QueryId(IPin
*iface
, LPWSTR
*id
)
1062 SG_Pin
*This
= impl_from_IPin(iface
);
1065 TRACE("(%p)->(%p)\n", This
, id
);
1068 len
= sizeof(WCHAR
)*(1+lstrlenW(This
->name
));
1069 *id
= CoTaskMemAlloc(len
);
1070 CopyMemory(*id
, This
->name
, len
);
1075 static HRESULT WINAPI
1076 SampleGrabber_IPin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mtype
)
1078 TRACE("(%p)\n", mtype
);
1083 static HRESULT WINAPI
1084 SampleGrabber_IPin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**mtypes
)
1086 SG_Pin
*This
= impl_from_IPin(iface
);
1088 TRACE("(%p)->(%p)\n", This
, mtypes
);
1091 *mtypes
= mediaenum_create(This
->sg
->pin_in
.pair
? &This
->sg
->mtype
: NULL
, FALSE
);
1092 return *mtypes
? S_OK
: E_OUTOFMEMORY
;
1095 /* IPin - input pin */
1096 static HRESULT WINAPI
1097 SampleGrabber_In_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1099 SG_Pin
*This
= impl_from_IPin(iface
);
1101 TRACE("(%p)->(%p, %p) size = %u\n", This
, pins
, nPins
, (nPins
? *nPins
: 0));
1107 IPin_AddRef(&This
->sg
->pin_out
.IPin_iface
);
1108 *pins
= &This
->sg
->pin_out
.IPin_iface
;
1116 /* IPin - output pin */
1117 static HRESULT WINAPI
1118 SampleGrabber_Out_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1120 WARN("(%p, %p): unexpected\n", pins
, nPins
);
1127 static HRESULT WINAPI
1128 SampleGrabber_IPin_EndOfStream(IPin
*iface
)
1135 static HRESULT WINAPI
1136 SampleGrabber_IPin_BeginFlush(IPin
*iface
)
1143 static HRESULT WINAPI
1144 SampleGrabber_IPin_EndFlush(IPin
*iface
)
1151 static HRESULT WINAPI
1152 SampleGrabber_IPin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double rate
)
1159 /* SampleGrabber vtables and constructor */
1161 static const IBaseFilterVtbl IBaseFilter_VTable
=
1163 SampleGrabber_IBaseFilter_QueryInterface
,
1164 SampleGrabber_IBaseFilter_AddRef
,
1165 SampleGrabber_IBaseFilter_Release
,
1166 BaseFilterImpl_GetClassID
,
1167 SampleGrabber_IBaseFilter_Stop
,
1168 SampleGrabber_IBaseFilter_Pause
,
1169 SampleGrabber_IBaseFilter_Run
,
1170 BaseFilterImpl_GetState
,
1171 BaseFilterImpl_SetSyncSource
,
1172 BaseFilterImpl_GetSyncSource
,
1173 BaseFilterImpl_EnumPins
,
1174 SampleGrabber_IBaseFilter_FindPin
,
1175 BaseFilterImpl_QueryFilterInfo
,
1176 SampleGrabber_IBaseFilter_JoinFilterGraph
,
1177 SampleGrabber_IBaseFilter_QueryVendorInfo
,
1180 static const ISampleGrabberVtbl ISampleGrabber_VTable
=
1182 SampleGrabber_ISampleGrabber_QueryInterface
,
1183 SampleGrabber_ISampleGrabber_AddRef
,
1184 SampleGrabber_ISampleGrabber_Release
,
1185 SampleGrabber_ISampleGrabber_SetOneShot
,
1186 SampleGrabber_ISampleGrabber_SetMediaType
,
1187 SampleGrabber_ISampleGrabber_GetConnectedMediaType
,
1188 SampleGrabber_ISampleGrabber_SetBufferSamples
,
1189 SampleGrabber_ISampleGrabber_GetCurrentBuffer
,
1190 SampleGrabber_ISampleGrabber_GetCurrentSample
,
1191 SampleGrabber_ISampleGrabber_SetCallback
,
1194 static const IMemInputPinVtbl IMemInputPin_VTable
=
1196 SampleGrabber_IMemInputPin_QueryInterface
,
1197 SampleGrabber_IMemInputPin_AddRef
,
1198 SampleGrabber_IMemInputPin_Release
,
1199 SampleGrabber_IMemInputPin_GetAllocator
,
1200 SampleGrabber_IMemInputPin_NotifyAllocator
,
1201 SampleGrabber_IMemInputPin_GetAllocatorRequirements
,
1202 SampleGrabber_IMemInputPin_Receive
,
1203 SampleGrabber_IMemInputPin_ReceiveMultiple
,
1204 SampleGrabber_IMemInputPin_ReceiveCanBlock
,
1207 static const IPinVtbl IPin_In_VTable
=
1209 SampleGrabber_IPin_QueryInterface
,
1210 SampleGrabber_IPin_AddRef
,
1211 SampleGrabber_IPin_Release
,
1212 SampleGrabber_In_IPin_Connect
,
1213 SampleGrabber_In_IPin_ReceiveConnection
,
1214 SampleGrabber_In_IPin_Disconnect
,
1215 SampleGrabber_IPin_ConnectedTo
,
1216 SampleGrabber_IPin_ConnectionMediaType
,
1217 SampleGrabber_IPin_QueryPinInfo
,
1218 SampleGrabber_IPin_QueryDirection
,
1219 SampleGrabber_IPin_QueryId
,
1220 SampleGrabber_IPin_QueryAccept
,
1221 SampleGrabber_IPin_EnumMediaTypes
,
1222 SampleGrabber_In_IPin_QueryInternalConnections
,
1223 SampleGrabber_IPin_EndOfStream
,
1224 SampleGrabber_IPin_BeginFlush
,
1225 SampleGrabber_IPin_EndFlush
,
1226 SampleGrabber_IPin_NewSegment
,
1229 static const IPinVtbl IPin_Out_VTable
=
1231 SampleGrabber_IPin_QueryInterface
,
1232 SampleGrabber_IPin_AddRef
,
1233 SampleGrabber_IPin_Release
,
1234 SampleGrabber_Out_IPin_Connect
,
1235 SampleGrabber_Out_IPin_ReceiveConnection
,
1236 SampleGrabber_Out_IPin_Disconnect
,
1237 SampleGrabber_IPin_ConnectedTo
,
1238 SampleGrabber_IPin_ConnectionMediaType
,
1239 SampleGrabber_IPin_QueryPinInfo
,
1240 SampleGrabber_IPin_QueryDirection
,
1241 SampleGrabber_IPin_QueryId
,
1242 SampleGrabber_IPin_QueryAccept
,
1243 SampleGrabber_IPin_EnumMediaTypes
,
1244 SampleGrabber_Out_IPin_QueryInternalConnections
,
1245 SampleGrabber_IPin_EndOfStream
,
1246 SampleGrabber_IPin_BeginFlush
,
1247 SampleGrabber_IPin_EndFlush
,
1248 SampleGrabber_IPin_NewSegment
,
1251 HRESULT
SampleGrabber_create(IUnknown
*pUnkOuter
, LPVOID
*ppv
)
1253 SG_Impl
* obj
= NULL
;
1254 ISeekingPassThru
*passthru
;
1257 TRACE("(%p,%p)\n", pUnkOuter
, ppv
);
1259 obj
= CoTaskMemAlloc(sizeof(SG_Impl
));
1262 return E_OUTOFMEMORY
;
1264 ZeroMemory(obj
, sizeof(SG_Impl
));
1266 BaseFilter_Init(&obj
->filter
, &IBaseFilter_VTable
, &CLSID_SampleGrabber
,
1267 (DWORD_PTR
)(__FILE__
": SG_Impl.csFilter"), &basefunc_vtbl
);
1268 obj
->IUnknown_inner
.lpVtbl
= &samplegrabber_vtbl
;
1269 obj
->ISampleGrabber_iface
.lpVtbl
= &ISampleGrabber_VTable
;
1270 obj
->IMemInputPin_iface
.lpVtbl
= &IMemInputPin_VTable
;
1271 obj
->pin_in
.IPin_iface
.lpVtbl
= &IPin_In_VTable
;
1272 obj
->pin_in
.dir
= PINDIR_INPUT
;
1273 obj
->pin_in
.name
= pin_in_name
;
1274 obj
->pin_in
.sg
= obj
;
1275 obj
->pin_in
.pair
= NULL
;
1276 obj
->pin_out
.IPin_iface
.lpVtbl
= &IPin_Out_VTable
;
1277 obj
->pin_out
.dir
= PINDIR_OUTPUT
;
1278 obj
->pin_out
.name
= pin_out_name
;
1279 obj
->pin_out
.sg
= obj
;
1280 obj
->pin_out
.pair
= NULL
;
1281 obj
->mtype
.majortype
= GUID_NULL
;
1282 obj
->mtype
.subtype
= MEDIASUBTYPE_None
;
1283 obj
->mtype
.formattype
= FORMAT_None
;
1284 obj
->allocator
= NULL
;
1285 obj
->memOutput
= NULL
;
1286 obj
->grabberIface
= NULL
;
1287 obj
->grabberMethod
= -1;
1288 obj
->oneShot
= OneShot_None
;
1289 obj
->bufferLen
= -1;
1290 obj
->bufferData
= NULL
;
1293 obj
->outer_unk
= pUnkOuter
;
1295 obj
->outer_unk
= &obj
->IUnknown_inner
;
1297 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, &obj
->IUnknown_inner
, CLSCTX_INPROC_SERVER
,
1298 &IID_IUnknown
, (void**)&obj
->seekthru_unk
);
1301 IUnknown_QueryInterface(obj
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
1302 ISeekingPassThru_Init(passthru
, FALSE
, &obj
->pin_in
.IPin_iface
);
1303 ISeekingPassThru_Release(passthru
);
1305 *ppv
= &obj
->IUnknown_inner
;