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
);
42 /* Single media type enumerator */
43 typedef struct _ME_Impl
{
51 /* IEnumMediaTypes interface implementation */
55 Single_IEnumMediaTypes_AddRef(IEnumMediaTypes
*iface
)
57 ME_Impl
*This
= (ME_Impl
*)iface
;
58 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
59 TRACE("(%p) new ref = %u\n", This
, refCount
);
65 Single_IEnumMediaTypes_Release(IEnumMediaTypes
*iface
)
67 ME_Impl
*This
= (ME_Impl
*)iface
;
68 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
69 TRACE("(%p) new ref = %u\n", This
, refCount
);
72 if (This
->mtype
.pbFormat
)
73 CoTaskMemFree(This
->mtype
.pbFormat
);
82 Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes
*iface
, REFIID riid
, void **ppvObject
)
84 ME_Impl
*This
= (ME_Impl
*)iface
;
85 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
87 if (IsEqualIID(riid
, &IID_IUnknown
) ||
88 IsEqualIID(riid
, &IID_IEnumMediaTypes
)) {
89 Single_IEnumMediaTypes_AddRef(iface
);
90 *ppvObject
= &(This
->me
);
94 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppvObject
);
100 Single_IEnumMediaTypes_Next(IEnumMediaTypes
*iface
, ULONG nTypes
, AM_MEDIA_TYPE
**types
, ULONG
*fetched
)
102 ME_Impl
*This
= (ME_Impl
*)iface
;
104 TRACE("(%p)->(%u, %p, %p)\n", This
, nTypes
, types
, fetched
);
107 if (!types
|| ((nTypes
!= 1) && !fetched
))
109 if (!This
->past
&& !IsEqualGUID(&This
->mtype
.majortype
,&GUID_NULL
)) {
110 AM_MEDIA_TYPE
*mtype
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
111 *mtype
= This
->mtype
;
112 if (mtype
->cbFormat
) {
113 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
114 CopyMemory(mtype
->pbFormat
, This
->mtype
.pbFormat
, mtype
->cbFormat
);
122 return (count
== nTypes
) ? S_OK
: S_FALSE
;
125 /* IEnumMediaTypes */
126 static HRESULT WINAPI
127 Single_IEnumMediaTypes_Skip(IEnumMediaTypes
*iface
, ULONG nTypes
)
129 ME_Impl
*This
= (ME_Impl
*)iface
;
130 TRACE("(%p)->(%u)\n", This
, nTypes
);
133 return This
->past
? S_FALSE
: S_OK
;
136 /* IEnumMediaTypes */
137 static HRESULT WINAPI
138 Single_IEnumMediaTypes_Reset(IEnumMediaTypes
*iface
)
140 ME_Impl
*This
= (ME_Impl
*)iface
;
141 TRACE("(%p)->()\n", This
);
146 /* IEnumMediaTypes */
147 static HRESULT WINAPI
148 Single_IEnumMediaTypes_Clone(IEnumMediaTypes
*iface
, IEnumMediaTypes
**me
)
150 ME_Impl
*This
= (ME_Impl
*)iface
;
151 TRACE("(%p)->(%p)\n", This
, me
);
154 *me
= mediaenum_create(&This
->mtype
);
156 return E_OUTOFMEMORY
;
157 ((ME_Impl
*)*me
)->past
= This
->past
;
162 /* Virtual tables and constructor */
164 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable
=
166 Single_IEnumMediaTypes_QueryInterface
,
167 Single_IEnumMediaTypes_AddRef
,
168 Single_IEnumMediaTypes_Release
,
169 Single_IEnumMediaTypes_Next
,
170 Single_IEnumMediaTypes_Skip
,
171 Single_IEnumMediaTypes_Reset
,
172 Single_IEnumMediaTypes_Clone
,
175 static IEnumMediaTypes
*mediaenum_create(const AM_MEDIA_TYPE
*mtype
)
177 ME_Impl
*obj
= CoTaskMemAlloc(sizeof(ME_Impl
));
179 ZeroMemory(obj
, sizeof(ME_Impl
));
180 obj
->me
.lpVtbl
= &IEnumMediaTypes_VTable
;
185 obj
->mtype
.pUnk
= NULL
;
186 if (mtype
->cbFormat
) {
187 obj
->mtype
.pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
188 CopyMemory(obj
->mtype
.pbFormat
, mtype
->pbFormat
, mtype
->cbFormat
);
191 obj
->mtype
.pbFormat
= NULL
;
194 obj
->mtype
.majortype
= GUID_NULL
;
200 /* Sample Grabber pin implementation */
201 typedef struct _SG_Pin
{
209 static inline SG_Pin
*impl_from_IPin(IPin
*iface
)
211 return CONTAINING_RECORD(iface
, SG_Pin
, IPin_iface
);
214 /* Sample Grabber filter implementation */
215 typedef struct _SG_Impl
{
216 IUnknown IUnknown_inner
;
218 ISampleGrabber ISampleGrabber_iface
;
219 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
220 IUnknown
* seekthru_unk
;
225 IMemInputPin IMemInputPin_iface
;
226 IMemAllocator
*allocator
;
227 IMemInputPin
*memOutput
;
228 ISampleGrabberCB
*grabberIface
;
241 static inline SG_Impl
*impl_from_IUnknown(IUnknown
*iface
)
243 return CONTAINING_RECORD(iface
, SG_Impl
, IUnknown_inner
);
246 static inline SG_Impl
*impl_from_BaseFilter(BaseFilter
*iface
)
248 return CONTAINING_RECORD(iface
, SG_Impl
, filter
);
251 static inline SG_Impl
*impl_from_IBaseFilter(IBaseFilter
*iface
)
253 return CONTAINING_RECORD(iface
, SG_Impl
, filter
.IBaseFilter_iface
);
256 static inline SG_Impl
*impl_from_ISampleGrabber(ISampleGrabber
*iface
)
258 return CONTAINING_RECORD(iface
, SG_Impl
, ISampleGrabber_iface
);
261 static inline SG_Impl
*impl_from_IMemInputPin(IMemInputPin
*iface
)
263 return CONTAINING_RECORD(iface
, SG_Impl
, IMemInputPin_iface
);
267 /* Cleanup at end of life */
268 static void SampleGrabber_cleanup(SG_Impl
*This
)
270 TRACE("(%p)\n", This
);
271 if (This
->filter
.filterInfo
.pGraph
)
272 WARN("(%p) still joined to filter graph %p\n", This
, This
->filter
.filterInfo
.pGraph
);
274 IMemAllocator_Release(This
->allocator
);
276 IMemInputPin_Release(This
->memOutput
);
277 if (This
->grabberIface
)
278 ISampleGrabberCB_Release(This
->grabberIface
);
279 if (This
->mtype
.pbFormat
)
280 CoTaskMemFree(This
->mtype
.pbFormat
);
281 if (This
->bufferData
)
282 CoTaskMemFree(This
->bufferData
);
283 if(This
->seekthru_unk
)
284 IUnknown_Release(This
->seekthru_unk
);
287 /* SampleGrabber inner IUnknown */
288 static HRESULT WINAPI
SampleGrabber_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
290 SG_Impl
*This
= impl_from_IUnknown(iface
);
292 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
295 if (IsEqualIID(riid
, &IID_IUnknown
))
296 *ppv
= &This
->IUnknown_inner
;
297 else if (IsEqualIID(riid
, &IID_IPersist
) || IsEqualIID(riid
, &IID_IMediaFilter
) ||
298 IsEqualIID(riid
, &IID_IBaseFilter
))
299 *ppv
= &This
->filter
.IBaseFilter_iface
;
300 else if (IsEqualIID(riid
, &IID_ISampleGrabber
))
301 *ppv
= &This
->ISampleGrabber_iface
;
302 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
303 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
304 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
305 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
307 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
310 return E_NOINTERFACE
;
312 IUnknown_AddRef((IUnknown
*)*ppv
);
316 static ULONG WINAPI
SampleGrabber_AddRef(IUnknown
*iface
)
318 SG_Impl
*This
= impl_from_IUnknown(iface
);
319 ULONG ref
= BaseFilterImpl_AddRef(&This
->filter
.IBaseFilter_iface
);
321 TRACE("(%p) ref=%d\n", This
, ref
);
326 static ULONG WINAPI
SampleGrabber_Release(IUnknown
*iface
)
328 SG_Impl
*This
= impl_from_IUnknown(iface
);
329 ULONG ref
= BaseFilterImpl_Release(&This
->filter
.IBaseFilter_iface
);
331 TRACE("(%p) ref=%d\n", This
, ref
);
335 SampleGrabber_cleanup(This
);
342 static const IUnknownVtbl samplegrabber_vtbl
=
344 SampleGrabber_QueryInterface
,
345 SampleGrabber_AddRef
,
346 SampleGrabber_Release
,
349 static IPin
*WINAPI
SampleGrabber_GetPin(BaseFilter
*iface
, int pos
)
351 SG_Impl
*This
= impl_from_BaseFilter(iface
);
355 pin
= &This
->pin_in
.IPin_iface
;
357 pin
= &This
->pin_out
.IPin_iface
;
365 static LONG WINAPI
SampleGrabber_GetPinCount(BaseFilter
*iface
)
370 static const BaseFilterFuncTable basefunc_vtbl
= {
371 SampleGrabber_GetPin
,
372 SampleGrabber_GetPinCount
375 /* Helper that buffers data and/or calls installed sample callbacks */
376 static void SampleGrabber_callback(SG_Impl
*This
, IMediaSample
*sample
)
379 REFERENCE_TIME tStart
, tEnd
;
380 if (This
->bufferLen
>= 0) {
382 LONG size
= IMediaSample_GetActualDataLength(sample
);
383 if (size
>= 0 && SUCCEEDED(IMediaSample_GetPointer(sample
, &data
))) {
386 EnterCriticalSection(&This
->filter
.csFilter
);
387 if (This
->bufferLen
!= size
) {
388 if (This
->bufferData
)
389 CoTaskMemFree(This
->bufferData
);
390 This
->bufferData
= size
? CoTaskMemAlloc(size
) : NULL
;
391 This
->bufferLen
= size
;
394 CopyMemory(This
->bufferData
, data
, size
);
395 LeaveCriticalSection(&This
->filter
.csFilter
);
398 if (!This
->grabberIface
)
400 if (SUCCEEDED(IMediaSample_GetTime(sample
, &tStart
, &tEnd
)))
401 time
= 1e-7 * tStart
;
402 switch (This
->grabberMethod
) {
405 ULONG ref
= IMediaSample_AddRef(sample
);
406 ISampleGrabberCB_SampleCB(This
->grabberIface
, time
, sample
);
407 ref
= IMediaSample_Release(sample
) + 1 - ref
;
410 ERR("(%p) Callback referenced sample %p by %u\n", This
, sample
, ref
);
411 /* ugly as hell but some apps are sooo buggy */
413 IMediaSample_Release(sample
);
420 LONG size
= IMediaSample_GetActualDataLength(sample
);
421 if (size
&& SUCCEEDED(IMediaSample_GetPointer(sample
, &data
)) && data
)
422 ISampleGrabberCB_BufferCB(This
->grabberIface
, time
, data
, size
);
428 FIXME("unsupported method %d\n", This
->grabberMethod
);
429 /* do not bother us again */
430 This
->grabberMethod
= -1;
435 /* SampleGrabber implementation of IBaseFilter interface */
438 static HRESULT WINAPI
439 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
441 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
442 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
447 SampleGrabber_IBaseFilter_AddRef(IBaseFilter
*iface
)
449 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
450 return IUnknown_AddRef(This
->outer_unk
);
455 SampleGrabber_IBaseFilter_Release(IBaseFilter
*iface
)
457 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
458 return IUnknown_Release(This
->outer_unk
);
462 static HRESULT WINAPI
463 SampleGrabber_IBaseFilter_Stop(IBaseFilter
*iface
)
465 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
466 TRACE("(%p)\n", This
);
467 This
->filter
.state
= State_Stopped
;
472 static HRESULT WINAPI
473 SampleGrabber_IBaseFilter_Pause(IBaseFilter
*iface
)
475 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
476 TRACE("(%p)\n", This
);
477 This
->filter
.state
= State_Paused
;
482 static HRESULT WINAPI
483 SampleGrabber_IBaseFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
485 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
486 TRACE("(%p)\n", This
);
487 This
->filter
.state
= State_Running
;
492 static HRESULT WINAPI
493 SampleGrabber_IBaseFilter_FindPin(IBaseFilter
*iface
, LPCWSTR id
, IPin
**pin
)
495 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
496 TRACE("(%p)->(%s, %p)\n", This
, debugstr_w(id
), pin
);
499 if (!lstrcmpiW(id
,pin_in_name
))
501 *pin
= &This
->pin_in
.IPin_iface
;
505 else if (!lstrcmpiW(id
,pin_out_name
))
507 *pin
= &This
->pin_out
.IPin_iface
;
512 return VFW_E_NOT_FOUND
;
516 static HRESULT WINAPI
517 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*graph
, LPCWSTR name
)
519 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
521 TRACE("(%p)->(%p, %s)\n", This
, graph
, debugstr_w(name
));
523 BaseFilterImpl_JoinFilterGraph(iface
, graph
, name
);
524 This
->oneShot
= OneShot_None
;
530 static HRESULT WINAPI
531 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter
*iface
, LPWSTR
*vendor
)
533 TRACE("(%p)\n", vendor
);
536 *vendor
= CoTaskMemAlloc(sizeof(vendor_name
));
537 CopyMemory(*vendor
, vendor_name
, sizeof(vendor_name
));
542 /* SampleGrabber implementation of ISampleGrabber interface */
545 static HRESULT WINAPI
546 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber
*iface
, REFIID riid
, void **ppv
)
548 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
549 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
554 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber
*iface
)
556 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
557 return IUnknown_AddRef(This
->outer_unk
);
562 SampleGrabber_ISampleGrabber_Release(ISampleGrabber
*iface
)
564 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
565 return IUnknown_Release(This
->outer_unk
);
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 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
626 TRACE("(%p)->(%u)\n", This
, bufferEm
);
627 EnterCriticalSection(&This
->filter
.csFilter
);
629 if (This
->bufferLen
< 0)
633 This
->bufferLen
= -1;
634 LeaveCriticalSection(&This
->filter
.csFilter
);
639 static HRESULT WINAPI
640 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber
*iface
, LONG
*bufSize
, LONG
*buffer
)
642 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
644 TRACE("(%p)->(%p, %p)\n", This
, bufSize
, buffer
);
647 EnterCriticalSection(&This
->filter
.csFilter
);
648 if (!This
->pin_in
.pair
)
649 ret
= VFW_E_NOT_CONNECTED
;
650 else if (This
->bufferLen
< 0)
652 else if (This
->bufferLen
== 0)
653 ret
= VFW_E_WRONG_STATE
;
656 if (*bufSize
>= This
->bufferLen
)
657 CopyMemory(buffer
, This
->bufferData
, This
->bufferLen
);
661 *bufSize
= This
->bufferLen
;
663 LeaveCriticalSection(&This
->filter
.csFilter
);
668 static HRESULT WINAPI
669 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber
*iface
, IMediaSample
**sample
)
671 /* MS doesn't implement it either, no one should call it */
672 WARN("(%p): not implemented\n", sample
);
677 static HRESULT WINAPI
678 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber
*iface
, ISampleGrabberCB
*cb
, LONG whichMethod
)
680 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
681 TRACE("(%p)->(%p, %u)\n", This
, cb
, whichMethod
);
682 if (This
->grabberIface
)
683 ISampleGrabberCB_Release(This
->grabberIface
);
684 This
->grabberIface
= cb
;
685 This
->grabberMethod
= whichMethod
;
687 ISampleGrabberCB_AddRef(cb
);
692 /* SampleGrabber implementation of IMemInputPin interface */
695 static HRESULT WINAPI
696 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin
*iface
, REFIID riid
, void **ppv
)
698 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
699 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
704 SampleGrabber_IMemInputPin_AddRef(IMemInputPin
*iface
)
706 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
707 return IUnknown_AddRef(This
->outer_unk
);
712 SampleGrabber_IMemInputPin_Release(IMemInputPin
*iface
)
714 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
715 return IUnknown_Release(This
->outer_unk
);
719 static HRESULT WINAPI
720 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin
*iface
, IMemAllocator
**allocator
)
722 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
723 TRACE("(%p)->(%p) allocator = %p\n", This
, allocator
, This
->allocator
);
726 *allocator
= This
->allocator
;
728 return VFW_E_NO_ALLOCATOR
;
729 IMemAllocator_AddRef(*allocator
);
734 static HRESULT WINAPI
735 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin
*iface
, IMemAllocator
*allocator
, BOOL readOnly
)
737 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
738 TRACE("(%p)->(%p, %u) allocator = %p\n", This
, allocator
, readOnly
, This
->allocator
);
739 if (This
->allocator
== allocator
)
742 IMemAllocator_Release(This
->allocator
);
743 This
->allocator
= allocator
;
745 IMemAllocator_AddRef(allocator
);
750 static HRESULT WINAPI
751 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
753 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
754 FIXME("(%p)->(%p): semi-stub\n", This
, props
);
757 return This
->memOutput
? IMemInputPin_GetAllocatorRequirements(This
->memOutput
, props
) : E_NOTIMPL
;
761 static HRESULT WINAPI
762 SampleGrabber_IMemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*sample
)
764 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
766 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This
, sample
, This
->memOutput
, This
->grabberIface
);
769 if ((This
->filter
.state
!= State_Running
) || (This
->oneShot
== OneShot_Past
))
771 SampleGrabber_callback(This
, sample
);
772 hr
= This
->memOutput
? IMemInputPin_Receive(This
->memOutput
, sample
) : S_OK
;
773 if (This
->oneShot
== OneShot_Wait
) {
774 This
->oneShot
= OneShot_Past
;
776 if (This
->pin_out
.pair
)
777 IPin_EndOfStream(This
->pin_out
.pair
);
783 static HRESULT WINAPI
784 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin
*iface
, IMediaSample
**samples
, LONG nSamples
, LONG
*nProcessed
)
786 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
788 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This
, samples
, nSamples
, nProcessed
, This
->memOutput
, This
->grabberIface
);
789 if (!samples
|| !nProcessed
)
791 if ((This
->filter
.state
!= State_Running
) || (This
->oneShot
== OneShot_Past
))
793 for (idx
= 0; idx
< nSamples
; idx
++)
794 SampleGrabber_callback(This
, samples
[idx
]);
795 return This
->memOutput
? IMemInputPin_ReceiveMultiple(This
->memOutput
, samples
, nSamples
, nProcessed
) : S_OK
;
799 static HRESULT WINAPI
800 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
802 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
803 TRACE("(%p)\n", This
);
804 return This
->memOutput
? IMemInputPin_ReceiveCanBlock(This
->memOutput
) : S_OK
;
808 /* SampleGrabber member pin implementation */
812 SampleGrabber_IPin_AddRef(IPin
*iface
)
814 SG_Pin
*This
= impl_from_IPin(iface
);
815 return ISampleGrabber_AddRef(&This
->sg
->ISampleGrabber_iface
);
820 SampleGrabber_IPin_Release(IPin
*iface
)
822 SG_Pin
*This
= impl_from_IPin(iface
);
823 return ISampleGrabber_Release(&This
->sg
->ISampleGrabber_iface
);
827 static HRESULT WINAPI
828 SampleGrabber_IPin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
830 SG_Pin
*This
= impl_from_IPin(iface
);
831 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
834 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPin
))
836 else if (IsEqualIID(riid
, &IID_IMemInputPin
))
837 *ppv
= &This
->sg
->IMemInputPin_iface
;
838 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
839 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
840 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
841 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
843 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
844 return E_NOINTERFACE
;
847 IUnknown_AddRef((IUnknown
*)*ppv
);
851 /* IPin - input pin */
852 static HRESULT WINAPI
853 SampleGrabber_In_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*mtype
)
855 WARN("(%p, %p): unexpected\n", receiver
, mtype
);
859 /* IPin - output pin */
860 static HRESULT WINAPI
861 SampleGrabber_Out_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*type
)
863 SG_Pin
*This
= impl_from_IPin(iface
);
866 TRACE("(%p)->(%p, %p)\n", This
, receiver
, type
);
870 return VFW_E_ALREADY_CONNECTED
;
871 if (This
->sg
->filter
.state
!= State_Stopped
)
872 return VFW_E_NOT_STOPPED
;
874 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
875 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
877 debugstr_guid(&type
->formattype
), type
->cbFormat
);
878 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
879 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
880 return VFW_E_TYPE_NOT_ACCEPTED
;
881 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
882 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
883 return VFW_E_TYPE_NOT_ACCEPTED
;
884 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
885 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
886 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
887 return VFW_E_TYPE_NOT_ACCEPTED
;
890 type
= &This
->sg
->mtype
;
891 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
892 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
894 return VFW_E_TYPE_NOT_ACCEPTED
;
895 hr
= IPin_ReceiveConnection(receiver
, &This
->IPin_iface
, type
);
898 This
->pair
= receiver
;
899 if (This
->sg
->memOutput
) {
900 IMemInputPin_Release(This
->sg
->memOutput
);
901 This
->sg
->memOutput
= NULL
;
903 IPin_QueryInterface(receiver
,&IID_IMemInputPin
,(void **)&(This
->sg
->memOutput
));
904 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This
, receiver
, This
->sg
->memOutput
);
908 /* IPin - input pin */
909 static HRESULT WINAPI
910 SampleGrabber_In_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*type
)
912 SG_Pin
*This
= impl_from_IPin(iface
);
914 TRACE("(%p)->(%p, %p)\n", This
, connector
, type
);
918 return VFW_E_ALREADY_CONNECTED
;
919 if (This
->sg
->filter
.state
!= State_Stopped
)
920 return VFW_E_NOT_STOPPED
;
922 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
923 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
925 debugstr_guid(&type
->formattype
), type
->cbFormat
);
926 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
927 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
929 return VFW_E_INVALIDMEDIATYPE
;
930 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
931 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
932 return VFW_E_TYPE_NOT_ACCEPTED
;
933 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
934 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
935 return VFW_E_TYPE_NOT_ACCEPTED
;
936 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
937 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
938 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
939 return VFW_E_TYPE_NOT_ACCEPTED
;
940 if (This
->sg
->mtype
.pbFormat
)
941 CoTaskMemFree(This
->sg
->mtype
.pbFormat
);
942 This
->sg
->mtype
= *type
;
943 This
->sg
->mtype
.pUnk
= NULL
;
944 if (type
->cbFormat
) {
945 This
->sg
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
946 CopyMemory(This
->sg
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
949 This
->sg
->mtype
.pbFormat
= NULL
;
951 This
->pair
= connector
;
952 TRACE("(%p) Accepted IPin %p\n", This
, connector
);
956 /* IPin - output pin */
957 static HRESULT WINAPI
958 SampleGrabber_Out_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*mtype
)
960 WARN("(%p, %p): unexpected\n", connector
, mtype
);
964 /* IPin - input pin */
965 static HRESULT WINAPI
966 SampleGrabber_In_IPin_Disconnect(IPin
*iface
)
968 SG_Pin
*This
= impl_from_IPin(iface
);
970 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
971 if (This
->sg
->filter
.state
!= State_Stopped
)
972 return VFW_E_NOT_STOPPED
;
980 /* IPin - output pin */
981 static HRESULT WINAPI
982 SampleGrabber_Out_IPin_Disconnect(IPin
*iface
)
984 SG_Pin
*This
= impl_from_IPin(iface
);
986 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
987 if (This
->sg
->filter
.state
!= State_Stopped
)
988 return VFW_E_NOT_STOPPED
;
991 if (This
->sg
->memOutput
) {
992 IMemInputPin_Release(This
->sg
->memOutput
);
993 This
->sg
->memOutput
= NULL
;
1001 static HRESULT WINAPI
1002 SampleGrabber_IPin_ConnectedTo(IPin
*iface
, IPin
**pin
)
1004 SG_Pin
*This
= impl_from_IPin(iface
);
1006 TRACE("(%p)->(%p) pair = %p\n", This
, pin
, This
->pair
);
1014 return VFW_E_NOT_CONNECTED
;
1018 static HRESULT WINAPI
1019 SampleGrabber_IPin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*mtype
)
1021 SG_Pin
*This
= impl_from_IPin(iface
);
1023 TRACE("(%p)->(%p)\n", This
, mtype
);
1027 return VFW_E_NOT_CONNECTED
;
1028 *mtype
= This
->sg
->mtype
;
1029 if (mtype
->cbFormat
) {
1030 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
1031 CopyMemory(mtype
->pbFormat
, This
->sg
->mtype
.pbFormat
, mtype
->cbFormat
);
1037 static HRESULT WINAPI
1038 SampleGrabber_IPin_QueryPinInfo(IPin
*iface
, PIN_INFO
*info
)
1040 SG_Pin
*This
= impl_from_IPin(iface
);
1042 TRACE("(%p)->(%p)\n", This
, info
);
1045 info
->pFilter
= &This
->sg
->filter
.IBaseFilter_iface
;
1046 IBaseFilter_AddRef(info
->pFilter
);
1047 info
->dir
= This
->dir
;
1048 lstrcpynW(info
->achName
,This
->name
,MAX_PIN_NAME
);
1053 static HRESULT WINAPI
1054 SampleGrabber_IPin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*dir
)
1056 SG_Pin
*This
= impl_from_IPin(iface
);
1058 TRACE("(%p)->(%p)\n", This
, dir
);
1066 static HRESULT WINAPI
1067 SampleGrabber_IPin_QueryId(IPin
*iface
, LPWSTR
*id
)
1069 SG_Pin
*This
= impl_from_IPin(iface
);
1072 TRACE("(%p)->(%p)\n", This
, id
);
1075 len
= sizeof(WCHAR
)*(1+lstrlenW(This
->name
));
1076 *id
= CoTaskMemAlloc(len
);
1077 CopyMemory(*id
, This
->name
, len
);
1082 static HRESULT WINAPI
1083 SampleGrabber_IPin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mtype
)
1085 TRACE("(%p)\n", mtype
);
1090 static HRESULT WINAPI
1091 SampleGrabber_IPin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**mtypes
)
1093 SG_Pin
*This
= impl_from_IPin(iface
);
1095 TRACE("(%p)->(%p)\n", This
, mtypes
);
1098 *mtypes
= mediaenum_create(This
->sg
->pin_in
.pair
? &This
->sg
->mtype
: NULL
);
1099 return *mtypes
? S_OK
: E_OUTOFMEMORY
;
1102 /* IPin - input pin */
1103 static HRESULT WINAPI
1104 SampleGrabber_In_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1106 SG_Pin
*This
= impl_from_IPin(iface
);
1108 TRACE("(%p)->(%p, %p) size = %u\n", This
, pins
, nPins
, (nPins
? *nPins
: 0));
1114 IPin_AddRef(&This
->sg
->pin_out
.IPin_iface
);
1115 *pins
= &This
->sg
->pin_out
.IPin_iface
;
1123 /* IPin - output pin */
1124 static HRESULT WINAPI
1125 SampleGrabber_Out_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1127 WARN("(%p, %p): unexpected\n", pins
, nPins
);
1134 static HRESULT WINAPI
1135 SampleGrabber_IPin_EndOfStream(IPin
*iface
)
1142 static HRESULT WINAPI
1143 SampleGrabber_IPin_BeginFlush(IPin
*iface
)
1150 static HRESULT WINAPI
1151 SampleGrabber_IPin_EndFlush(IPin
*iface
)
1158 static HRESULT WINAPI
1159 SampleGrabber_IPin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double rate
)
1166 /* SampleGrabber vtables and constructor */
1168 static const IBaseFilterVtbl IBaseFilter_VTable
=
1170 SampleGrabber_IBaseFilter_QueryInterface
,
1171 SampleGrabber_IBaseFilter_AddRef
,
1172 SampleGrabber_IBaseFilter_Release
,
1173 BaseFilterImpl_GetClassID
,
1174 SampleGrabber_IBaseFilter_Stop
,
1175 SampleGrabber_IBaseFilter_Pause
,
1176 SampleGrabber_IBaseFilter_Run
,
1177 BaseFilterImpl_GetState
,
1178 BaseFilterImpl_SetSyncSource
,
1179 BaseFilterImpl_GetSyncSource
,
1180 BaseFilterImpl_EnumPins
,
1181 SampleGrabber_IBaseFilter_FindPin
,
1182 BaseFilterImpl_QueryFilterInfo
,
1183 SampleGrabber_IBaseFilter_JoinFilterGraph
,
1184 SampleGrabber_IBaseFilter_QueryVendorInfo
,
1187 static const ISampleGrabberVtbl ISampleGrabber_VTable
=
1189 SampleGrabber_ISampleGrabber_QueryInterface
,
1190 SampleGrabber_ISampleGrabber_AddRef
,
1191 SampleGrabber_ISampleGrabber_Release
,
1192 SampleGrabber_ISampleGrabber_SetOneShot
,
1193 SampleGrabber_ISampleGrabber_SetMediaType
,
1194 SampleGrabber_ISampleGrabber_GetConnectedMediaType
,
1195 SampleGrabber_ISampleGrabber_SetBufferSamples
,
1196 SampleGrabber_ISampleGrabber_GetCurrentBuffer
,
1197 SampleGrabber_ISampleGrabber_GetCurrentSample
,
1198 SampleGrabber_ISampleGrabber_SetCallback
,
1201 static const IMemInputPinVtbl IMemInputPin_VTable
=
1203 SampleGrabber_IMemInputPin_QueryInterface
,
1204 SampleGrabber_IMemInputPin_AddRef
,
1205 SampleGrabber_IMemInputPin_Release
,
1206 SampleGrabber_IMemInputPin_GetAllocator
,
1207 SampleGrabber_IMemInputPin_NotifyAllocator
,
1208 SampleGrabber_IMemInputPin_GetAllocatorRequirements
,
1209 SampleGrabber_IMemInputPin_Receive
,
1210 SampleGrabber_IMemInputPin_ReceiveMultiple
,
1211 SampleGrabber_IMemInputPin_ReceiveCanBlock
,
1214 static const IPinVtbl IPin_In_VTable
=
1216 SampleGrabber_IPin_QueryInterface
,
1217 SampleGrabber_IPin_AddRef
,
1218 SampleGrabber_IPin_Release
,
1219 SampleGrabber_In_IPin_Connect
,
1220 SampleGrabber_In_IPin_ReceiveConnection
,
1221 SampleGrabber_In_IPin_Disconnect
,
1222 SampleGrabber_IPin_ConnectedTo
,
1223 SampleGrabber_IPin_ConnectionMediaType
,
1224 SampleGrabber_IPin_QueryPinInfo
,
1225 SampleGrabber_IPin_QueryDirection
,
1226 SampleGrabber_IPin_QueryId
,
1227 SampleGrabber_IPin_QueryAccept
,
1228 SampleGrabber_IPin_EnumMediaTypes
,
1229 SampleGrabber_In_IPin_QueryInternalConnections
,
1230 SampleGrabber_IPin_EndOfStream
,
1231 SampleGrabber_IPin_BeginFlush
,
1232 SampleGrabber_IPin_EndFlush
,
1233 SampleGrabber_IPin_NewSegment
,
1236 static const IPinVtbl IPin_Out_VTable
=
1238 SampleGrabber_IPin_QueryInterface
,
1239 SampleGrabber_IPin_AddRef
,
1240 SampleGrabber_IPin_Release
,
1241 SampleGrabber_Out_IPin_Connect
,
1242 SampleGrabber_Out_IPin_ReceiveConnection
,
1243 SampleGrabber_Out_IPin_Disconnect
,
1244 SampleGrabber_IPin_ConnectedTo
,
1245 SampleGrabber_IPin_ConnectionMediaType
,
1246 SampleGrabber_IPin_QueryPinInfo
,
1247 SampleGrabber_IPin_QueryDirection
,
1248 SampleGrabber_IPin_QueryId
,
1249 SampleGrabber_IPin_QueryAccept
,
1250 SampleGrabber_IPin_EnumMediaTypes
,
1251 SampleGrabber_Out_IPin_QueryInternalConnections
,
1252 SampleGrabber_IPin_EndOfStream
,
1253 SampleGrabber_IPin_BeginFlush
,
1254 SampleGrabber_IPin_EndFlush
,
1255 SampleGrabber_IPin_NewSegment
,
1258 HRESULT
SampleGrabber_create(IUnknown
*pUnkOuter
, LPVOID
*ppv
)
1260 SG_Impl
* obj
= NULL
;
1261 ISeekingPassThru
*passthru
;
1264 TRACE("(%p,%p)\n", ppv
, pUnkOuter
);
1266 obj
= CoTaskMemAlloc(sizeof(SG_Impl
));
1269 return E_OUTOFMEMORY
;
1271 ZeroMemory(obj
, sizeof(SG_Impl
));
1273 BaseFilter_Init(&obj
->filter
, &IBaseFilter_VTable
, &CLSID_SampleGrabber
,
1274 (DWORD_PTR
)(__FILE__
": SG_Impl.csFilter"), &basefunc_vtbl
);
1275 obj
->IUnknown_inner
.lpVtbl
= &samplegrabber_vtbl
;
1276 obj
->ISampleGrabber_iface
.lpVtbl
= &ISampleGrabber_VTable
;
1277 obj
->IMemInputPin_iface
.lpVtbl
= &IMemInputPin_VTable
;
1278 obj
->pin_in
.IPin_iface
.lpVtbl
= &IPin_In_VTable
;
1279 obj
->pin_in
.dir
= PINDIR_INPUT
;
1280 obj
->pin_in
.name
= pin_in_name
;
1281 obj
->pin_in
.sg
= obj
;
1282 obj
->pin_in
.pair
= NULL
;
1283 obj
->pin_out
.IPin_iface
.lpVtbl
= &IPin_Out_VTable
;
1284 obj
->pin_out
.dir
= PINDIR_OUTPUT
;
1285 obj
->pin_out
.name
= pin_out_name
;
1286 obj
->pin_out
.sg
= obj
;
1287 obj
->pin_out
.pair
= NULL
;
1288 obj
->mtype
.majortype
= GUID_NULL
;
1289 obj
->mtype
.subtype
= MEDIASUBTYPE_None
;
1290 obj
->mtype
.formattype
= FORMAT_None
;
1291 obj
->allocator
= NULL
;
1292 obj
->memOutput
= NULL
;
1293 obj
->grabberIface
= NULL
;
1294 obj
->grabberMethod
= -1;
1295 obj
->oneShot
= OneShot_None
;
1296 obj
->bufferLen
= -1;
1297 obj
->bufferData
= NULL
;
1300 obj
->outer_unk
= pUnkOuter
;
1302 obj
->outer_unk
= &obj
->IUnknown_inner
;
1304 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)obj
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&obj
->seekthru_unk
);
1307 IUnknown_QueryInterface(obj
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
1308 ISeekingPassThru_Init(passthru
, FALSE
, &obj
->pin_in
.IPin_iface
);
1309 ISeekingPassThru_Release(passthru
);
1311 *ppv
= &obj
->IUnknown_inner
;