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
20 #include "qedit_private.h"
22 #include <wine/strmbase.h>
24 static const WCHAR vendor_name
[] = { 'W', 'i', 'n', 'e', 0 };
25 static const WCHAR pin_in_name
[] = { 'I', 'n', 0 };
26 static const WCHAR pin_out_name
[] = { 'O', 'u', 't', 0 };
28 static IEnumMediaTypes
*mediaenum_create(const AM_MEDIA_TYPE
*mtype
);
30 /* Single media type enumerator */
31 typedef struct _ME_Impl
{
39 /* IEnumMediaTypes interface implementation */
43 Single_IEnumMediaTypes_AddRef(IEnumMediaTypes
*iface
)
45 ME_Impl
*This
= (ME_Impl
*)iface
;
46 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
47 TRACE("(%p) new ref = %u\n", This
, refCount
);
53 Single_IEnumMediaTypes_Release(IEnumMediaTypes
*iface
)
55 ME_Impl
*This
= (ME_Impl
*)iface
;
56 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
57 TRACE("(%p) new ref = %u\n", This
, refCount
);
60 if (This
->mtype
.pbFormat
)
61 CoTaskMemFree(This
->mtype
.pbFormat
);
70 Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes
*iface
, REFIID riid
, void **ppvObject
)
72 ME_Impl
*This
= (ME_Impl
*)iface
;
73 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppvObject
);
75 if (IsEqualIID(riid
, &IID_IUnknown
) ||
76 IsEqualIID(riid
, &IID_IEnumMediaTypes
)) {
77 Single_IEnumMediaTypes_AddRef(iface
);
78 *ppvObject
= &(This
->me
);
82 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppvObject
);
88 Single_IEnumMediaTypes_Next(IEnumMediaTypes
*iface
, ULONG nTypes
, AM_MEDIA_TYPE
**types
, ULONG
*fetched
)
90 ME_Impl
*This
= (ME_Impl
*)iface
;
92 TRACE("(%p)->(%u, %p, %p)\n", This
, nTypes
, types
, fetched
);
95 if (!types
|| ((nTypes
!= 1) && !fetched
))
97 if (!This
->past
&& !IsEqualGUID(&This
->mtype
.majortype
,&GUID_NULL
)) {
98 AM_MEDIA_TYPE
*mtype
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
100 if (mtype
->cbFormat
) {
101 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
102 CopyMemory(mtype
->pbFormat
, This
->mtype
.pbFormat
, mtype
->cbFormat
);
110 return (count
== nTypes
) ? S_OK
: S_FALSE
;
113 /* IEnumMediaTypes */
114 static HRESULT WINAPI
115 Single_IEnumMediaTypes_Skip(IEnumMediaTypes
*iface
, ULONG nTypes
)
117 ME_Impl
*This
= (ME_Impl
*)iface
;
118 TRACE("(%p)->(%u)\n", This
, nTypes
);
121 return This
->past
? S_FALSE
: S_OK
;
124 /* IEnumMediaTypes */
125 static HRESULT WINAPI
126 Single_IEnumMediaTypes_Reset(IEnumMediaTypes
*iface
)
128 ME_Impl
*This
= (ME_Impl
*)iface
;
129 TRACE("(%p)->()\n", This
);
134 /* IEnumMediaTypes */
135 static HRESULT WINAPI
136 Single_IEnumMediaTypes_Clone(IEnumMediaTypes
*iface
, IEnumMediaTypes
**me
)
138 ME_Impl
*This
= (ME_Impl
*)iface
;
139 TRACE("(%p)->(%p)\n", This
, me
);
142 *me
= mediaenum_create(&This
->mtype
);
144 return E_OUTOFMEMORY
;
145 ((ME_Impl
*)*me
)->past
= This
->past
;
150 /* Virtual tables and constructor */
152 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable
=
154 Single_IEnumMediaTypes_QueryInterface
,
155 Single_IEnumMediaTypes_AddRef
,
156 Single_IEnumMediaTypes_Release
,
157 Single_IEnumMediaTypes_Next
,
158 Single_IEnumMediaTypes_Skip
,
159 Single_IEnumMediaTypes_Reset
,
160 Single_IEnumMediaTypes_Clone
,
163 static IEnumMediaTypes
*mediaenum_create(const AM_MEDIA_TYPE
*mtype
)
165 ME_Impl
*obj
= CoTaskMemAlloc(sizeof(ME_Impl
));
167 ZeroMemory(obj
, sizeof(ME_Impl
));
168 obj
->me
.lpVtbl
= &IEnumMediaTypes_VTable
;
173 obj
->mtype
.pUnk
= NULL
;
174 if (mtype
->cbFormat
) {
175 obj
->mtype
.pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
176 CopyMemory(obj
->mtype
.pbFormat
, mtype
->pbFormat
, mtype
->cbFormat
);
179 obj
->mtype
.pbFormat
= NULL
;
182 obj
->mtype
.majortype
= GUID_NULL
;
188 /* Sample Grabber pin implementation */
189 typedef struct _SG_Pin
{
197 static inline SG_Pin
*impl_from_IPin(IPin
*iface
)
199 return CONTAINING_RECORD(iface
, SG_Pin
, IPin_iface
);
202 /* Sample Grabber filter implementation */
203 typedef struct _SG_Impl
{
204 IUnknown IUnknown_inner
;
206 ISampleGrabber ISampleGrabber_iface
;
207 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
208 IUnknown
* seekthru_unk
;
213 IMemInputPin IMemInputPin_iface
;
214 IMemAllocator
*allocator
;
215 IMemInputPin
*memOutput
;
216 ISampleGrabberCB
*grabberIface
;
229 static inline SG_Impl
*impl_from_IUnknown(IUnknown
*iface
)
231 return CONTAINING_RECORD(iface
, SG_Impl
, IUnknown_inner
);
234 static inline SG_Impl
*impl_from_BaseFilter(BaseFilter
*iface
)
236 return CONTAINING_RECORD(iface
, SG_Impl
, filter
);
239 static inline SG_Impl
*impl_from_IBaseFilter(IBaseFilter
*iface
)
241 return CONTAINING_RECORD(iface
, SG_Impl
, filter
.IBaseFilter_iface
);
244 static inline SG_Impl
*impl_from_ISampleGrabber(ISampleGrabber
*iface
)
246 return CONTAINING_RECORD(iface
, SG_Impl
, ISampleGrabber_iface
);
249 static inline SG_Impl
*impl_from_IMemInputPin(IMemInputPin
*iface
)
251 return CONTAINING_RECORD(iface
, SG_Impl
, IMemInputPin_iface
);
255 /* Cleanup at end of life */
256 static void SampleGrabber_cleanup(SG_Impl
*This
)
258 TRACE("(%p)\n", This
);
259 if (This
->filter
.filterInfo
.pGraph
)
260 WARN("(%p) still joined to filter graph %p\n", This
, This
->filter
.filterInfo
.pGraph
);
262 IMemAllocator_Release(This
->allocator
);
264 IMemInputPin_Release(This
->memOutput
);
265 if (This
->grabberIface
)
266 ISampleGrabberCB_Release(This
->grabberIface
);
267 if (This
->mtype
.pbFormat
)
268 CoTaskMemFree(This
->mtype
.pbFormat
);
269 if (This
->bufferData
)
270 CoTaskMemFree(This
->bufferData
);
271 if(This
->seekthru_unk
)
272 IUnknown_Release(This
->seekthru_unk
);
275 /* SampleGrabber inner IUnknown */
276 static HRESULT WINAPI
SampleGrabber_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
278 SG_Impl
*This
= impl_from_IUnknown(iface
);
280 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
283 if (IsEqualIID(riid
, &IID_IUnknown
))
284 *ppv
= &This
->IUnknown_inner
;
285 else if (IsEqualIID(riid
, &IID_IPersist
) || IsEqualIID(riid
, &IID_IMediaFilter
) ||
286 IsEqualIID(riid
, &IID_IBaseFilter
))
287 *ppv
= &This
->filter
.IBaseFilter_iface
;
288 else if (IsEqualIID(riid
, &IID_ISampleGrabber
))
289 *ppv
= &This
->ISampleGrabber_iface
;
290 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
291 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
292 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
293 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
295 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
298 return E_NOINTERFACE
;
300 IUnknown_AddRef((IUnknown
*)*ppv
);
304 static ULONG WINAPI
SampleGrabber_AddRef(IUnknown
*iface
)
306 SG_Impl
*This
= impl_from_IUnknown(iface
);
307 ULONG ref
= BaseFilterImpl_AddRef(&This
->filter
.IBaseFilter_iface
);
309 TRACE("(%p) ref=%d\n", This
, ref
);
314 static ULONG WINAPI
SampleGrabber_Release(IUnknown
*iface
)
316 SG_Impl
*This
= impl_from_IUnknown(iface
);
317 ULONG ref
= BaseFilterImpl_Release(&This
->filter
.IBaseFilter_iface
);
319 TRACE("(%p) ref=%d\n", This
, ref
);
323 SampleGrabber_cleanup(This
);
330 static const IUnknownVtbl samplegrabber_vtbl
=
332 SampleGrabber_QueryInterface
,
333 SampleGrabber_AddRef
,
334 SampleGrabber_Release
,
337 static IPin
*WINAPI
SampleGrabber_GetPin(BaseFilter
*iface
, int pos
)
339 SG_Impl
*This
= impl_from_BaseFilter(iface
);
343 pin
= &This
->pin_in
.IPin_iface
;
345 pin
= &This
->pin_out
.IPin_iface
;
353 static LONG WINAPI
SampleGrabber_GetPinCount(BaseFilter
*iface
)
358 static const BaseFilterFuncTable basefunc_vtbl
= {
359 SampleGrabber_GetPin
,
360 SampleGrabber_GetPinCount
363 /* Helper that buffers data and/or calls installed sample callbacks */
364 static void SampleGrabber_callback(SG_Impl
*This
, IMediaSample
*sample
)
367 REFERENCE_TIME tStart
, tEnd
;
368 if (This
->bufferLen
>= 0) {
370 LONG size
= IMediaSample_GetActualDataLength(sample
);
371 if (size
>= 0 && SUCCEEDED(IMediaSample_GetPointer(sample
, &data
))) {
374 EnterCriticalSection(&This
->filter
.csFilter
);
375 if (This
->bufferLen
!= size
) {
376 if (This
->bufferData
)
377 CoTaskMemFree(This
->bufferData
);
378 This
->bufferData
= size
? CoTaskMemAlloc(size
) : NULL
;
379 This
->bufferLen
= size
;
382 CopyMemory(This
->bufferData
, data
, size
);
383 LeaveCriticalSection(&This
->filter
.csFilter
);
386 if (!This
->grabberIface
)
388 if (SUCCEEDED(IMediaSample_GetTime(sample
, &tStart
, &tEnd
)))
389 time
= 1e-7 * tStart
;
390 switch (This
->grabberMethod
) {
393 ULONG ref
= IMediaSample_AddRef(sample
);
394 ISampleGrabberCB_SampleCB(This
->grabberIface
, time
, sample
);
395 ref
= IMediaSample_Release(sample
) + 1 - ref
;
398 ERR("(%p) Callback referenced sample %p by %u\n", This
, sample
, ref
);
399 /* ugly as hell but some apps are sooo buggy */
401 IMediaSample_Release(sample
);
408 LONG size
= IMediaSample_GetActualDataLength(sample
);
409 if (size
&& SUCCEEDED(IMediaSample_GetPointer(sample
, &data
)) && data
)
410 ISampleGrabberCB_BufferCB(This
->grabberIface
, time
, data
, size
);
416 FIXME("unsupported method %d\n", This
->grabberMethod
);
417 /* do not bother us again */
418 This
->grabberMethod
= -1;
423 /* SampleGrabber implementation of IBaseFilter interface */
426 static HRESULT WINAPI
427 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
429 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
430 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
435 SampleGrabber_IBaseFilter_AddRef(IBaseFilter
*iface
)
437 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
438 return IUnknown_AddRef(This
->outer_unk
);
443 SampleGrabber_IBaseFilter_Release(IBaseFilter
*iface
)
445 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
446 return IUnknown_Release(This
->outer_unk
);
450 static HRESULT WINAPI
451 SampleGrabber_IBaseFilter_Stop(IBaseFilter
*iface
)
453 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
454 TRACE("(%p)\n", This
);
455 This
->filter
.state
= State_Stopped
;
460 static HRESULT WINAPI
461 SampleGrabber_IBaseFilter_Pause(IBaseFilter
*iface
)
463 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
464 TRACE("(%p)\n", This
);
465 This
->filter
.state
= State_Paused
;
470 static HRESULT WINAPI
471 SampleGrabber_IBaseFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
473 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
474 TRACE("(%p)\n", This
);
475 This
->filter
.state
= State_Running
;
480 static HRESULT WINAPI
481 SampleGrabber_IBaseFilter_FindPin(IBaseFilter
*iface
, LPCWSTR id
, IPin
**pin
)
483 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
484 TRACE("(%p)->(%s, %p)\n", This
, debugstr_w(id
), pin
);
487 if (!lstrcmpiW(id
,pin_in_name
))
489 *pin
= &This
->pin_in
.IPin_iface
;
493 else if (!lstrcmpiW(id
,pin_out_name
))
495 *pin
= &This
->pin_out
.IPin_iface
;
500 return VFW_E_NOT_FOUND
;
504 static HRESULT WINAPI
505 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*graph
, LPCWSTR name
)
507 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
509 TRACE("(%p)->(%p, %s)\n", This
, graph
, debugstr_w(name
));
511 BaseFilterImpl_JoinFilterGraph(iface
, graph
, name
);
512 This
->oneShot
= OneShot_None
;
518 static HRESULT WINAPI
519 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter
*iface
, LPWSTR
*vendor
)
521 TRACE("(%p)\n", vendor
);
524 *vendor
= CoTaskMemAlloc(sizeof(vendor_name
));
525 CopyMemory(*vendor
, vendor_name
, sizeof(vendor_name
));
530 /* SampleGrabber implementation of ISampleGrabber interface */
533 static HRESULT WINAPI
534 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber
*iface
, REFIID riid
, void **ppv
)
536 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
537 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
542 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber
*iface
)
544 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
545 return IUnknown_AddRef(This
->outer_unk
);
550 SampleGrabber_ISampleGrabber_Release(ISampleGrabber
*iface
)
552 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
553 return IUnknown_Release(This
->outer_unk
);
557 static HRESULT WINAPI
558 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber
*iface
, BOOL oneShot
)
560 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
561 TRACE("(%p)->(%u)\n", This
, oneShot
);
562 This
->oneShot
= oneShot
? OneShot_Wait
: OneShot_None
;
567 static HRESULT WINAPI
568 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber
*iface
, const AM_MEDIA_TYPE
*type
)
570 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
571 TRACE("(%p)->(%p)\n", This
, type
);
574 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
575 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
577 debugstr_guid(&type
->formattype
), type
->cbFormat
);
578 if (This
->mtype
.pbFormat
)
579 CoTaskMemFree(This
->mtype
.pbFormat
);
581 This
->mtype
.pUnk
= NULL
;
582 if (type
->cbFormat
) {
583 This
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
584 CopyMemory(This
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
587 This
->mtype
.pbFormat
= NULL
;
592 static HRESULT WINAPI
593 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber
*iface
, AM_MEDIA_TYPE
*type
)
595 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
596 TRACE("(%p)->(%p)\n", This
, type
);
599 if (!This
->pin_in
.pair
)
600 return VFW_E_NOT_CONNECTED
;
602 if (type
->cbFormat
) {
603 type
->pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
604 CopyMemory(type
->pbFormat
, This
->mtype
.pbFormat
, type
->cbFormat
);
610 static HRESULT WINAPI
611 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber
*iface
, BOOL bufferEm
)
613 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
614 TRACE("(%p)->(%u)\n", This
, bufferEm
);
615 EnterCriticalSection(&This
->filter
.csFilter
);
617 if (This
->bufferLen
< 0)
621 This
->bufferLen
= -1;
622 LeaveCriticalSection(&This
->filter
.csFilter
);
627 static HRESULT WINAPI
628 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber
*iface
, LONG
*bufSize
, LONG
*buffer
)
630 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
632 TRACE("(%p)->(%p, %p)\n", This
, bufSize
, buffer
);
635 EnterCriticalSection(&This
->filter
.csFilter
);
636 if (!This
->pin_in
.pair
)
637 ret
= VFW_E_NOT_CONNECTED
;
638 else if (This
->bufferLen
< 0)
640 else if (This
->bufferLen
== 0)
641 ret
= VFW_E_WRONG_STATE
;
644 if (*bufSize
>= This
->bufferLen
)
645 CopyMemory(buffer
, This
->bufferData
, This
->bufferLen
);
649 *bufSize
= This
->bufferLen
;
651 LeaveCriticalSection(&This
->filter
.csFilter
);
656 static HRESULT WINAPI
657 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber
*iface
, IMediaSample
**sample
)
659 /* MS doesn't implement it either, no one should call it */
660 WARN("(%p): not implemented\n", sample
);
665 static HRESULT WINAPI
666 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber
*iface
, ISampleGrabberCB
*cb
, LONG whichMethod
)
668 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
669 TRACE("(%p)->(%p, %u)\n", This
, cb
, whichMethod
);
670 if (This
->grabberIface
)
671 ISampleGrabberCB_Release(This
->grabberIface
);
672 This
->grabberIface
= cb
;
673 This
->grabberMethod
= whichMethod
;
675 ISampleGrabberCB_AddRef(cb
);
680 /* SampleGrabber implementation of IMemInputPin interface */
683 static HRESULT WINAPI
684 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin
*iface
, REFIID riid
, void **ppv
)
686 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
687 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
692 SampleGrabber_IMemInputPin_AddRef(IMemInputPin
*iface
)
694 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
695 return IUnknown_AddRef(This
->outer_unk
);
700 SampleGrabber_IMemInputPin_Release(IMemInputPin
*iface
)
702 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
703 return IUnknown_Release(This
->outer_unk
);
707 static HRESULT WINAPI
708 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin
*iface
, IMemAllocator
**allocator
)
710 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
711 TRACE("(%p)->(%p) allocator = %p\n", This
, allocator
, This
->allocator
);
714 *allocator
= This
->allocator
;
716 return VFW_E_NO_ALLOCATOR
;
717 IMemAllocator_AddRef(*allocator
);
722 static HRESULT WINAPI
723 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin
*iface
, IMemAllocator
*allocator
, BOOL readOnly
)
725 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
726 TRACE("(%p)->(%p, %u) allocator = %p\n", This
, allocator
, readOnly
, This
->allocator
);
727 if (This
->allocator
== allocator
)
730 IMemAllocator_Release(This
->allocator
);
731 This
->allocator
= allocator
;
733 IMemAllocator_AddRef(allocator
);
738 static HRESULT WINAPI
739 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
741 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
742 FIXME("(%p)->(%p): semi-stub\n", This
, props
);
745 return This
->memOutput
? IMemInputPin_GetAllocatorRequirements(This
->memOutput
, props
) : E_NOTIMPL
;
749 static HRESULT WINAPI
750 SampleGrabber_IMemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*sample
)
752 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
754 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This
, sample
, This
->memOutput
, This
->grabberIface
);
757 if ((This
->filter
.state
!= State_Running
) || (This
->oneShot
== OneShot_Past
))
759 SampleGrabber_callback(This
, sample
);
760 hr
= This
->memOutput
? IMemInputPin_Receive(This
->memOutput
, sample
) : S_OK
;
761 if (This
->oneShot
== OneShot_Wait
) {
762 This
->oneShot
= OneShot_Past
;
764 if (This
->pin_out
.pair
)
765 IPin_EndOfStream(This
->pin_out
.pair
);
771 static HRESULT WINAPI
772 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin
*iface
, IMediaSample
**samples
, LONG nSamples
, LONG
*nProcessed
)
774 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
776 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This
, samples
, nSamples
, nProcessed
, This
->memOutput
, This
->grabberIface
);
777 if (!samples
|| !nProcessed
)
779 if ((This
->filter
.state
!= State_Running
) || (This
->oneShot
== OneShot_Past
))
781 for (idx
= 0; idx
< nSamples
; idx
++)
782 SampleGrabber_callback(This
, samples
[idx
]);
783 return This
->memOutput
? IMemInputPin_ReceiveMultiple(This
->memOutput
, samples
, nSamples
, nProcessed
) : S_OK
;
787 static HRESULT WINAPI
788 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
790 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
791 TRACE("(%p)\n", This
);
792 return This
->memOutput
? IMemInputPin_ReceiveCanBlock(This
->memOutput
) : S_OK
;
796 /* SampleGrabber member pin implementation */
800 SampleGrabber_IPin_AddRef(IPin
*iface
)
802 SG_Pin
*This
= impl_from_IPin(iface
);
803 return ISampleGrabber_AddRef(&This
->sg
->ISampleGrabber_iface
);
808 SampleGrabber_IPin_Release(IPin
*iface
)
810 SG_Pin
*This
= impl_from_IPin(iface
);
811 return ISampleGrabber_Release(&This
->sg
->ISampleGrabber_iface
);
815 static HRESULT WINAPI
816 SampleGrabber_IPin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
818 SG_Pin
*This
= impl_from_IPin(iface
);
819 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
822 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPin
))
824 else if (IsEqualIID(riid
, &IID_IMemInputPin
))
825 *ppv
= &This
->sg
->IMemInputPin_iface
;
826 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
827 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
828 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
829 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
831 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
832 return E_NOINTERFACE
;
835 IUnknown_AddRef((IUnknown
*)*ppv
);
839 /* IPin - input pin */
840 static HRESULT WINAPI
841 SampleGrabber_In_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*mtype
)
843 WARN("(%p, %p): unexpected\n", receiver
, mtype
);
847 /* IPin - output pin */
848 static HRESULT WINAPI
849 SampleGrabber_Out_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*type
)
851 SG_Pin
*This
= impl_from_IPin(iface
);
854 TRACE("(%p)->(%p, %p)\n", This
, receiver
, type
);
858 return VFW_E_ALREADY_CONNECTED
;
859 if (This
->sg
->filter
.state
!= State_Stopped
)
860 return VFW_E_NOT_STOPPED
;
862 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
863 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
865 debugstr_guid(&type
->formattype
), type
->cbFormat
);
866 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
867 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
868 return VFW_E_TYPE_NOT_ACCEPTED
;
869 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
870 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
871 return VFW_E_TYPE_NOT_ACCEPTED
;
872 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
873 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
874 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
875 return VFW_E_TYPE_NOT_ACCEPTED
;
878 type
= &This
->sg
->mtype
;
879 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
880 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
882 return VFW_E_TYPE_NOT_ACCEPTED
;
883 hr
= IPin_ReceiveConnection(receiver
, &This
->IPin_iface
, type
);
886 This
->pair
= receiver
;
887 if (This
->sg
->memOutput
) {
888 IMemInputPin_Release(This
->sg
->memOutput
);
889 This
->sg
->memOutput
= NULL
;
891 IPin_QueryInterface(receiver
,&IID_IMemInputPin
,(void **)&(This
->sg
->memOutput
));
892 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This
, receiver
, This
->sg
->memOutput
);
896 /* IPin - input pin */
897 static HRESULT WINAPI
898 SampleGrabber_In_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*type
)
900 SG_Pin
*This
= impl_from_IPin(iface
);
902 TRACE("(%p)->(%p, %p)\n", This
, connector
, type
);
906 return VFW_E_ALREADY_CONNECTED
;
907 if (This
->sg
->filter
.state
!= State_Stopped
)
908 return VFW_E_NOT_STOPPED
;
910 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
911 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
913 debugstr_guid(&type
->formattype
), type
->cbFormat
);
914 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
915 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
917 return VFW_E_INVALIDMEDIATYPE
;
918 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
919 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
920 return VFW_E_TYPE_NOT_ACCEPTED
;
921 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
922 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
923 return VFW_E_TYPE_NOT_ACCEPTED
;
924 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
925 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
926 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
927 return VFW_E_TYPE_NOT_ACCEPTED
;
928 if (This
->sg
->mtype
.pbFormat
)
929 CoTaskMemFree(This
->sg
->mtype
.pbFormat
);
930 This
->sg
->mtype
= *type
;
931 This
->sg
->mtype
.pUnk
= NULL
;
932 if (type
->cbFormat
) {
933 This
->sg
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
934 CopyMemory(This
->sg
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
937 This
->sg
->mtype
.pbFormat
= NULL
;
939 This
->pair
= connector
;
940 TRACE("(%p) Accepted IPin %p\n", This
, connector
);
944 /* IPin - output pin */
945 static HRESULT WINAPI
946 SampleGrabber_Out_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*mtype
)
948 WARN("(%p, %p): unexpected\n", connector
, mtype
);
952 /* IPin - input pin */
953 static HRESULT WINAPI
954 SampleGrabber_In_IPin_Disconnect(IPin
*iface
)
956 SG_Pin
*This
= impl_from_IPin(iface
);
958 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
959 if (This
->sg
->filter
.state
!= State_Stopped
)
960 return VFW_E_NOT_STOPPED
;
968 /* IPin - output pin */
969 static HRESULT WINAPI
970 SampleGrabber_Out_IPin_Disconnect(IPin
*iface
)
972 SG_Pin
*This
= impl_from_IPin(iface
);
974 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
975 if (This
->sg
->filter
.state
!= State_Stopped
)
976 return VFW_E_NOT_STOPPED
;
979 if (This
->sg
->memOutput
) {
980 IMemInputPin_Release(This
->sg
->memOutput
);
981 This
->sg
->memOutput
= NULL
;
989 static HRESULT WINAPI
990 SampleGrabber_IPin_ConnectedTo(IPin
*iface
, IPin
**pin
)
992 SG_Pin
*This
= impl_from_IPin(iface
);
994 TRACE("(%p)->(%p) pair = %p\n", This
, pin
, This
->pair
);
1002 return VFW_E_NOT_CONNECTED
;
1006 static HRESULT WINAPI
1007 SampleGrabber_IPin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*mtype
)
1009 SG_Pin
*This
= impl_from_IPin(iface
);
1011 TRACE("(%p)->(%p)\n", This
, mtype
);
1015 return VFW_E_NOT_CONNECTED
;
1016 *mtype
= This
->sg
->mtype
;
1017 if (mtype
->cbFormat
) {
1018 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
1019 CopyMemory(mtype
->pbFormat
, This
->sg
->mtype
.pbFormat
, mtype
->cbFormat
);
1025 static HRESULT WINAPI
1026 SampleGrabber_IPin_QueryPinInfo(IPin
*iface
, PIN_INFO
*info
)
1028 SG_Pin
*This
= impl_from_IPin(iface
);
1030 TRACE("(%p)->(%p)\n", This
, info
);
1033 info
->pFilter
= &This
->sg
->filter
.IBaseFilter_iface
;
1034 IBaseFilter_AddRef(info
->pFilter
);
1035 info
->dir
= This
->dir
;
1036 lstrcpynW(info
->achName
,This
->name
,MAX_PIN_NAME
);
1041 static HRESULT WINAPI
1042 SampleGrabber_IPin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*dir
)
1044 SG_Pin
*This
= impl_from_IPin(iface
);
1046 TRACE("(%p)->(%p)\n", This
, dir
);
1054 static HRESULT WINAPI
1055 SampleGrabber_IPin_QueryId(IPin
*iface
, LPWSTR
*id
)
1057 SG_Pin
*This
= impl_from_IPin(iface
);
1060 TRACE("(%p)->(%p)\n", This
, id
);
1063 len
= sizeof(WCHAR
)*(1+lstrlenW(This
->name
));
1064 *id
= CoTaskMemAlloc(len
);
1065 CopyMemory(*id
, This
->name
, len
);
1070 static HRESULT WINAPI
1071 SampleGrabber_IPin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mtype
)
1073 TRACE("(%p)\n", mtype
);
1078 static HRESULT WINAPI
1079 SampleGrabber_IPin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**mtypes
)
1081 SG_Pin
*This
= impl_from_IPin(iface
);
1083 TRACE("(%p)->(%p)\n", This
, mtypes
);
1086 *mtypes
= mediaenum_create(This
->sg
->pin_in
.pair
? &This
->sg
->mtype
: NULL
);
1087 return *mtypes
? S_OK
: E_OUTOFMEMORY
;
1090 /* IPin - input pin */
1091 static HRESULT WINAPI
1092 SampleGrabber_In_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1094 SG_Pin
*This
= impl_from_IPin(iface
);
1096 TRACE("(%p)->(%p, %p) size = %u\n", This
, pins
, nPins
, (nPins
? *nPins
: 0));
1102 IPin_AddRef(&This
->sg
->pin_out
.IPin_iface
);
1103 *pins
= &This
->sg
->pin_out
.IPin_iface
;
1111 /* IPin - output pin */
1112 static HRESULT WINAPI
1113 SampleGrabber_Out_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1115 WARN("(%p, %p): unexpected\n", pins
, nPins
);
1122 static HRESULT WINAPI
1123 SampleGrabber_IPin_EndOfStream(IPin
*iface
)
1130 static HRESULT WINAPI
1131 SampleGrabber_IPin_BeginFlush(IPin
*iface
)
1138 static HRESULT WINAPI
1139 SampleGrabber_IPin_EndFlush(IPin
*iface
)
1146 static HRESULT WINAPI
1147 SampleGrabber_IPin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double rate
)
1154 /* SampleGrabber vtables and constructor */
1156 static const IBaseFilterVtbl IBaseFilter_VTable
=
1158 SampleGrabber_IBaseFilter_QueryInterface
,
1159 SampleGrabber_IBaseFilter_AddRef
,
1160 SampleGrabber_IBaseFilter_Release
,
1161 BaseFilterImpl_GetClassID
,
1162 SampleGrabber_IBaseFilter_Stop
,
1163 SampleGrabber_IBaseFilter_Pause
,
1164 SampleGrabber_IBaseFilter_Run
,
1165 BaseFilterImpl_GetState
,
1166 BaseFilterImpl_SetSyncSource
,
1167 BaseFilterImpl_GetSyncSource
,
1168 BaseFilterImpl_EnumPins
,
1169 SampleGrabber_IBaseFilter_FindPin
,
1170 BaseFilterImpl_QueryFilterInfo
,
1171 SampleGrabber_IBaseFilter_JoinFilterGraph
,
1172 SampleGrabber_IBaseFilter_QueryVendorInfo
,
1175 static const ISampleGrabberVtbl ISampleGrabber_VTable
=
1177 SampleGrabber_ISampleGrabber_QueryInterface
,
1178 SampleGrabber_ISampleGrabber_AddRef
,
1179 SampleGrabber_ISampleGrabber_Release
,
1180 SampleGrabber_ISampleGrabber_SetOneShot
,
1181 SampleGrabber_ISampleGrabber_SetMediaType
,
1182 SampleGrabber_ISampleGrabber_GetConnectedMediaType
,
1183 SampleGrabber_ISampleGrabber_SetBufferSamples
,
1184 SampleGrabber_ISampleGrabber_GetCurrentBuffer
,
1185 SampleGrabber_ISampleGrabber_GetCurrentSample
,
1186 SampleGrabber_ISampleGrabber_SetCallback
,
1189 static const IMemInputPinVtbl IMemInputPin_VTable
=
1191 SampleGrabber_IMemInputPin_QueryInterface
,
1192 SampleGrabber_IMemInputPin_AddRef
,
1193 SampleGrabber_IMemInputPin_Release
,
1194 SampleGrabber_IMemInputPin_GetAllocator
,
1195 SampleGrabber_IMemInputPin_NotifyAllocator
,
1196 SampleGrabber_IMemInputPin_GetAllocatorRequirements
,
1197 SampleGrabber_IMemInputPin_Receive
,
1198 SampleGrabber_IMemInputPin_ReceiveMultiple
,
1199 SampleGrabber_IMemInputPin_ReceiveCanBlock
,
1202 static const IPinVtbl IPin_In_VTable
=
1204 SampleGrabber_IPin_QueryInterface
,
1205 SampleGrabber_IPin_AddRef
,
1206 SampleGrabber_IPin_Release
,
1207 SampleGrabber_In_IPin_Connect
,
1208 SampleGrabber_In_IPin_ReceiveConnection
,
1209 SampleGrabber_In_IPin_Disconnect
,
1210 SampleGrabber_IPin_ConnectedTo
,
1211 SampleGrabber_IPin_ConnectionMediaType
,
1212 SampleGrabber_IPin_QueryPinInfo
,
1213 SampleGrabber_IPin_QueryDirection
,
1214 SampleGrabber_IPin_QueryId
,
1215 SampleGrabber_IPin_QueryAccept
,
1216 SampleGrabber_IPin_EnumMediaTypes
,
1217 SampleGrabber_In_IPin_QueryInternalConnections
,
1218 SampleGrabber_IPin_EndOfStream
,
1219 SampleGrabber_IPin_BeginFlush
,
1220 SampleGrabber_IPin_EndFlush
,
1221 SampleGrabber_IPin_NewSegment
,
1224 static const IPinVtbl IPin_Out_VTable
=
1226 SampleGrabber_IPin_QueryInterface
,
1227 SampleGrabber_IPin_AddRef
,
1228 SampleGrabber_IPin_Release
,
1229 SampleGrabber_Out_IPin_Connect
,
1230 SampleGrabber_Out_IPin_ReceiveConnection
,
1231 SampleGrabber_Out_IPin_Disconnect
,
1232 SampleGrabber_IPin_ConnectedTo
,
1233 SampleGrabber_IPin_ConnectionMediaType
,
1234 SampleGrabber_IPin_QueryPinInfo
,
1235 SampleGrabber_IPin_QueryDirection
,
1236 SampleGrabber_IPin_QueryId
,
1237 SampleGrabber_IPin_QueryAccept
,
1238 SampleGrabber_IPin_EnumMediaTypes
,
1239 SampleGrabber_Out_IPin_QueryInternalConnections
,
1240 SampleGrabber_IPin_EndOfStream
,
1241 SampleGrabber_IPin_BeginFlush
,
1242 SampleGrabber_IPin_EndFlush
,
1243 SampleGrabber_IPin_NewSegment
,
1246 HRESULT
SampleGrabber_create(IUnknown
*pUnkOuter
, LPVOID
*ppv
)
1248 SG_Impl
* obj
= NULL
;
1249 ISeekingPassThru
*passthru
;
1252 TRACE("(%p,%p)\n", ppv
, pUnkOuter
);
1254 obj
= CoTaskMemAlloc(sizeof(SG_Impl
));
1257 return E_OUTOFMEMORY
;
1259 ZeroMemory(obj
, sizeof(SG_Impl
));
1261 BaseFilter_Init(&obj
->filter
, &IBaseFilter_VTable
, &CLSID_SampleGrabber
,
1262 (DWORD_PTR
)(__FILE__
": SG_Impl.csFilter"), &basefunc_vtbl
);
1263 obj
->IUnknown_inner
.lpVtbl
= &samplegrabber_vtbl
;
1264 obj
->ISampleGrabber_iface
.lpVtbl
= &ISampleGrabber_VTable
;
1265 obj
->IMemInputPin_iface
.lpVtbl
= &IMemInputPin_VTable
;
1266 obj
->pin_in
.IPin_iface
.lpVtbl
= &IPin_In_VTable
;
1267 obj
->pin_in
.dir
= PINDIR_INPUT
;
1268 obj
->pin_in
.name
= pin_in_name
;
1269 obj
->pin_in
.sg
= obj
;
1270 obj
->pin_in
.pair
= NULL
;
1271 obj
->pin_out
.IPin_iface
.lpVtbl
= &IPin_Out_VTable
;
1272 obj
->pin_out
.dir
= PINDIR_OUTPUT
;
1273 obj
->pin_out
.name
= pin_out_name
;
1274 obj
->pin_out
.sg
= obj
;
1275 obj
->pin_out
.pair
= NULL
;
1276 obj
->mtype
.majortype
= GUID_NULL
;
1277 obj
->mtype
.subtype
= MEDIASUBTYPE_None
;
1278 obj
->mtype
.formattype
= FORMAT_None
;
1279 obj
->allocator
= NULL
;
1280 obj
->memOutput
= NULL
;
1281 obj
->grabberIface
= NULL
;
1282 obj
->grabberMethod
= -1;
1283 obj
->oneShot
= OneShot_None
;
1284 obj
->bufferLen
= -1;
1285 obj
->bufferData
= NULL
;
1288 obj
->outer_unk
= pUnkOuter
;
1290 obj
->outer_unk
= &obj
->IUnknown_inner
;
1292 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)obj
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&obj
->seekthru_unk
);
1295 IUnknown_QueryInterface(obj
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
1296 ISeekingPassThru_Init(passthru
, FALSE
, &obj
->pin_in
.IPin_iface
);
1297 ISeekingPassThru_Release(passthru
);
1299 *ppv
= &obj
->IUnknown_inner
;