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
, BOOL past
);
30 /* Single media type enumerator */
31 typedef struct _ME_Impl
{
32 IEnumMediaTypes IEnumMediaTypes_iface
;
39 /* IEnumMediaTypes interface implementation */
41 static inline ME_Impl
*impl_from_IEnumMediaTypes(IEnumMediaTypes
*iface
)
43 return CONTAINING_RECORD(iface
, ME_Impl
, IEnumMediaTypes_iface
);
46 static HRESULT WINAPI
Single_IEnumMediaTypes_QueryInterface(IEnumMediaTypes
*iface
, REFIID riid
,
49 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
51 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ret_iface
);
53 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IEnumMediaTypes
)) {
55 IEnumMediaTypes_AddRef(iface
);
59 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ret_iface
);
63 static ULONG WINAPI
Single_IEnumMediaTypes_AddRef(IEnumMediaTypes
*iface
)
65 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
66 ULONG refCount
= InterlockedIncrement(&This
->refCount
);
68 TRACE("(%p) new ref = %u\n", This
, refCount
);
72 static ULONG WINAPI
Single_IEnumMediaTypes_Release(IEnumMediaTypes
*iface
)
74 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
75 ULONG refCount
= InterlockedDecrement(&This
->refCount
);
77 TRACE("(%p) new ref = %u\n", This
, refCount
);
80 if (This
->mtype
.pbFormat
)
81 CoTaskMemFree(This
->mtype
.pbFormat
);
89 static HRESULT WINAPI
Single_IEnumMediaTypes_Next(IEnumMediaTypes
*iface
, ULONG nTypes
,
90 AM_MEDIA_TYPE
**types
, ULONG
*fetched
)
92 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
95 TRACE("(%p)->(%u, %p, %p)\n", This
, nTypes
, types
, fetched
);
98 if (!types
|| ((nTypes
!= 1) && !fetched
))
100 if (!This
->past
&& !IsEqualGUID(&This
->mtype
.majortype
,&GUID_NULL
)) {
101 AM_MEDIA_TYPE
*mtype
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
102 *mtype
= This
->mtype
;
103 if (mtype
->cbFormat
) {
104 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
105 CopyMemory(mtype
->pbFormat
, This
->mtype
.pbFormat
, mtype
->cbFormat
);
113 return (count
== nTypes
) ? S_OK
: S_FALSE
;
116 static HRESULT WINAPI
Single_IEnumMediaTypes_Skip(IEnumMediaTypes
*iface
, ULONG nTypes
)
118 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
120 TRACE("(%p)->(%u)\n", This
, nTypes
);
123 return This
->past
? S_FALSE
: S_OK
;
126 static HRESULT WINAPI
Single_IEnumMediaTypes_Reset(IEnumMediaTypes
*iface
)
128 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
130 TRACE("(%p)->()\n", This
);
135 static HRESULT WINAPI
Single_IEnumMediaTypes_Clone(IEnumMediaTypes
*iface
, IEnumMediaTypes
**me
)
137 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
139 TRACE("(%p)->(%p)\n", This
, me
);
142 *me
= mediaenum_create(&This
->mtype
, This
->past
);
144 return E_OUTOFMEMORY
;
149 /* Virtual tables and constructor */
151 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable
=
153 Single_IEnumMediaTypes_QueryInterface
,
154 Single_IEnumMediaTypes_AddRef
,
155 Single_IEnumMediaTypes_Release
,
156 Single_IEnumMediaTypes_Next
,
157 Single_IEnumMediaTypes_Skip
,
158 Single_IEnumMediaTypes_Reset
,
159 Single_IEnumMediaTypes_Clone
,
162 static IEnumMediaTypes
*mediaenum_create(const AM_MEDIA_TYPE
*mtype
, BOOL past
)
164 ME_Impl
*obj
= CoTaskMemAlloc(sizeof(ME_Impl
));
168 ZeroMemory(obj
, sizeof(*obj
));
169 obj
->IEnumMediaTypes_iface
.lpVtbl
= &IEnumMediaTypes_VTable
;
174 obj
->mtype
.pUnk
= NULL
;
175 if (mtype
->cbFormat
) {
176 obj
->mtype
.pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
177 CopyMemory(obj
->mtype
.pbFormat
, mtype
->pbFormat
, mtype
->cbFormat
);
180 obj
->mtype
.pbFormat
= NULL
;
183 obj
->mtype
.majortype
= GUID_NULL
;
185 return &obj
->IEnumMediaTypes_iface
;
189 /* Sample Grabber pin implementation */
190 typedef struct _SG_Pin
{
198 static inline SG_Pin
*impl_from_IPin(IPin
*iface
)
200 return CONTAINING_RECORD(iface
, SG_Pin
, IPin_iface
);
203 /* Sample Grabber filter implementation */
204 typedef struct _SG_Impl
{
205 IUnknown IUnknown_inner
;
207 ISampleGrabber ISampleGrabber_iface
;
208 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
209 IUnknown
* seekthru_unk
;
214 IMemInputPin IMemInputPin_iface
;
215 IMemAllocator
*allocator
;
216 IMemInputPin
*memOutput
;
217 ISampleGrabberCB
*grabberIface
;
230 static inline SG_Impl
*impl_from_IUnknown(IUnknown
*iface
)
232 return CONTAINING_RECORD(iface
, SG_Impl
, IUnknown_inner
);
235 static inline SG_Impl
*impl_from_BaseFilter(BaseFilter
*iface
)
237 return CONTAINING_RECORD(iface
, SG_Impl
, filter
);
240 static inline SG_Impl
*impl_from_IBaseFilter(IBaseFilter
*iface
)
242 return CONTAINING_RECORD(iface
, SG_Impl
, filter
.IBaseFilter_iface
);
245 static inline SG_Impl
*impl_from_ISampleGrabber(ISampleGrabber
*iface
)
247 return CONTAINING_RECORD(iface
, SG_Impl
, ISampleGrabber_iface
);
250 static inline SG_Impl
*impl_from_IMemInputPin(IMemInputPin
*iface
)
252 return CONTAINING_RECORD(iface
, SG_Impl
, IMemInputPin_iface
);
256 /* Cleanup at end of life */
257 static void SampleGrabber_cleanup(SG_Impl
*This
)
259 TRACE("(%p)\n", This
);
260 if (This
->filter
.filterInfo
.pGraph
)
261 WARN("(%p) still joined to filter graph %p\n", This
, This
->filter
.filterInfo
.pGraph
);
263 IMemAllocator_Release(This
->allocator
);
265 IMemInputPin_Release(This
->memOutput
);
266 if (This
->grabberIface
)
267 ISampleGrabberCB_Release(This
->grabberIface
);
268 if (This
->mtype
.pbFormat
)
269 CoTaskMemFree(This
->mtype
.pbFormat
);
270 if (This
->bufferData
)
271 CoTaskMemFree(This
->bufferData
);
272 if(This
->seekthru_unk
)
273 IUnknown_Release(This
->seekthru_unk
);
276 /* SampleGrabber inner IUnknown */
277 static HRESULT WINAPI
SampleGrabber_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
279 SG_Impl
*This
= impl_from_IUnknown(iface
);
281 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
284 if (IsEqualIID(riid
, &IID_IUnknown
))
285 *ppv
= &This
->IUnknown_inner
;
286 else if (IsEqualIID(riid
, &IID_IPersist
) || IsEqualIID(riid
, &IID_IMediaFilter
) ||
287 IsEqualIID(riid
, &IID_IBaseFilter
))
288 *ppv
= &This
->filter
.IBaseFilter_iface
;
289 else if (IsEqualIID(riid
, &IID_ISampleGrabber
))
290 *ppv
= &This
->ISampleGrabber_iface
;
291 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
292 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
293 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
294 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
296 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
299 return E_NOINTERFACE
;
301 IUnknown_AddRef((IUnknown
*)*ppv
);
305 static ULONG WINAPI
SampleGrabber_AddRef(IUnknown
*iface
)
307 SG_Impl
*This
= impl_from_IUnknown(iface
);
308 ULONG ref
= BaseFilterImpl_AddRef(&This
->filter
.IBaseFilter_iface
);
310 TRACE("(%p) ref=%d\n", This
, ref
);
315 static ULONG WINAPI
SampleGrabber_Release(IUnknown
*iface
)
317 SG_Impl
*This
= impl_from_IUnknown(iface
);
318 ULONG ref
= BaseFilterImpl_Release(&This
->filter
.IBaseFilter_iface
);
320 TRACE("(%p) ref=%d\n", This
, ref
);
324 SampleGrabber_cleanup(This
);
331 static const IUnknownVtbl samplegrabber_vtbl
=
333 SampleGrabber_QueryInterface
,
334 SampleGrabber_AddRef
,
335 SampleGrabber_Release
,
338 static IPin
*WINAPI
SampleGrabber_GetPin(BaseFilter
*iface
, int pos
)
340 SG_Impl
*This
= impl_from_BaseFilter(iface
);
344 pin
= &This
->pin_in
.IPin_iface
;
346 pin
= &This
->pin_out
.IPin_iface
;
354 static LONG WINAPI
SampleGrabber_GetPinCount(BaseFilter
*iface
)
359 static const BaseFilterFuncTable basefunc_vtbl
= {
360 SampleGrabber_GetPin
,
361 SampleGrabber_GetPinCount
364 /* Helper that buffers data and/or calls installed sample callbacks */
365 static void SampleGrabber_callback(SG_Impl
*This
, IMediaSample
*sample
)
368 REFERENCE_TIME tStart
, tEnd
;
369 if (This
->bufferLen
>= 0) {
371 LONG size
= IMediaSample_GetActualDataLength(sample
);
372 if (size
>= 0 && SUCCEEDED(IMediaSample_GetPointer(sample
, &data
))) {
375 EnterCriticalSection(&This
->filter
.csFilter
);
376 if (This
->bufferLen
!= size
) {
377 if (This
->bufferData
)
378 CoTaskMemFree(This
->bufferData
);
379 This
->bufferData
= size
? CoTaskMemAlloc(size
) : NULL
;
380 This
->bufferLen
= size
;
383 CopyMemory(This
->bufferData
, data
, size
);
384 LeaveCriticalSection(&This
->filter
.csFilter
);
387 if (!This
->grabberIface
)
389 if (SUCCEEDED(IMediaSample_GetTime(sample
, &tStart
, &tEnd
)))
390 time
= 1e-7 * tStart
;
391 switch (This
->grabberMethod
) {
394 ULONG ref
= IMediaSample_AddRef(sample
);
395 ISampleGrabberCB_SampleCB(This
->grabberIface
, time
, sample
);
396 ref
= IMediaSample_Release(sample
) + 1 - ref
;
399 ERR("(%p) Callback referenced sample %p by %u\n", This
, sample
, ref
);
400 /* ugly as hell but some apps are sooo buggy */
402 IMediaSample_Release(sample
);
409 LONG size
= IMediaSample_GetActualDataLength(sample
);
410 if (size
&& SUCCEEDED(IMediaSample_GetPointer(sample
, &data
)) && data
)
411 ISampleGrabberCB_BufferCB(This
->grabberIface
, time
, data
, size
);
417 FIXME("unsupported method %d\n", This
->grabberMethod
);
418 /* do not bother us again */
419 This
->grabberMethod
= -1;
424 /* SampleGrabber implementation of IBaseFilter interface */
427 static HRESULT WINAPI
428 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
430 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
431 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
436 SampleGrabber_IBaseFilter_AddRef(IBaseFilter
*iface
)
438 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
439 return IUnknown_AddRef(This
->outer_unk
);
444 SampleGrabber_IBaseFilter_Release(IBaseFilter
*iface
)
446 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
447 return IUnknown_Release(This
->outer_unk
);
451 static HRESULT WINAPI
452 SampleGrabber_IBaseFilter_Stop(IBaseFilter
*iface
)
454 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
455 TRACE("(%p)\n", This
);
456 This
->filter
.state
= State_Stopped
;
461 static HRESULT WINAPI
462 SampleGrabber_IBaseFilter_Pause(IBaseFilter
*iface
)
464 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
465 TRACE("(%p)\n", This
);
466 This
->filter
.state
= State_Paused
;
471 static HRESULT WINAPI
472 SampleGrabber_IBaseFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
474 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
475 TRACE("(%p)\n", This
);
476 This
->filter
.state
= State_Running
;
481 static HRESULT WINAPI
482 SampleGrabber_IBaseFilter_FindPin(IBaseFilter
*iface
, LPCWSTR id
, IPin
**pin
)
484 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
485 TRACE("(%p)->(%s, %p)\n", This
, debugstr_w(id
), pin
);
488 if (!lstrcmpiW(id
,pin_in_name
))
490 *pin
= &This
->pin_in
.IPin_iface
;
494 else if (!lstrcmpiW(id
,pin_out_name
))
496 *pin
= &This
->pin_out
.IPin_iface
;
501 return VFW_E_NOT_FOUND
;
505 static HRESULT WINAPI
506 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*graph
, LPCWSTR name
)
508 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
510 TRACE("(%p)->(%p, %s)\n", This
, graph
, debugstr_w(name
));
512 BaseFilterImpl_JoinFilterGraph(iface
, graph
, name
);
513 This
->oneShot
= OneShot_None
;
519 static HRESULT WINAPI
520 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter
*iface
, LPWSTR
*vendor
)
522 TRACE("(%p)\n", vendor
);
525 *vendor
= CoTaskMemAlloc(sizeof(vendor_name
));
526 CopyMemory(*vendor
, vendor_name
, sizeof(vendor_name
));
531 /* SampleGrabber implementation of ISampleGrabber interface */
534 static HRESULT WINAPI
535 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber
*iface
, REFIID riid
, void **ppv
)
537 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
538 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
543 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber
*iface
)
545 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
546 return IUnknown_AddRef(This
->outer_unk
);
551 SampleGrabber_ISampleGrabber_Release(ISampleGrabber
*iface
)
553 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
554 return IUnknown_Release(This
->outer_unk
);
558 static HRESULT WINAPI
559 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber
*iface
, BOOL oneShot
)
561 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
562 TRACE("(%p)->(%u)\n", This
, oneShot
);
563 This
->oneShot
= oneShot
? OneShot_Wait
: OneShot_None
;
568 static HRESULT WINAPI
569 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber
*iface
, const AM_MEDIA_TYPE
*type
)
571 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
572 TRACE("(%p)->(%p)\n", This
, type
);
575 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
576 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
578 debugstr_guid(&type
->formattype
), type
->cbFormat
);
579 if (This
->mtype
.pbFormat
)
580 CoTaskMemFree(This
->mtype
.pbFormat
);
582 This
->mtype
.pUnk
= NULL
;
583 if (type
->cbFormat
) {
584 This
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
585 CopyMemory(This
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
588 This
->mtype
.pbFormat
= NULL
;
593 static HRESULT WINAPI
594 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber
*iface
, AM_MEDIA_TYPE
*type
)
596 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
597 TRACE("(%p)->(%p)\n", This
, type
);
600 if (!This
->pin_in
.pair
)
601 return VFW_E_NOT_CONNECTED
;
603 if (type
->cbFormat
) {
604 type
->pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
605 CopyMemory(type
->pbFormat
, This
->mtype
.pbFormat
, type
->cbFormat
);
611 static HRESULT WINAPI
612 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber
*iface
, BOOL bufferEm
)
614 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
615 TRACE("(%p)->(%u)\n", This
, bufferEm
);
616 EnterCriticalSection(&This
->filter
.csFilter
);
618 if (This
->bufferLen
< 0)
622 This
->bufferLen
= -1;
623 LeaveCriticalSection(&This
->filter
.csFilter
);
628 static HRESULT WINAPI
629 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber
*iface
, LONG
*bufSize
, LONG
*buffer
)
631 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
633 TRACE("(%p)->(%p, %p)\n", This
, bufSize
, buffer
);
636 EnterCriticalSection(&This
->filter
.csFilter
);
637 if (!This
->pin_in
.pair
)
638 ret
= VFW_E_NOT_CONNECTED
;
639 else if (This
->bufferLen
< 0)
641 else if (This
->bufferLen
== 0)
642 ret
= VFW_E_WRONG_STATE
;
645 if (*bufSize
>= This
->bufferLen
)
646 CopyMemory(buffer
, This
->bufferData
, This
->bufferLen
);
650 *bufSize
= This
->bufferLen
;
652 LeaveCriticalSection(&This
->filter
.csFilter
);
657 static HRESULT WINAPI
658 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber
*iface
, IMediaSample
**sample
)
660 /* MS doesn't implement it either, no one should call it */
661 WARN("(%p): not implemented\n", sample
);
666 static HRESULT WINAPI
667 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber
*iface
, ISampleGrabberCB
*cb
, LONG whichMethod
)
669 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
670 TRACE("(%p)->(%p, %u)\n", This
, cb
, whichMethod
);
671 if (This
->grabberIface
)
672 ISampleGrabberCB_Release(This
->grabberIface
);
673 This
->grabberIface
= cb
;
674 This
->grabberMethod
= whichMethod
;
676 ISampleGrabberCB_AddRef(cb
);
681 /* SampleGrabber implementation of IMemInputPin interface */
684 static HRESULT WINAPI
685 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin
*iface
, REFIID riid
, void **ppv
)
687 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
688 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
693 SampleGrabber_IMemInputPin_AddRef(IMemInputPin
*iface
)
695 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
696 return IUnknown_AddRef(This
->outer_unk
);
701 SampleGrabber_IMemInputPin_Release(IMemInputPin
*iface
)
703 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
704 return IUnknown_Release(This
->outer_unk
);
708 static HRESULT WINAPI
709 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin
*iface
, IMemAllocator
**allocator
)
711 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
712 TRACE("(%p)->(%p) allocator = %p\n", This
, allocator
, This
->allocator
);
715 *allocator
= This
->allocator
;
717 return VFW_E_NO_ALLOCATOR
;
718 IMemAllocator_AddRef(*allocator
);
723 static HRESULT WINAPI
724 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin
*iface
, IMemAllocator
*allocator
, BOOL readOnly
)
726 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
727 TRACE("(%p)->(%p, %u) allocator = %p\n", This
, allocator
, readOnly
, This
->allocator
);
728 if (This
->allocator
== allocator
)
731 IMemAllocator_Release(This
->allocator
);
732 This
->allocator
= allocator
;
734 IMemAllocator_AddRef(allocator
);
739 static HRESULT WINAPI
740 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
742 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
743 FIXME("(%p)->(%p): semi-stub\n", This
, props
);
746 return This
->memOutput
? IMemInputPin_GetAllocatorRequirements(This
->memOutput
, props
) : E_NOTIMPL
;
750 static HRESULT WINAPI
751 SampleGrabber_IMemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*sample
)
753 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
755 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This
, sample
, This
->memOutput
, This
->grabberIface
);
758 if ((This
->filter
.state
!= State_Running
) || (This
->oneShot
== OneShot_Past
))
760 SampleGrabber_callback(This
, sample
);
761 hr
= This
->memOutput
? IMemInputPin_Receive(This
->memOutput
, sample
) : S_OK
;
762 if (This
->oneShot
== OneShot_Wait
) {
763 This
->oneShot
= OneShot_Past
;
765 if (This
->pin_out
.pair
)
766 IPin_EndOfStream(This
->pin_out
.pair
);
772 static HRESULT WINAPI
773 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin
*iface
, IMediaSample
**samples
, LONG nSamples
, LONG
*nProcessed
)
775 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
777 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This
, samples
, nSamples
, nProcessed
, This
->memOutput
, This
->grabberIface
);
778 if (!samples
|| !nProcessed
)
780 if ((This
->filter
.state
!= State_Running
) || (This
->oneShot
== OneShot_Past
))
782 for (idx
= 0; idx
< nSamples
; idx
++)
783 SampleGrabber_callback(This
, samples
[idx
]);
784 return This
->memOutput
? IMemInputPin_ReceiveMultiple(This
->memOutput
, samples
, nSamples
, nProcessed
) : S_OK
;
788 static HRESULT WINAPI
789 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
791 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
792 TRACE("(%p)\n", This
);
793 return This
->memOutput
? IMemInputPin_ReceiveCanBlock(This
->memOutput
) : S_OK
;
797 /* SampleGrabber member pin implementation */
801 SampleGrabber_IPin_AddRef(IPin
*iface
)
803 SG_Pin
*This
= impl_from_IPin(iface
);
804 return ISampleGrabber_AddRef(&This
->sg
->ISampleGrabber_iface
);
809 SampleGrabber_IPin_Release(IPin
*iface
)
811 SG_Pin
*This
= impl_from_IPin(iface
);
812 return ISampleGrabber_Release(&This
->sg
->ISampleGrabber_iface
);
816 static HRESULT WINAPI
817 SampleGrabber_IPin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
819 SG_Pin
*This
= impl_from_IPin(iface
);
820 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
823 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPin
))
825 else if (IsEqualIID(riid
, &IID_IMemInputPin
))
826 *ppv
= &This
->sg
->IMemInputPin_iface
;
827 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
828 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
829 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
830 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
832 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
833 return E_NOINTERFACE
;
836 IUnknown_AddRef((IUnknown
*)*ppv
);
840 /* IPin - input pin */
841 static HRESULT WINAPI
842 SampleGrabber_In_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*mtype
)
844 WARN("(%p, %p): unexpected\n", receiver
, mtype
);
848 /* IPin - output pin */
849 static HRESULT WINAPI
850 SampleGrabber_Out_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*type
)
852 SG_Pin
*This
= impl_from_IPin(iface
);
855 TRACE("(%p)->(%p, %p)\n", This
, receiver
, type
);
859 return VFW_E_ALREADY_CONNECTED
;
860 if (This
->sg
->filter
.state
!= State_Stopped
)
861 return VFW_E_NOT_STOPPED
;
863 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
864 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
866 debugstr_guid(&type
->formattype
), type
->cbFormat
);
867 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
868 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
869 return VFW_E_TYPE_NOT_ACCEPTED
;
870 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
871 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
872 return VFW_E_TYPE_NOT_ACCEPTED
;
873 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
874 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
875 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
876 return VFW_E_TYPE_NOT_ACCEPTED
;
879 type
= &This
->sg
->mtype
;
880 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
881 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
883 return VFW_E_TYPE_NOT_ACCEPTED
;
884 hr
= IPin_ReceiveConnection(receiver
, &This
->IPin_iface
, type
);
887 This
->pair
= receiver
;
888 if (This
->sg
->memOutput
) {
889 IMemInputPin_Release(This
->sg
->memOutput
);
890 This
->sg
->memOutput
= NULL
;
892 IPin_QueryInterface(receiver
,&IID_IMemInputPin
,(void **)&(This
->sg
->memOutput
));
893 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This
, receiver
, This
->sg
->memOutput
);
897 /* IPin - input pin */
898 static HRESULT WINAPI
899 SampleGrabber_In_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*type
)
901 SG_Pin
*This
= impl_from_IPin(iface
);
903 TRACE("(%p)->(%p, %p)\n", This
, connector
, type
);
907 return VFW_E_ALREADY_CONNECTED
;
908 if (This
->sg
->filter
.state
!= State_Stopped
)
909 return VFW_E_NOT_STOPPED
;
911 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
912 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
914 debugstr_guid(&type
->formattype
), type
->cbFormat
);
915 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
916 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
918 return VFW_E_INVALIDMEDIATYPE
;
919 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
920 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
921 return VFW_E_TYPE_NOT_ACCEPTED
;
922 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
923 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
924 return VFW_E_TYPE_NOT_ACCEPTED
;
925 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
926 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
927 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
928 return VFW_E_TYPE_NOT_ACCEPTED
;
929 if (This
->sg
->mtype
.pbFormat
)
930 CoTaskMemFree(This
->sg
->mtype
.pbFormat
);
931 This
->sg
->mtype
= *type
;
932 This
->sg
->mtype
.pUnk
= NULL
;
933 if (type
->cbFormat
) {
934 This
->sg
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
935 CopyMemory(This
->sg
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
938 This
->sg
->mtype
.pbFormat
= NULL
;
940 This
->pair
= connector
;
941 TRACE("(%p) Accepted IPin %p\n", This
, connector
);
945 /* IPin - output pin */
946 static HRESULT WINAPI
947 SampleGrabber_Out_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*mtype
)
949 WARN("(%p, %p): unexpected\n", connector
, mtype
);
953 /* IPin - input pin */
954 static HRESULT WINAPI
955 SampleGrabber_In_IPin_Disconnect(IPin
*iface
)
957 SG_Pin
*This
= impl_from_IPin(iface
);
959 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
960 if (This
->sg
->filter
.state
!= State_Stopped
)
961 return VFW_E_NOT_STOPPED
;
969 /* IPin - output pin */
970 static HRESULT WINAPI
971 SampleGrabber_Out_IPin_Disconnect(IPin
*iface
)
973 SG_Pin
*This
= impl_from_IPin(iface
);
975 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
976 if (This
->sg
->filter
.state
!= State_Stopped
)
977 return VFW_E_NOT_STOPPED
;
980 if (This
->sg
->memOutput
) {
981 IMemInputPin_Release(This
->sg
->memOutput
);
982 This
->sg
->memOutput
= NULL
;
990 static HRESULT WINAPI
991 SampleGrabber_IPin_ConnectedTo(IPin
*iface
, IPin
**pin
)
993 SG_Pin
*This
= impl_from_IPin(iface
);
995 TRACE("(%p)->(%p) pair = %p\n", This
, pin
, This
->pair
);
1003 return VFW_E_NOT_CONNECTED
;
1007 static HRESULT WINAPI
1008 SampleGrabber_IPin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*mtype
)
1010 SG_Pin
*This
= impl_from_IPin(iface
);
1012 TRACE("(%p)->(%p)\n", This
, mtype
);
1016 return VFW_E_NOT_CONNECTED
;
1017 *mtype
= This
->sg
->mtype
;
1018 if (mtype
->cbFormat
) {
1019 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
1020 CopyMemory(mtype
->pbFormat
, This
->sg
->mtype
.pbFormat
, mtype
->cbFormat
);
1026 static HRESULT WINAPI
1027 SampleGrabber_IPin_QueryPinInfo(IPin
*iface
, PIN_INFO
*info
)
1029 SG_Pin
*This
= impl_from_IPin(iface
);
1031 TRACE("(%p)->(%p)\n", This
, info
);
1034 info
->pFilter
= &This
->sg
->filter
.IBaseFilter_iface
;
1035 IBaseFilter_AddRef(info
->pFilter
);
1036 info
->dir
= This
->dir
;
1037 lstrcpynW(info
->achName
,This
->name
,MAX_PIN_NAME
);
1042 static HRESULT WINAPI
1043 SampleGrabber_IPin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*dir
)
1045 SG_Pin
*This
= impl_from_IPin(iface
);
1047 TRACE("(%p)->(%p)\n", This
, dir
);
1055 static HRESULT WINAPI
1056 SampleGrabber_IPin_QueryId(IPin
*iface
, LPWSTR
*id
)
1058 SG_Pin
*This
= impl_from_IPin(iface
);
1061 TRACE("(%p)->(%p)\n", This
, id
);
1064 len
= sizeof(WCHAR
)*(1+lstrlenW(This
->name
));
1065 *id
= CoTaskMemAlloc(len
);
1066 CopyMemory(*id
, This
->name
, len
);
1071 static HRESULT WINAPI
1072 SampleGrabber_IPin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mtype
)
1074 TRACE("(%p)\n", mtype
);
1079 static HRESULT WINAPI
1080 SampleGrabber_IPin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**mtypes
)
1082 SG_Pin
*This
= impl_from_IPin(iface
);
1084 TRACE("(%p)->(%p)\n", This
, mtypes
);
1087 *mtypes
= mediaenum_create(This
->sg
->pin_in
.pair
? &This
->sg
->mtype
: NULL
, FALSE
);
1088 return *mtypes
? S_OK
: E_OUTOFMEMORY
;
1091 /* IPin - input pin */
1092 static HRESULT WINAPI
1093 SampleGrabber_In_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1095 SG_Pin
*This
= impl_from_IPin(iface
);
1097 TRACE("(%p)->(%p, %p) size = %u\n", This
, pins
, nPins
, (nPins
? *nPins
: 0));
1103 IPin_AddRef(&This
->sg
->pin_out
.IPin_iface
);
1104 *pins
= &This
->sg
->pin_out
.IPin_iface
;
1112 /* IPin - output pin */
1113 static HRESULT WINAPI
1114 SampleGrabber_Out_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1116 WARN("(%p, %p): unexpected\n", pins
, nPins
);
1123 static HRESULT WINAPI
1124 SampleGrabber_IPin_EndOfStream(IPin
*iface
)
1131 static HRESULT WINAPI
1132 SampleGrabber_IPin_BeginFlush(IPin
*iface
)
1139 static HRESULT WINAPI
1140 SampleGrabber_IPin_EndFlush(IPin
*iface
)
1147 static HRESULT WINAPI
1148 SampleGrabber_IPin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double rate
)
1155 /* SampleGrabber vtables and constructor */
1157 static const IBaseFilterVtbl IBaseFilter_VTable
=
1159 SampleGrabber_IBaseFilter_QueryInterface
,
1160 SampleGrabber_IBaseFilter_AddRef
,
1161 SampleGrabber_IBaseFilter_Release
,
1162 BaseFilterImpl_GetClassID
,
1163 SampleGrabber_IBaseFilter_Stop
,
1164 SampleGrabber_IBaseFilter_Pause
,
1165 SampleGrabber_IBaseFilter_Run
,
1166 BaseFilterImpl_GetState
,
1167 BaseFilterImpl_SetSyncSource
,
1168 BaseFilterImpl_GetSyncSource
,
1169 BaseFilterImpl_EnumPins
,
1170 SampleGrabber_IBaseFilter_FindPin
,
1171 BaseFilterImpl_QueryFilterInfo
,
1172 SampleGrabber_IBaseFilter_JoinFilterGraph
,
1173 SampleGrabber_IBaseFilter_QueryVendorInfo
,
1176 static const ISampleGrabberVtbl ISampleGrabber_VTable
=
1178 SampleGrabber_ISampleGrabber_QueryInterface
,
1179 SampleGrabber_ISampleGrabber_AddRef
,
1180 SampleGrabber_ISampleGrabber_Release
,
1181 SampleGrabber_ISampleGrabber_SetOneShot
,
1182 SampleGrabber_ISampleGrabber_SetMediaType
,
1183 SampleGrabber_ISampleGrabber_GetConnectedMediaType
,
1184 SampleGrabber_ISampleGrabber_SetBufferSamples
,
1185 SampleGrabber_ISampleGrabber_GetCurrentBuffer
,
1186 SampleGrabber_ISampleGrabber_GetCurrentSample
,
1187 SampleGrabber_ISampleGrabber_SetCallback
,
1190 static const IMemInputPinVtbl IMemInputPin_VTable
=
1192 SampleGrabber_IMemInputPin_QueryInterface
,
1193 SampleGrabber_IMemInputPin_AddRef
,
1194 SampleGrabber_IMemInputPin_Release
,
1195 SampleGrabber_IMemInputPin_GetAllocator
,
1196 SampleGrabber_IMemInputPin_NotifyAllocator
,
1197 SampleGrabber_IMemInputPin_GetAllocatorRequirements
,
1198 SampleGrabber_IMemInputPin_Receive
,
1199 SampleGrabber_IMemInputPin_ReceiveMultiple
,
1200 SampleGrabber_IMemInputPin_ReceiveCanBlock
,
1203 static const IPinVtbl IPin_In_VTable
=
1205 SampleGrabber_IPin_QueryInterface
,
1206 SampleGrabber_IPin_AddRef
,
1207 SampleGrabber_IPin_Release
,
1208 SampleGrabber_In_IPin_Connect
,
1209 SampleGrabber_In_IPin_ReceiveConnection
,
1210 SampleGrabber_In_IPin_Disconnect
,
1211 SampleGrabber_IPin_ConnectedTo
,
1212 SampleGrabber_IPin_ConnectionMediaType
,
1213 SampleGrabber_IPin_QueryPinInfo
,
1214 SampleGrabber_IPin_QueryDirection
,
1215 SampleGrabber_IPin_QueryId
,
1216 SampleGrabber_IPin_QueryAccept
,
1217 SampleGrabber_IPin_EnumMediaTypes
,
1218 SampleGrabber_In_IPin_QueryInternalConnections
,
1219 SampleGrabber_IPin_EndOfStream
,
1220 SampleGrabber_IPin_BeginFlush
,
1221 SampleGrabber_IPin_EndFlush
,
1222 SampleGrabber_IPin_NewSegment
,
1225 static const IPinVtbl IPin_Out_VTable
=
1227 SampleGrabber_IPin_QueryInterface
,
1228 SampleGrabber_IPin_AddRef
,
1229 SampleGrabber_IPin_Release
,
1230 SampleGrabber_Out_IPin_Connect
,
1231 SampleGrabber_Out_IPin_ReceiveConnection
,
1232 SampleGrabber_Out_IPin_Disconnect
,
1233 SampleGrabber_IPin_ConnectedTo
,
1234 SampleGrabber_IPin_ConnectionMediaType
,
1235 SampleGrabber_IPin_QueryPinInfo
,
1236 SampleGrabber_IPin_QueryDirection
,
1237 SampleGrabber_IPin_QueryId
,
1238 SampleGrabber_IPin_QueryAccept
,
1239 SampleGrabber_IPin_EnumMediaTypes
,
1240 SampleGrabber_Out_IPin_QueryInternalConnections
,
1241 SampleGrabber_IPin_EndOfStream
,
1242 SampleGrabber_IPin_BeginFlush
,
1243 SampleGrabber_IPin_EndFlush
,
1244 SampleGrabber_IPin_NewSegment
,
1247 HRESULT
SampleGrabber_create(IUnknown
*pUnkOuter
, LPVOID
*ppv
)
1249 SG_Impl
* obj
= NULL
;
1250 ISeekingPassThru
*passthru
;
1253 TRACE("(%p,%p)\n", ppv
, pUnkOuter
);
1255 obj
= CoTaskMemAlloc(sizeof(SG_Impl
));
1258 return E_OUTOFMEMORY
;
1260 ZeroMemory(obj
, sizeof(SG_Impl
));
1262 BaseFilter_Init(&obj
->filter
, &IBaseFilter_VTable
, &CLSID_SampleGrabber
,
1263 (DWORD_PTR
)(__FILE__
": SG_Impl.csFilter"), &basefunc_vtbl
);
1264 obj
->IUnknown_inner
.lpVtbl
= &samplegrabber_vtbl
;
1265 obj
->ISampleGrabber_iface
.lpVtbl
= &ISampleGrabber_VTable
;
1266 obj
->IMemInputPin_iface
.lpVtbl
= &IMemInputPin_VTable
;
1267 obj
->pin_in
.IPin_iface
.lpVtbl
= &IPin_In_VTable
;
1268 obj
->pin_in
.dir
= PINDIR_INPUT
;
1269 obj
->pin_in
.name
= pin_in_name
;
1270 obj
->pin_in
.sg
= obj
;
1271 obj
->pin_in
.pair
= NULL
;
1272 obj
->pin_out
.IPin_iface
.lpVtbl
= &IPin_Out_VTable
;
1273 obj
->pin_out
.dir
= PINDIR_OUTPUT
;
1274 obj
->pin_out
.name
= pin_out_name
;
1275 obj
->pin_out
.sg
= obj
;
1276 obj
->pin_out
.pair
= NULL
;
1277 obj
->mtype
.majortype
= GUID_NULL
;
1278 obj
->mtype
.subtype
= MEDIASUBTYPE_None
;
1279 obj
->mtype
.formattype
= FORMAT_None
;
1280 obj
->allocator
= NULL
;
1281 obj
->memOutput
= NULL
;
1282 obj
->grabberIface
= NULL
;
1283 obj
->grabberMethod
= -1;
1284 obj
->oneShot
= OneShot_None
;
1285 obj
->bufferLen
= -1;
1286 obj
->bufferData
= NULL
;
1289 obj
->outer_unk
= pUnkOuter
;
1291 obj
->outer_unk
= &obj
->IUnknown_inner
;
1293 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)obj
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&obj
->seekthru_unk
);
1296 IUnknown_QueryInterface(obj
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
1297 ISeekingPassThru_Init(passthru
, FALSE
, &obj
->pin_in
.IPin_iface
);
1298 ISeekingPassThru_Release(passthru
);
1300 *ppv
= &obj
->IUnknown_inner
;