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 if (This
->mtype
.pbFormat
)
93 CoTaskMemFree(This
->mtype
.pbFormat
);
100 static HRESULT WINAPI
Single_IEnumMediaTypes_Next(IEnumMediaTypes
*iface
, ULONG nTypes
,
101 AM_MEDIA_TYPE
**types
, ULONG
*fetched
)
103 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
106 TRACE("(%p)->(%u, %p, %p)\n", This
, nTypes
, types
, fetched
);
109 if (!types
|| ((nTypes
!= 1) && !fetched
))
111 if (!This
->past
&& !IsEqualGUID(&This
->mtype
.majortype
,&GUID_NULL
)) {
112 AM_MEDIA_TYPE
*mtype
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
113 *mtype
= This
->mtype
;
114 if (mtype
->cbFormat
) {
115 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
116 CopyMemory(mtype
->pbFormat
, This
->mtype
.pbFormat
, mtype
->cbFormat
);
124 return (count
== nTypes
) ? S_OK
: S_FALSE
;
127 static HRESULT WINAPI
Single_IEnumMediaTypes_Skip(IEnumMediaTypes
*iface
, ULONG nTypes
)
129 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
131 TRACE("(%p)->(%u)\n", This
, nTypes
);
134 return This
->past
? S_FALSE
: S_OK
;
137 static HRESULT WINAPI
Single_IEnumMediaTypes_Reset(IEnumMediaTypes
*iface
)
139 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
141 TRACE("(%p)->()\n", This
);
146 static HRESULT WINAPI
Single_IEnumMediaTypes_Clone(IEnumMediaTypes
*iface
, IEnumMediaTypes
**me
)
148 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
150 TRACE("(%p)->(%p)\n", This
, me
);
153 *me
= mediaenum_create(&This
->mtype
, This
->past
);
155 return E_OUTOFMEMORY
;
160 /* Virtual tables and constructor */
162 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable
=
164 Single_IEnumMediaTypes_QueryInterface
,
165 Single_IEnumMediaTypes_AddRef
,
166 Single_IEnumMediaTypes_Release
,
167 Single_IEnumMediaTypes_Next
,
168 Single_IEnumMediaTypes_Skip
,
169 Single_IEnumMediaTypes_Reset
,
170 Single_IEnumMediaTypes_Clone
,
173 static IEnumMediaTypes
*mediaenum_create(const AM_MEDIA_TYPE
*mtype
, BOOL past
)
175 ME_Impl
*obj
= CoTaskMemAlloc(sizeof(ME_Impl
));
179 ZeroMemory(obj
, sizeof(*obj
));
180 obj
->IEnumMediaTypes_iface
.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
;
196 return &obj
->IEnumMediaTypes_iface
;
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
);
341 static const IUnknownVtbl samplegrabber_vtbl
=
343 SampleGrabber_QueryInterface
,
344 SampleGrabber_AddRef
,
345 SampleGrabber_Release
,
348 static IPin
*WINAPI
SampleGrabber_GetPin(BaseFilter
*iface
, int pos
)
350 SG_Impl
*This
= impl_from_BaseFilter(iface
);
354 pin
= &This
->pin_in
.IPin_iface
;
356 pin
= &This
->pin_out
.IPin_iface
;
364 static LONG WINAPI
SampleGrabber_GetPinCount(BaseFilter
*iface
)
369 static const BaseFilterFuncTable basefunc_vtbl
= {
370 SampleGrabber_GetPin
,
371 SampleGrabber_GetPinCount
374 /* Helper that buffers data and/or calls installed sample callbacks */
375 static void SampleGrabber_callback(SG_Impl
*This
, IMediaSample
*sample
)
378 REFERENCE_TIME tStart
, tEnd
;
379 if (This
->bufferLen
>= 0) {
381 LONG size
= IMediaSample_GetActualDataLength(sample
);
382 if (size
>= 0 && SUCCEEDED(IMediaSample_GetPointer(sample
, &data
))) {
385 EnterCriticalSection(&This
->filter
.csFilter
);
386 if (This
->bufferLen
!= size
) {
387 if (This
->bufferData
)
388 CoTaskMemFree(This
->bufferData
);
389 This
->bufferData
= size
? CoTaskMemAlloc(size
) : NULL
;
390 This
->bufferLen
= size
;
393 CopyMemory(This
->bufferData
, data
, size
);
394 LeaveCriticalSection(&This
->filter
.csFilter
);
397 if (!This
->grabberIface
)
399 if (SUCCEEDED(IMediaSample_GetTime(sample
, &tStart
, &tEnd
)))
400 time
= 1e-7 * tStart
;
401 switch (This
->grabberMethod
) {
404 ULONG ref
= IMediaSample_AddRef(sample
);
405 ISampleGrabberCB_SampleCB(This
->grabberIface
, time
, sample
);
406 ref
= IMediaSample_Release(sample
) + 1 - ref
;
409 ERR("(%p) Callback referenced sample %p by %u\n", This
, sample
, ref
);
410 /* ugly as hell but some apps are sooo buggy */
412 IMediaSample_Release(sample
);
419 LONG size
= IMediaSample_GetActualDataLength(sample
);
420 if (size
&& SUCCEEDED(IMediaSample_GetPointer(sample
, &data
)) && data
)
421 ISampleGrabberCB_BufferCB(This
->grabberIface
, time
, data
, size
);
427 FIXME("unsupported method %d\n", This
->grabberMethod
);
428 /* do not bother us again */
429 This
->grabberMethod
= -1;
434 /* SampleGrabber implementation of IBaseFilter interface */
437 static HRESULT WINAPI
438 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
440 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
441 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
446 SampleGrabber_IBaseFilter_AddRef(IBaseFilter
*iface
)
448 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
449 return IUnknown_AddRef(This
->outer_unk
);
454 SampleGrabber_IBaseFilter_Release(IBaseFilter
*iface
)
456 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
457 return IUnknown_Release(This
->outer_unk
);
461 static HRESULT WINAPI
462 SampleGrabber_IBaseFilter_Stop(IBaseFilter
*iface
)
464 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
465 TRACE("(%p)\n", This
);
466 This
->filter
.state
= State_Stopped
;
471 static HRESULT WINAPI
472 SampleGrabber_IBaseFilter_Pause(IBaseFilter
*iface
)
474 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
475 TRACE("(%p)\n", This
);
476 This
->filter
.state
= State_Paused
;
481 static HRESULT WINAPI
482 SampleGrabber_IBaseFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
484 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
485 TRACE("(%p)\n", This
);
486 This
->filter
.state
= State_Running
;
491 static HRESULT WINAPI
492 SampleGrabber_IBaseFilter_FindPin(IBaseFilter
*iface
, LPCWSTR id
, IPin
**pin
)
494 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
495 TRACE("(%p)->(%s, %p)\n", This
, debugstr_w(id
), pin
);
498 if (!lstrcmpiW(id
,pin_in_name
))
500 *pin
= &This
->pin_in
.IPin_iface
;
504 else if (!lstrcmpiW(id
,pin_out_name
))
506 *pin
= &This
->pin_out
.IPin_iface
;
511 return VFW_E_NOT_FOUND
;
515 static HRESULT WINAPI
516 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*graph
, LPCWSTR name
)
518 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
520 TRACE("(%p)->(%p, %s)\n", This
, graph
, debugstr_w(name
));
522 BaseFilterImpl_JoinFilterGraph(iface
, graph
, name
);
523 This
->oneShot
= OneShot_None
;
529 static HRESULT WINAPI
530 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter
*iface
, LPWSTR
*vendor
)
532 TRACE("(%p)\n", vendor
);
535 *vendor
= CoTaskMemAlloc(sizeof(vendor_name
));
536 CopyMemory(*vendor
, vendor_name
, sizeof(vendor_name
));
541 /* SampleGrabber implementation of ISampleGrabber interface */
544 static HRESULT WINAPI
545 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber
*iface
, REFIID riid
, void **ppv
)
547 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
548 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
553 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber
*iface
)
555 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
556 return IUnknown_AddRef(This
->outer_unk
);
561 SampleGrabber_ISampleGrabber_Release(ISampleGrabber
*iface
)
563 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
564 return IUnknown_Release(This
->outer_unk
);
568 static HRESULT WINAPI
569 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber
*iface
, BOOL oneShot
)
571 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
572 TRACE("(%p)->(%u)\n", This
, oneShot
);
573 This
->oneShot
= oneShot
? OneShot_Wait
: OneShot_None
;
578 static HRESULT WINAPI
579 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber
*iface
, const AM_MEDIA_TYPE
*type
)
581 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
582 TRACE("(%p)->(%p)\n", This
, type
);
585 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
586 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
588 debugstr_guid(&type
->formattype
), type
->cbFormat
);
589 if (This
->mtype
.pbFormat
)
590 CoTaskMemFree(This
->mtype
.pbFormat
);
592 This
->mtype
.pUnk
= NULL
;
593 if (type
->cbFormat
) {
594 This
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
595 CopyMemory(This
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
598 This
->mtype
.pbFormat
= NULL
;
603 static HRESULT WINAPI
604 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber
*iface
, AM_MEDIA_TYPE
*type
)
606 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
607 TRACE("(%p)->(%p)\n", This
, type
);
610 if (!This
->pin_in
.pair
)
611 return VFW_E_NOT_CONNECTED
;
613 if (type
->cbFormat
) {
614 type
->pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
615 CopyMemory(type
->pbFormat
, This
->mtype
.pbFormat
, type
->cbFormat
);
621 static HRESULT WINAPI
622 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber
*iface
, BOOL bufferEm
)
624 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
625 TRACE("(%p)->(%u)\n", This
, bufferEm
);
626 EnterCriticalSection(&This
->filter
.csFilter
);
628 if (This
->bufferLen
< 0)
632 This
->bufferLen
= -1;
633 LeaveCriticalSection(&This
->filter
.csFilter
);
638 static HRESULT WINAPI
639 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber
*iface
, LONG
*bufSize
, LONG
*buffer
)
641 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
643 TRACE("(%p)->(%p, %p)\n", This
, bufSize
, buffer
);
646 EnterCriticalSection(&This
->filter
.csFilter
);
647 if (!This
->pin_in
.pair
)
648 ret
= VFW_E_NOT_CONNECTED
;
649 else if (This
->bufferLen
< 0)
651 else if (This
->bufferLen
== 0)
652 ret
= VFW_E_WRONG_STATE
;
655 if (*bufSize
>= This
->bufferLen
)
656 CopyMemory(buffer
, This
->bufferData
, This
->bufferLen
);
660 *bufSize
= This
->bufferLen
;
662 LeaveCriticalSection(&This
->filter
.csFilter
);
667 static HRESULT WINAPI
668 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber
*iface
, IMediaSample
**sample
)
670 /* MS doesn't implement it either, no one should call it */
671 WARN("(%p): not implemented\n", sample
);
676 static HRESULT WINAPI
677 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber
*iface
, ISampleGrabberCB
*cb
, LONG whichMethod
)
679 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
680 TRACE("(%p)->(%p, %u)\n", This
, cb
, whichMethod
);
681 if (This
->grabberIface
)
682 ISampleGrabberCB_Release(This
->grabberIface
);
683 This
->grabberIface
= cb
;
684 This
->grabberMethod
= whichMethod
;
686 ISampleGrabberCB_AddRef(cb
);
691 /* SampleGrabber implementation of IMemInputPin interface */
694 static HRESULT WINAPI
695 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin
*iface
, REFIID riid
, void **ppv
)
697 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
698 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
703 SampleGrabber_IMemInputPin_AddRef(IMemInputPin
*iface
)
705 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
706 return IUnknown_AddRef(This
->outer_unk
);
711 SampleGrabber_IMemInputPin_Release(IMemInputPin
*iface
)
713 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
714 return IUnknown_Release(This
->outer_unk
);
718 static HRESULT WINAPI
719 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin
*iface
, IMemAllocator
**allocator
)
721 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
722 TRACE("(%p)->(%p) allocator = %p\n", This
, allocator
, This
->allocator
);
725 *allocator
= This
->allocator
;
727 return VFW_E_NO_ALLOCATOR
;
728 IMemAllocator_AddRef(*allocator
);
733 static HRESULT WINAPI
734 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin
*iface
, IMemAllocator
*allocator
, BOOL readOnly
)
736 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
737 TRACE("(%p)->(%p, %u) allocator = %p\n", This
, allocator
, readOnly
, This
->allocator
);
738 if (This
->allocator
== allocator
)
741 IMemAllocator_Release(This
->allocator
);
742 This
->allocator
= allocator
;
744 IMemAllocator_AddRef(allocator
);
749 static HRESULT WINAPI
750 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
752 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
753 FIXME("(%p)->(%p): semi-stub\n", This
, props
);
756 return This
->memOutput
? IMemInputPin_GetAllocatorRequirements(This
->memOutput
, props
) : E_NOTIMPL
;
760 static HRESULT WINAPI
761 SampleGrabber_IMemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*sample
)
763 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
765 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This
, sample
, This
->memOutput
, This
->grabberIface
);
768 if (This
->oneShot
== OneShot_Past
)
770 SampleGrabber_callback(This
, sample
);
771 hr
= This
->memOutput
? IMemInputPin_Receive(This
->memOutput
, sample
) : S_OK
;
772 if (This
->oneShot
== OneShot_Wait
) {
773 This
->oneShot
= OneShot_Past
;
775 if (This
->pin_out
.pair
)
776 IPin_EndOfStream(This
->pin_out
.pair
);
782 static HRESULT WINAPI
783 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin
*iface
, IMediaSample
**samples
, LONG nSamples
, LONG
*nProcessed
)
785 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
787 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This
, samples
, nSamples
, nProcessed
, This
->memOutput
, This
->grabberIface
);
788 if (!samples
|| !nProcessed
)
790 if ((This
->filter
.state
!= State_Running
) || (This
->oneShot
== OneShot_Past
))
792 for (idx
= 0; idx
< nSamples
; idx
++)
793 SampleGrabber_callback(This
, samples
[idx
]);
794 return This
->memOutput
? IMemInputPin_ReceiveMultiple(This
->memOutput
, samples
, nSamples
, nProcessed
) : S_OK
;
798 static HRESULT WINAPI
799 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
801 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
802 TRACE("(%p)\n", This
);
803 return This
->memOutput
? IMemInputPin_ReceiveCanBlock(This
->memOutput
) : S_OK
;
807 /* SampleGrabber member pin implementation */
811 SampleGrabber_IPin_AddRef(IPin
*iface
)
813 SG_Pin
*This
= impl_from_IPin(iface
);
814 return ISampleGrabber_AddRef(&This
->sg
->ISampleGrabber_iface
);
819 SampleGrabber_IPin_Release(IPin
*iface
)
821 SG_Pin
*This
= impl_from_IPin(iface
);
822 return ISampleGrabber_Release(&This
->sg
->ISampleGrabber_iface
);
826 static HRESULT WINAPI
827 SampleGrabber_IPin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
829 SG_Pin
*This
= impl_from_IPin(iface
);
830 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
833 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPin
))
835 else if (IsEqualIID(riid
, &IID_IMemInputPin
))
836 *ppv
= &This
->sg
->IMemInputPin_iface
;
837 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
838 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
839 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
840 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
842 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
843 return E_NOINTERFACE
;
846 IUnknown_AddRef((IUnknown
*)*ppv
);
850 /* IPin - input pin */
851 static HRESULT WINAPI
852 SampleGrabber_In_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*mtype
)
854 WARN("(%p, %p): unexpected\n", receiver
, mtype
);
858 /* IPin - output pin */
859 static HRESULT WINAPI
860 SampleGrabber_Out_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*type
)
862 SG_Pin
*This
= impl_from_IPin(iface
);
865 TRACE("(%p)->(%p, %p)\n", This
, receiver
, type
);
869 return VFW_E_ALREADY_CONNECTED
;
870 if (This
->sg
->filter
.state
!= State_Stopped
)
871 return VFW_E_NOT_STOPPED
;
873 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
874 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
876 debugstr_guid(&type
->formattype
), type
->cbFormat
);
877 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
878 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
879 return VFW_E_TYPE_NOT_ACCEPTED
;
880 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
881 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
882 return VFW_E_TYPE_NOT_ACCEPTED
;
883 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
884 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
885 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
886 return VFW_E_TYPE_NOT_ACCEPTED
;
889 type
= &This
->sg
->mtype
;
890 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
891 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
893 return VFW_E_TYPE_NOT_ACCEPTED
;
894 hr
= IPin_ReceiveConnection(receiver
, &This
->IPin_iface
, type
);
897 This
->pair
= receiver
;
898 if (This
->sg
->memOutput
) {
899 IMemInputPin_Release(This
->sg
->memOutput
);
900 This
->sg
->memOutput
= NULL
;
902 IPin_QueryInterface(receiver
,&IID_IMemInputPin
,(void **)&(This
->sg
->memOutput
));
903 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This
, receiver
, This
->sg
->memOutput
);
907 /* IPin - input pin */
908 static HRESULT WINAPI
909 SampleGrabber_In_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*type
)
911 SG_Pin
*This
= impl_from_IPin(iface
);
913 TRACE("(%p)->(%p, %p)\n", This
, connector
, type
);
917 return VFW_E_ALREADY_CONNECTED
;
918 if (This
->sg
->filter
.state
!= State_Stopped
)
919 return VFW_E_NOT_STOPPED
;
921 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
922 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
924 debugstr_guid(&type
->formattype
), type
->cbFormat
);
925 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
926 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
928 return VFW_E_INVALIDMEDIATYPE
;
929 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
930 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
931 return VFW_E_TYPE_NOT_ACCEPTED
;
932 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
933 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
934 return VFW_E_TYPE_NOT_ACCEPTED
;
935 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
936 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
937 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
938 return VFW_E_TYPE_NOT_ACCEPTED
;
939 if (This
->sg
->mtype
.pbFormat
)
940 CoTaskMemFree(This
->sg
->mtype
.pbFormat
);
941 This
->sg
->mtype
= *type
;
942 This
->sg
->mtype
.pUnk
= NULL
;
943 if (type
->cbFormat
) {
944 This
->sg
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
945 CopyMemory(This
->sg
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
948 This
->sg
->mtype
.pbFormat
= NULL
;
950 This
->pair
= connector
;
951 TRACE("(%p) Accepted IPin %p\n", This
, connector
);
955 /* IPin - output pin */
956 static HRESULT WINAPI
957 SampleGrabber_Out_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*mtype
)
959 WARN("(%p, %p): unexpected\n", connector
, mtype
);
963 /* IPin - input pin */
964 static HRESULT WINAPI
965 SampleGrabber_In_IPin_Disconnect(IPin
*iface
)
967 SG_Pin
*This
= impl_from_IPin(iface
);
969 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
970 if (This
->sg
->filter
.state
!= State_Stopped
)
971 return VFW_E_NOT_STOPPED
;
979 /* IPin - output pin */
980 static HRESULT WINAPI
981 SampleGrabber_Out_IPin_Disconnect(IPin
*iface
)
983 SG_Pin
*This
= impl_from_IPin(iface
);
985 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
986 if (This
->sg
->filter
.state
!= State_Stopped
)
987 return VFW_E_NOT_STOPPED
;
990 if (This
->sg
->memOutput
) {
991 IMemInputPin_Release(This
->sg
->memOutput
);
992 This
->sg
->memOutput
= NULL
;
1000 static HRESULT WINAPI
1001 SampleGrabber_IPin_ConnectedTo(IPin
*iface
, IPin
**pin
)
1003 SG_Pin
*This
= impl_from_IPin(iface
);
1005 TRACE("(%p)->(%p) pair = %p\n", This
, pin
, This
->pair
);
1013 return VFW_E_NOT_CONNECTED
;
1017 static HRESULT WINAPI
1018 SampleGrabber_IPin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*mtype
)
1020 SG_Pin
*This
= impl_from_IPin(iface
);
1022 TRACE("(%p)->(%p)\n", This
, mtype
);
1026 return VFW_E_NOT_CONNECTED
;
1027 *mtype
= This
->sg
->mtype
;
1028 if (mtype
->cbFormat
) {
1029 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
1030 CopyMemory(mtype
->pbFormat
, This
->sg
->mtype
.pbFormat
, mtype
->cbFormat
);
1036 static HRESULT WINAPI
1037 SampleGrabber_IPin_QueryPinInfo(IPin
*iface
, PIN_INFO
*info
)
1039 SG_Pin
*This
= impl_from_IPin(iface
);
1041 TRACE("(%p)->(%p)\n", This
, info
);
1044 info
->pFilter
= &This
->sg
->filter
.IBaseFilter_iface
;
1045 IBaseFilter_AddRef(info
->pFilter
);
1046 info
->dir
= This
->dir
;
1047 lstrcpynW(info
->achName
,This
->name
,MAX_PIN_NAME
);
1052 static HRESULT WINAPI
1053 SampleGrabber_IPin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*dir
)
1055 SG_Pin
*This
= impl_from_IPin(iface
);
1057 TRACE("(%p)->(%p)\n", This
, dir
);
1065 static HRESULT WINAPI
1066 SampleGrabber_IPin_QueryId(IPin
*iface
, LPWSTR
*id
)
1068 SG_Pin
*This
= impl_from_IPin(iface
);
1071 TRACE("(%p)->(%p)\n", This
, id
);
1074 len
= sizeof(WCHAR
)*(1+lstrlenW(This
->name
));
1075 *id
= CoTaskMemAlloc(len
);
1076 CopyMemory(*id
, This
->name
, len
);
1081 static HRESULT WINAPI
1082 SampleGrabber_IPin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mtype
)
1084 TRACE("(%p)\n", mtype
);
1089 static HRESULT WINAPI
1090 SampleGrabber_IPin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**mtypes
)
1092 SG_Pin
*This
= impl_from_IPin(iface
);
1094 TRACE("(%p)->(%p)\n", This
, mtypes
);
1097 *mtypes
= mediaenum_create(This
->sg
->pin_in
.pair
? &This
->sg
->mtype
: NULL
, FALSE
);
1098 return *mtypes
? S_OK
: E_OUTOFMEMORY
;
1101 /* IPin - input pin */
1102 static HRESULT WINAPI
1103 SampleGrabber_In_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1105 SG_Pin
*This
= impl_from_IPin(iface
);
1107 TRACE("(%p)->(%p, %p) size = %u\n", This
, pins
, nPins
, (nPins
? *nPins
: 0));
1113 IPin_AddRef(&This
->sg
->pin_out
.IPin_iface
);
1114 *pins
= &This
->sg
->pin_out
.IPin_iface
;
1122 /* IPin - output pin */
1123 static HRESULT WINAPI
1124 SampleGrabber_Out_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1126 WARN("(%p, %p): unexpected\n", pins
, nPins
);
1133 static HRESULT WINAPI
1134 SampleGrabber_IPin_EndOfStream(IPin
*iface
)
1141 static HRESULT WINAPI
1142 SampleGrabber_IPin_BeginFlush(IPin
*iface
)
1149 static HRESULT WINAPI
1150 SampleGrabber_IPin_EndFlush(IPin
*iface
)
1157 static HRESULT WINAPI
1158 SampleGrabber_IPin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double rate
)
1165 /* SampleGrabber vtables and constructor */
1167 static const IBaseFilterVtbl IBaseFilter_VTable
=
1169 SampleGrabber_IBaseFilter_QueryInterface
,
1170 SampleGrabber_IBaseFilter_AddRef
,
1171 SampleGrabber_IBaseFilter_Release
,
1172 BaseFilterImpl_GetClassID
,
1173 SampleGrabber_IBaseFilter_Stop
,
1174 SampleGrabber_IBaseFilter_Pause
,
1175 SampleGrabber_IBaseFilter_Run
,
1176 BaseFilterImpl_GetState
,
1177 BaseFilterImpl_SetSyncSource
,
1178 BaseFilterImpl_GetSyncSource
,
1179 BaseFilterImpl_EnumPins
,
1180 SampleGrabber_IBaseFilter_FindPin
,
1181 BaseFilterImpl_QueryFilterInfo
,
1182 SampleGrabber_IBaseFilter_JoinFilterGraph
,
1183 SampleGrabber_IBaseFilter_QueryVendorInfo
,
1186 static const ISampleGrabberVtbl ISampleGrabber_VTable
=
1188 SampleGrabber_ISampleGrabber_QueryInterface
,
1189 SampleGrabber_ISampleGrabber_AddRef
,
1190 SampleGrabber_ISampleGrabber_Release
,
1191 SampleGrabber_ISampleGrabber_SetOneShot
,
1192 SampleGrabber_ISampleGrabber_SetMediaType
,
1193 SampleGrabber_ISampleGrabber_GetConnectedMediaType
,
1194 SampleGrabber_ISampleGrabber_SetBufferSamples
,
1195 SampleGrabber_ISampleGrabber_GetCurrentBuffer
,
1196 SampleGrabber_ISampleGrabber_GetCurrentSample
,
1197 SampleGrabber_ISampleGrabber_SetCallback
,
1200 static const IMemInputPinVtbl IMemInputPin_VTable
=
1202 SampleGrabber_IMemInputPin_QueryInterface
,
1203 SampleGrabber_IMemInputPin_AddRef
,
1204 SampleGrabber_IMemInputPin_Release
,
1205 SampleGrabber_IMemInputPin_GetAllocator
,
1206 SampleGrabber_IMemInputPin_NotifyAllocator
,
1207 SampleGrabber_IMemInputPin_GetAllocatorRequirements
,
1208 SampleGrabber_IMemInputPin_Receive
,
1209 SampleGrabber_IMemInputPin_ReceiveMultiple
,
1210 SampleGrabber_IMemInputPin_ReceiveCanBlock
,
1213 static const IPinVtbl IPin_In_VTable
=
1215 SampleGrabber_IPin_QueryInterface
,
1216 SampleGrabber_IPin_AddRef
,
1217 SampleGrabber_IPin_Release
,
1218 SampleGrabber_In_IPin_Connect
,
1219 SampleGrabber_In_IPin_ReceiveConnection
,
1220 SampleGrabber_In_IPin_Disconnect
,
1221 SampleGrabber_IPin_ConnectedTo
,
1222 SampleGrabber_IPin_ConnectionMediaType
,
1223 SampleGrabber_IPin_QueryPinInfo
,
1224 SampleGrabber_IPin_QueryDirection
,
1225 SampleGrabber_IPin_QueryId
,
1226 SampleGrabber_IPin_QueryAccept
,
1227 SampleGrabber_IPin_EnumMediaTypes
,
1228 SampleGrabber_In_IPin_QueryInternalConnections
,
1229 SampleGrabber_IPin_EndOfStream
,
1230 SampleGrabber_IPin_BeginFlush
,
1231 SampleGrabber_IPin_EndFlush
,
1232 SampleGrabber_IPin_NewSegment
,
1235 static const IPinVtbl IPin_Out_VTable
=
1237 SampleGrabber_IPin_QueryInterface
,
1238 SampleGrabber_IPin_AddRef
,
1239 SampleGrabber_IPin_Release
,
1240 SampleGrabber_Out_IPin_Connect
,
1241 SampleGrabber_Out_IPin_ReceiveConnection
,
1242 SampleGrabber_Out_IPin_Disconnect
,
1243 SampleGrabber_IPin_ConnectedTo
,
1244 SampleGrabber_IPin_ConnectionMediaType
,
1245 SampleGrabber_IPin_QueryPinInfo
,
1246 SampleGrabber_IPin_QueryDirection
,
1247 SampleGrabber_IPin_QueryId
,
1248 SampleGrabber_IPin_QueryAccept
,
1249 SampleGrabber_IPin_EnumMediaTypes
,
1250 SampleGrabber_Out_IPin_QueryInternalConnections
,
1251 SampleGrabber_IPin_EndOfStream
,
1252 SampleGrabber_IPin_BeginFlush
,
1253 SampleGrabber_IPin_EndFlush
,
1254 SampleGrabber_IPin_NewSegment
,
1257 HRESULT
SampleGrabber_create(IUnknown
*pUnkOuter
, LPVOID
*ppv
)
1259 SG_Impl
* obj
= NULL
;
1260 ISeekingPassThru
*passthru
;
1263 TRACE("(%p,%p)\n", pUnkOuter
, ppv
);
1265 obj
= CoTaskMemAlloc(sizeof(SG_Impl
));
1268 return E_OUTOFMEMORY
;
1270 ZeroMemory(obj
, sizeof(SG_Impl
));
1272 BaseFilter_Init(&obj
->filter
, &IBaseFilter_VTable
, &CLSID_SampleGrabber
,
1273 (DWORD_PTR
)(__FILE__
": SG_Impl.csFilter"), &basefunc_vtbl
);
1274 obj
->IUnknown_inner
.lpVtbl
= &samplegrabber_vtbl
;
1275 obj
->ISampleGrabber_iface
.lpVtbl
= &ISampleGrabber_VTable
;
1276 obj
->IMemInputPin_iface
.lpVtbl
= &IMemInputPin_VTable
;
1277 obj
->pin_in
.IPin_iface
.lpVtbl
= &IPin_In_VTable
;
1278 obj
->pin_in
.dir
= PINDIR_INPUT
;
1279 obj
->pin_in
.name
= pin_in_name
;
1280 obj
->pin_in
.sg
= obj
;
1281 obj
->pin_in
.pair
= NULL
;
1282 obj
->pin_out
.IPin_iface
.lpVtbl
= &IPin_Out_VTable
;
1283 obj
->pin_out
.dir
= PINDIR_OUTPUT
;
1284 obj
->pin_out
.name
= pin_out_name
;
1285 obj
->pin_out
.sg
= obj
;
1286 obj
->pin_out
.pair
= NULL
;
1287 obj
->mtype
.majortype
= GUID_NULL
;
1288 obj
->mtype
.subtype
= MEDIASUBTYPE_None
;
1289 obj
->mtype
.formattype
= FORMAT_None
;
1290 obj
->allocator
= NULL
;
1291 obj
->memOutput
= NULL
;
1292 obj
->grabberIface
= NULL
;
1293 obj
->grabberMethod
= -1;
1294 obj
->oneShot
= OneShot_None
;
1295 obj
->bufferLen
= -1;
1296 obj
->bufferData
= NULL
;
1299 obj
->outer_unk
= pUnkOuter
;
1301 obj
->outer_unk
= &obj
->IUnknown_inner
;
1303 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)obj
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&obj
->seekthru_unk
);
1306 IUnknown_QueryInterface(obj
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
1307 ISeekingPassThru_Init(passthru
, FALSE
, &obj
->pin_in
.IPin_iface
);
1308 ISeekingPassThru_Release(passthru
);
1310 *ppv
= &obj
->IUnknown_inner
;