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 /* IEnumMediaTypes */
101 static HRESULT WINAPI
Single_IEnumMediaTypes_Next(IEnumMediaTypes
*iface
, ULONG nTypes
,
102 AM_MEDIA_TYPE
**types
, ULONG
*fetched
)
104 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
107 TRACE("(%p)->(%u, %p, %p)\n", This
, nTypes
, types
, fetched
);
110 if (!types
|| ((nTypes
!= 1) && !fetched
))
112 if (!This
->past
&& !IsEqualGUID(&This
->mtype
.majortype
,&GUID_NULL
)) {
113 AM_MEDIA_TYPE
*mtype
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
));
114 *mtype
= This
->mtype
;
115 if (mtype
->cbFormat
) {
116 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
117 CopyMemory(mtype
->pbFormat
, This
->mtype
.pbFormat
, mtype
->cbFormat
);
125 return (count
== nTypes
) ? S_OK
: S_FALSE
;
128 static HRESULT WINAPI
Single_IEnumMediaTypes_Skip(IEnumMediaTypes
*iface
, ULONG nTypes
)
130 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
132 TRACE("(%p)->(%u)\n", This
, nTypes
);
135 return This
->past
? S_FALSE
: S_OK
;
138 static HRESULT WINAPI
Single_IEnumMediaTypes_Reset(IEnumMediaTypes
*iface
)
140 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
142 TRACE("(%p)->()\n", This
);
147 static HRESULT WINAPI
Single_IEnumMediaTypes_Clone(IEnumMediaTypes
*iface
, IEnumMediaTypes
**me
)
149 ME_Impl
*This
= impl_from_IEnumMediaTypes(iface
);
151 TRACE("(%p)->(%p)\n", This
, me
);
154 *me
= mediaenum_create(&This
->mtype
, This
->past
);
156 return E_OUTOFMEMORY
;
161 /* Virtual tables and constructor */
163 static const IEnumMediaTypesVtbl IEnumMediaTypes_VTable
=
165 Single_IEnumMediaTypes_QueryInterface
,
166 Single_IEnumMediaTypes_AddRef
,
167 Single_IEnumMediaTypes_Release
,
168 Single_IEnumMediaTypes_Next
,
169 Single_IEnumMediaTypes_Skip
,
170 Single_IEnumMediaTypes_Reset
,
171 Single_IEnumMediaTypes_Clone
,
174 static IEnumMediaTypes
*mediaenum_create(const AM_MEDIA_TYPE
*mtype
, BOOL past
)
176 ME_Impl
*obj
= CoTaskMemAlloc(sizeof(ME_Impl
));
180 ZeroMemory(obj
, sizeof(*obj
));
181 obj
->IEnumMediaTypes_iface
.lpVtbl
= &IEnumMediaTypes_VTable
;
186 obj
->mtype
.pUnk
= NULL
;
187 if (mtype
->cbFormat
) {
188 obj
->mtype
.pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
189 CopyMemory(obj
->mtype
.pbFormat
, mtype
->pbFormat
, mtype
->cbFormat
);
192 obj
->mtype
.pbFormat
= NULL
;
195 obj
->mtype
.majortype
= GUID_NULL
;
197 return &obj
->IEnumMediaTypes_iface
;
201 /* Sample Grabber pin implementation */
202 typedef struct _SG_Pin
{
210 static inline SG_Pin
*impl_from_IPin(IPin
*iface
)
212 return CONTAINING_RECORD(iface
, SG_Pin
, IPin_iface
);
215 /* Sample Grabber filter implementation */
216 typedef struct _SG_Impl
{
217 IUnknown IUnknown_inner
;
219 ISampleGrabber ISampleGrabber_iface
;
220 /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */
221 IUnknown
* seekthru_unk
;
226 IMemInputPin IMemInputPin_iface
;
227 IMemAllocator
*allocator
;
228 IMemInputPin
*memOutput
;
229 ISampleGrabberCB
*grabberIface
;
242 static inline SG_Impl
*impl_from_IUnknown(IUnknown
*iface
)
244 return CONTAINING_RECORD(iface
, SG_Impl
, IUnknown_inner
);
247 static inline SG_Impl
*impl_from_BaseFilter(BaseFilter
*iface
)
249 return CONTAINING_RECORD(iface
, SG_Impl
, filter
);
252 static inline SG_Impl
*impl_from_IBaseFilter(IBaseFilter
*iface
)
254 return CONTAINING_RECORD(iface
, SG_Impl
, filter
.IBaseFilter_iface
);
257 static inline SG_Impl
*impl_from_ISampleGrabber(ISampleGrabber
*iface
)
259 return CONTAINING_RECORD(iface
, SG_Impl
, ISampleGrabber_iface
);
262 static inline SG_Impl
*impl_from_IMemInputPin(IMemInputPin
*iface
)
264 return CONTAINING_RECORD(iface
, SG_Impl
, IMemInputPin_iface
);
268 /* Cleanup at end of life */
269 static void SampleGrabber_cleanup(SG_Impl
*This
)
271 TRACE("(%p)\n", This
);
272 if (This
->filter
.filterInfo
.pGraph
)
273 WARN("(%p) still joined to filter graph %p\n", This
, This
->filter
.filterInfo
.pGraph
);
275 IMemAllocator_Release(This
->allocator
);
277 IMemInputPin_Release(This
->memOutput
);
278 if (This
->grabberIface
)
279 ISampleGrabberCB_Release(This
->grabberIface
);
280 if (This
->mtype
.pbFormat
)
281 CoTaskMemFree(This
->mtype
.pbFormat
);
282 if (This
->bufferData
)
283 CoTaskMemFree(This
->bufferData
);
284 if(This
->seekthru_unk
)
285 IUnknown_Release(This
->seekthru_unk
);
288 /* SampleGrabber inner IUnknown */
289 static HRESULT WINAPI
SampleGrabber_QueryInterface(IUnknown
*iface
, REFIID riid
, void **ppv
)
291 SG_Impl
*This
= impl_from_IUnknown(iface
);
293 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
296 if (IsEqualIID(riid
, &IID_IUnknown
))
297 *ppv
= &This
->IUnknown_inner
;
298 else if (IsEqualIID(riid
, &IID_IPersist
) || IsEqualIID(riid
, &IID_IMediaFilter
) ||
299 IsEqualIID(riid
, &IID_IBaseFilter
))
300 *ppv
= &This
->filter
.IBaseFilter_iface
;
301 else if (IsEqualIID(riid
, &IID_ISampleGrabber
))
302 *ppv
= &This
->ISampleGrabber_iface
;
303 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
304 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
305 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
306 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
308 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
311 return E_NOINTERFACE
;
313 IUnknown_AddRef((IUnknown
*)*ppv
);
317 static ULONG WINAPI
SampleGrabber_AddRef(IUnknown
*iface
)
319 SG_Impl
*This
= impl_from_IUnknown(iface
);
320 ULONG ref
= BaseFilterImpl_AddRef(&This
->filter
.IBaseFilter_iface
);
322 TRACE("(%p) ref=%d\n", This
, ref
);
327 static ULONG WINAPI
SampleGrabber_Release(IUnknown
*iface
)
329 SG_Impl
*This
= impl_from_IUnknown(iface
);
330 ULONG ref
= BaseFilterImpl_Release(&This
->filter
.IBaseFilter_iface
);
332 TRACE("(%p) ref=%d\n", This
, ref
);
336 SampleGrabber_cleanup(This
);
343 static const IUnknownVtbl samplegrabber_vtbl
=
345 SampleGrabber_QueryInterface
,
346 SampleGrabber_AddRef
,
347 SampleGrabber_Release
,
350 static IPin
*WINAPI
SampleGrabber_GetPin(BaseFilter
*iface
, int pos
)
352 SG_Impl
*This
= impl_from_BaseFilter(iface
);
356 pin
= &This
->pin_in
.IPin_iface
;
358 pin
= &This
->pin_out
.IPin_iface
;
366 static LONG WINAPI
SampleGrabber_GetPinCount(BaseFilter
*iface
)
371 static const BaseFilterFuncTable basefunc_vtbl
= {
372 SampleGrabber_GetPin
,
373 SampleGrabber_GetPinCount
376 /* Helper that buffers data and/or calls installed sample callbacks */
377 static void SampleGrabber_callback(SG_Impl
*This
, IMediaSample
*sample
)
380 REFERENCE_TIME tStart
, tEnd
;
381 if (This
->bufferLen
>= 0) {
383 LONG size
= IMediaSample_GetActualDataLength(sample
);
384 if (size
>= 0 && SUCCEEDED(IMediaSample_GetPointer(sample
, &data
))) {
387 EnterCriticalSection(&This
->filter
.csFilter
);
388 if (This
->bufferLen
!= size
) {
389 if (This
->bufferData
)
390 CoTaskMemFree(This
->bufferData
);
391 This
->bufferData
= size
? CoTaskMemAlloc(size
) : NULL
;
392 This
->bufferLen
= size
;
395 CopyMemory(This
->bufferData
, data
, size
);
396 LeaveCriticalSection(&This
->filter
.csFilter
);
399 if (!This
->grabberIface
)
401 if (SUCCEEDED(IMediaSample_GetTime(sample
, &tStart
, &tEnd
)))
402 time
= 1e-7 * tStart
;
403 switch (This
->grabberMethod
) {
406 ULONG ref
= IMediaSample_AddRef(sample
);
407 ISampleGrabberCB_SampleCB(This
->grabberIface
, time
, sample
);
408 ref
= IMediaSample_Release(sample
) + 1 - ref
;
411 ERR("(%p) Callback referenced sample %p by %u\n", This
, sample
, ref
);
412 /* ugly as hell but some apps are sooo buggy */
414 IMediaSample_Release(sample
);
421 LONG size
= IMediaSample_GetActualDataLength(sample
);
422 if (size
&& SUCCEEDED(IMediaSample_GetPointer(sample
, &data
)) && data
)
423 ISampleGrabberCB_BufferCB(This
->grabberIface
, time
, data
, size
);
429 FIXME("unsupported method %d\n", This
->grabberMethod
);
430 /* do not bother us again */
431 This
->grabberMethod
= -1;
436 /* SampleGrabber implementation of IBaseFilter interface */
439 static HRESULT WINAPI
440 SampleGrabber_IBaseFilter_QueryInterface(IBaseFilter
*iface
, REFIID riid
, void **ppv
)
442 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
443 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
448 SampleGrabber_IBaseFilter_AddRef(IBaseFilter
*iface
)
450 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
451 return IUnknown_AddRef(This
->outer_unk
);
456 SampleGrabber_IBaseFilter_Release(IBaseFilter
*iface
)
458 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
459 return IUnknown_Release(This
->outer_unk
);
463 static HRESULT WINAPI
464 SampleGrabber_IBaseFilter_Stop(IBaseFilter
*iface
)
466 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
467 TRACE("(%p)\n", This
);
468 This
->filter
.state
= State_Stopped
;
473 static HRESULT WINAPI
474 SampleGrabber_IBaseFilter_Pause(IBaseFilter
*iface
)
476 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
477 TRACE("(%p)\n", This
);
478 This
->filter
.state
= State_Paused
;
483 static HRESULT WINAPI
484 SampleGrabber_IBaseFilter_Run(IBaseFilter
*iface
, REFERENCE_TIME tStart
)
486 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
487 TRACE("(%p)\n", This
);
488 This
->filter
.state
= State_Running
;
493 static HRESULT WINAPI
494 SampleGrabber_IBaseFilter_FindPin(IBaseFilter
*iface
, LPCWSTR id
, IPin
**pin
)
496 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
497 TRACE("(%p)->(%s, %p)\n", This
, debugstr_w(id
), pin
);
500 if (!lstrcmpiW(id
,pin_in_name
))
502 *pin
= &This
->pin_in
.IPin_iface
;
506 else if (!lstrcmpiW(id
,pin_out_name
))
508 *pin
= &This
->pin_out
.IPin_iface
;
513 return VFW_E_NOT_FOUND
;
517 static HRESULT WINAPI
518 SampleGrabber_IBaseFilter_JoinFilterGraph(IBaseFilter
*iface
, IFilterGraph
*graph
, LPCWSTR name
)
520 SG_Impl
*This
= impl_from_IBaseFilter(iface
);
522 TRACE("(%p)->(%p, %s)\n", This
, graph
, debugstr_w(name
));
524 BaseFilterImpl_JoinFilterGraph(iface
, graph
, name
);
525 This
->oneShot
= OneShot_None
;
531 static HRESULT WINAPI
532 SampleGrabber_IBaseFilter_QueryVendorInfo(IBaseFilter
*iface
, LPWSTR
*vendor
)
534 TRACE("(%p)\n", vendor
);
537 *vendor
= CoTaskMemAlloc(sizeof(vendor_name
));
538 CopyMemory(*vendor
, vendor_name
, sizeof(vendor_name
));
543 /* SampleGrabber implementation of ISampleGrabber interface */
546 static HRESULT WINAPI
547 SampleGrabber_ISampleGrabber_QueryInterface(ISampleGrabber
*iface
, REFIID riid
, void **ppv
)
549 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
550 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
555 SampleGrabber_ISampleGrabber_AddRef(ISampleGrabber
*iface
)
557 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
558 return IUnknown_AddRef(This
->outer_unk
);
563 SampleGrabber_ISampleGrabber_Release(ISampleGrabber
*iface
)
565 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
566 return IUnknown_Release(This
->outer_unk
);
570 static HRESULT WINAPI
571 SampleGrabber_ISampleGrabber_SetOneShot(ISampleGrabber
*iface
, BOOL oneShot
)
573 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
574 TRACE("(%p)->(%u)\n", This
, oneShot
);
575 This
->oneShot
= oneShot
? OneShot_Wait
: OneShot_None
;
580 static HRESULT WINAPI
581 SampleGrabber_ISampleGrabber_SetMediaType(ISampleGrabber
*iface
, const AM_MEDIA_TYPE
*type
)
583 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
584 TRACE("(%p)->(%p)\n", This
, type
);
587 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
588 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
590 debugstr_guid(&type
->formattype
), type
->cbFormat
);
591 if (This
->mtype
.pbFormat
)
592 CoTaskMemFree(This
->mtype
.pbFormat
);
594 This
->mtype
.pUnk
= NULL
;
595 if (type
->cbFormat
) {
596 This
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
597 CopyMemory(This
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
600 This
->mtype
.pbFormat
= NULL
;
605 static HRESULT WINAPI
606 SampleGrabber_ISampleGrabber_GetConnectedMediaType(ISampleGrabber
*iface
, AM_MEDIA_TYPE
*type
)
608 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
609 TRACE("(%p)->(%p)\n", This
, type
);
612 if (!This
->pin_in
.pair
)
613 return VFW_E_NOT_CONNECTED
;
615 if (type
->cbFormat
) {
616 type
->pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
617 CopyMemory(type
->pbFormat
, This
->mtype
.pbFormat
, type
->cbFormat
);
623 static HRESULT WINAPI
624 SampleGrabber_ISampleGrabber_SetBufferSamples(ISampleGrabber
*iface
, BOOL bufferEm
)
626 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
627 TRACE("(%p)->(%u)\n", This
, bufferEm
);
628 EnterCriticalSection(&This
->filter
.csFilter
);
630 if (This
->bufferLen
< 0)
634 This
->bufferLen
= -1;
635 LeaveCriticalSection(&This
->filter
.csFilter
);
640 static HRESULT WINAPI
641 SampleGrabber_ISampleGrabber_GetCurrentBuffer(ISampleGrabber
*iface
, LONG
*bufSize
, LONG
*buffer
)
643 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
645 TRACE("(%p)->(%p, %p)\n", This
, bufSize
, buffer
);
648 EnterCriticalSection(&This
->filter
.csFilter
);
649 if (!This
->pin_in
.pair
)
650 ret
= VFW_E_NOT_CONNECTED
;
651 else if (This
->bufferLen
< 0)
653 else if (This
->bufferLen
== 0)
654 ret
= VFW_E_WRONG_STATE
;
657 if (*bufSize
>= This
->bufferLen
)
658 CopyMemory(buffer
, This
->bufferData
, This
->bufferLen
);
662 *bufSize
= This
->bufferLen
;
664 LeaveCriticalSection(&This
->filter
.csFilter
);
669 static HRESULT WINAPI
670 SampleGrabber_ISampleGrabber_GetCurrentSample(ISampleGrabber
*iface
, IMediaSample
**sample
)
672 /* MS doesn't implement it either, no one should call it */
673 WARN("(%p): not implemented\n", sample
);
678 static HRESULT WINAPI
679 SampleGrabber_ISampleGrabber_SetCallback(ISampleGrabber
*iface
, ISampleGrabberCB
*cb
, LONG whichMethod
)
681 SG_Impl
*This
= impl_from_ISampleGrabber(iface
);
682 TRACE("(%p)->(%p, %u)\n", This
, cb
, whichMethod
);
683 if (This
->grabberIface
)
684 ISampleGrabberCB_Release(This
->grabberIface
);
685 This
->grabberIface
= cb
;
686 This
->grabberMethod
= whichMethod
;
688 ISampleGrabberCB_AddRef(cb
);
693 /* SampleGrabber implementation of IMemInputPin interface */
696 static HRESULT WINAPI
697 SampleGrabber_IMemInputPin_QueryInterface(IMemInputPin
*iface
, REFIID riid
, void **ppv
)
699 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
700 return IUnknown_QueryInterface(This
->outer_unk
, riid
, ppv
);
705 SampleGrabber_IMemInputPin_AddRef(IMemInputPin
*iface
)
707 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
708 return IUnknown_AddRef(This
->outer_unk
);
713 SampleGrabber_IMemInputPin_Release(IMemInputPin
*iface
)
715 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
716 return IUnknown_Release(This
->outer_unk
);
720 static HRESULT WINAPI
721 SampleGrabber_IMemInputPin_GetAllocator(IMemInputPin
*iface
, IMemAllocator
**allocator
)
723 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
724 TRACE("(%p)->(%p) allocator = %p\n", This
, allocator
, This
->allocator
);
727 *allocator
= This
->allocator
;
729 return VFW_E_NO_ALLOCATOR
;
730 IMemAllocator_AddRef(*allocator
);
735 static HRESULT WINAPI
736 SampleGrabber_IMemInputPin_NotifyAllocator(IMemInputPin
*iface
, IMemAllocator
*allocator
, BOOL readOnly
)
738 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
739 TRACE("(%p)->(%p, %u) allocator = %p\n", This
, allocator
, readOnly
, This
->allocator
);
740 if (This
->allocator
== allocator
)
743 IMemAllocator_Release(This
->allocator
);
744 This
->allocator
= allocator
;
746 IMemAllocator_AddRef(allocator
);
751 static HRESULT WINAPI
752 SampleGrabber_IMemInputPin_GetAllocatorRequirements(IMemInputPin
*iface
, ALLOCATOR_PROPERTIES
*props
)
754 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
755 FIXME("(%p)->(%p): semi-stub\n", This
, props
);
758 return This
->memOutput
? IMemInputPin_GetAllocatorRequirements(This
->memOutput
, props
) : E_NOTIMPL
;
762 static HRESULT WINAPI
763 SampleGrabber_IMemInputPin_Receive(IMemInputPin
*iface
, IMediaSample
*sample
)
765 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
767 TRACE("(%p)->(%p) output = %p, grabber = %p\n", This
, sample
, This
->memOutput
, This
->grabberIface
);
770 if ((This
->filter
.state
!= State_Running
) || (This
->oneShot
== OneShot_Past
))
772 SampleGrabber_callback(This
, sample
);
773 hr
= This
->memOutput
? IMemInputPin_Receive(This
->memOutput
, sample
) : S_OK
;
774 if (This
->oneShot
== OneShot_Wait
) {
775 This
->oneShot
= OneShot_Past
;
777 if (This
->pin_out
.pair
)
778 IPin_EndOfStream(This
->pin_out
.pair
);
784 static HRESULT WINAPI
785 SampleGrabber_IMemInputPin_ReceiveMultiple(IMemInputPin
*iface
, IMediaSample
**samples
, LONG nSamples
, LONG
*nProcessed
)
787 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
789 TRACE("(%p)->(%p, %u, %p) output = %p, grabber = %p\n", This
, samples
, nSamples
, nProcessed
, This
->memOutput
, This
->grabberIface
);
790 if (!samples
|| !nProcessed
)
792 if ((This
->filter
.state
!= State_Running
) || (This
->oneShot
== OneShot_Past
))
794 for (idx
= 0; idx
< nSamples
; idx
++)
795 SampleGrabber_callback(This
, samples
[idx
]);
796 return This
->memOutput
? IMemInputPin_ReceiveMultiple(This
->memOutput
, samples
, nSamples
, nProcessed
) : S_OK
;
800 static HRESULT WINAPI
801 SampleGrabber_IMemInputPin_ReceiveCanBlock(IMemInputPin
*iface
)
803 SG_Impl
*This
= impl_from_IMemInputPin(iface
);
804 TRACE("(%p)\n", This
);
805 return This
->memOutput
? IMemInputPin_ReceiveCanBlock(This
->memOutput
) : S_OK
;
809 /* SampleGrabber member pin implementation */
813 SampleGrabber_IPin_AddRef(IPin
*iface
)
815 SG_Pin
*This
= impl_from_IPin(iface
);
816 return ISampleGrabber_AddRef(&This
->sg
->ISampleGrabber_iface
);
821 SampleGrabber_IPin_Release(IPin
*iface
)
823 SG_Pin
*This
= impl_from_IPin(iface
);
824 return ISampleGrabber_Release(&This
->sg
->ISampleGrabber_iface
);
828 static HRESULT WINAPI
829 SampleGrabber_IPin_QueryInterface(IPin
*iface
, REFIID riid
, void **ppv
)
831 SG_Pin
*This
= impl_from_IPin(iface
);
832 TRACE("(%p)->(%s %p)\n", This
, debugstr_guid(riid
), ppv
);
835 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IPin
))
837 else if (IsEqualIID(riid
, &IID_IMemInputPin
))
838 *ppv
= &This
->sg
->IMemInputPin_iface
;
839 else if (IsEqualIID(riid
, &IID_IMediaSeeking
))
840 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
841 else if (IsEqualIID(riid
, &IID_IMediaPosition
))
842 return IUnknown_QueryInterface(&This
->sg
->IUnknown_inner
, riid
, ppv
);
844 WARN("(%p, %s,%p): not found\n", This
, debugstr_guid(riid
), ppv
);
845 return E_NOINTERFACE
;
848 IUnknown_AddRef((IUnknown
*)*ppv
);
852 /* IPin - input pin */
853 static HRESULT WINAPI
854 SampleGrabber_In_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*mtype
)
856 WARN("(%p, %p): unexpected\n", receiver
, mtype
);
860 /* IPin - output pin */
861 static HRESULT WINAPI
862 SampleGrabber_Out_IPin_Connect(IPin
*iface
, IPin
*receiver
, const AM_MEDIA_TYPE
*type
)
864 SG_Pin
*This
= impl_from_IPin(iface
);
867 TRACE("(%p)->(%p, %p)\n", This
, receiver
, type
);
871 return VFW_E_ALREADY_CONNECTED
;
872 if (This
->sg
->filter
.state
!= State_Stopped
)
873 return VFW_E_NOT_STOPPED
;
875 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
876 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
878 debugstr_guid(&type
->formattype
), type
->cbFormat
);
879 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
880 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
881 return VFW_E_TYPE_NOT_ACCEPTED
;
882 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
883 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
884 return VFW_E_TYPE_NOT_ACCEPTED
;
885 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
886 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
887 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
888 return VFW_E_TYPE_NOT_ACCEPTED
;
891 type
= &This
->sg
->mtype
;
892 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
893 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
895 return VFW_E_TYPE_NOT_ACCEPTED
;
896 hr
= IPin_ReceiveConnection(receiver
, &This
->IPin_iface
, type
);
899 This
->pair
= receiver
;
900 if (This
->sg
->memOutput
) {
901 IMemInputPin_Release(This
->sg
->memOutput
);
902 This
->sg
->memOutput
= NULL
;
904 IPin_QueryInterface(receiver
,&IID_IMemInputPin
,(void **)&(This
->sg
->memOutput
));
905 TRACE("(%p) Accepted IPin %p, IMemInputPin %p\n", This
, receiver
, This
->sg
->memOutput
);
909 /* IPin - input pin */
910 static HRESULT WINAPI
911 SampleGrabber_In_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*type
)
913 SG_Pin
*This
= impl_from_IPin(iface
);
915 TRACE("(%p)->(%p, %p)\n", This
, connector
, type
);
919 return VFW_E_ALREADY_CONNECTED
;
920 if (This
->sg
->filter
.state
!= State_Stopped
)
921 return VFW_E_NOT_STOPPED
;
923 TRACE("Media type: %s/%s ssize: %u format: %s (%u bytes)\n",
924 debugstr_guid(&type
->majortype
), debugstr_guid(&type
->subtype
),
926 debugstr_guid(&type
->formattype
), type
->cbFormat
);
927 if (!IsEqualGUID(&type
->formattype
, &FORMAT_None
) &&
928 !IsEqualGUID(&type
->formattype
, &GUID_NULL
) &&
930 return VFW_E_INVALIDMEDIATYPE
;
931 if (!IsEqualGUID(&This
->sg
->mtype
.majortype
,&GUID_NULL
) &&
932 !IsEqualGUID(&This
->sg
->mtype
.majortype
,&type
->majortype
))
933 return VFW_E_TYPE_NOT_ACCEPTED
;
934 if (!IsEqualGUID(&This
->sg
->mtype
.subtype
,&MEDIASUBTYPE_None
) &&
935 !IsEqualGUID(&This
->sg
->mtype
.subtype
,&type
->subtype
))
936 return VFW_E_TYPE_NOT_ACCEPTED
;
937 if (!IsEqualGUID(&This
->sg
->mtype
.formattype
,&GUID_NULL
) &&
938 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&FORMAT_None
) &&
939 !IsEqualGUID(&This
->sg
->mtype
.formattype
,&type
->formattype
))
940 return VFW_E_TYPE_NOT_ACCEPTED
;
941 if (This
->sg
->mtype
.pbFormat
)
942 CoTaskMemFree(This
->sg
->mtype
.pbFormat
);
943 This
->sg
->mtype
= *type
;
944 This
->sg
->mtype
.pUnk
= NULL
;
945 if (type
->cbFormat
) {
946 This
->sg
->mtype
.pbFormat
= CoTaskMemAlloc(type
->cbFormat
);
947 CopyMemory(This
->sg
->mtype
.pbFormat
, type
->pbFormat
, type
->cbFormat
);
950 This
->sg
->mtype
.pbFormat
= NULL
;
952 This
->pair
= connector
;
953 TRACE("(%p) Accepted IPin %p\n", This
, connector
);
957 /* IPin - output pin */
958 static HRESULT WINAPI
959 SampleGrabber_Out_IPin_ReceiveConnection(IPin
*iface
, IPin
*connector
, const AM_MEDIA_TYPE
*mtype
)
961 WARN("(%p, %p): unexpected\n", connector
, mtype
);
965 /* IPin - input pin */
966 static HRESULT WINAPI
967 SampleGrabber_In_IPin_Disconnect(IPin
*iface
)
969 SG_Pin
*This
= impl_from_IPin(iface
);
971 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
972 if (This
->sg
->filter
.state
!= State_Stopped
)
973 return VFW_E_NOT_STOPPED
;
981 /* IPin - output pin */
982 static HRESULT WINAPI
983 SampleGrabber_Out_IPin_Disconnect(IPin
*iface
)
985 SG_Pin
*This
= impl_from_IPin(iface
);
987 TRACE("(%p)->() pair = %p\n", This
, This
->pair
);
988 if (This
->sg
->filter
.state
!= State_Stopped
)
989 return VFW_E_NOT_STOPPED
;
992 if (This
->sg
->memOutput
) {
993 IMemInputPin_Release(This
->sg
->memOutput
);
994 This
->sg
->memOutput
= NULL
;
1002 static HRESULT WINAPI
1003 SampleGrabber_IPin_ConnectedTo(IPin
*iface
, IPin
**pin
)
1005 SG_Pin
*This
= impl_from_IPin(iface
);
1007 TRACE("(%p)->(%p) pair = %p\n", This
, pin
, This
->pair
);
1015 return VFW_E_NOT_CONNECTED
;
1019 static HRESULT WINAPI
1020 SampleGrabber_IPin_ConnectionMediaType(IPin
*iface
, AM_MEDIA_TYPE
*mtype
)
1022 SG_Pin
*This
= impl_from_IPin(iface
);
1024 TRACE("(%p)->(%p)\n", This
, mtype
);
1028 return VFW_E_NOT_CONNECTED
;
1029 *mtype
= This
->sg
->mtype
;
1030 if (mtype
->cbFormat
) {
1031 mtype
->pbFormat
= CoTaskMemAlloc(mtype
->cbFormat
);
1032 CopyMemory(mtype
->pbFormat
, This
->sg
->mtype
.pbFormat
, mtype
->cbFormat
);
1038 static HRESULT WINAPI
1039 SampleGrabber_IPin_QueryPinInfo(IPin
*iface
, PIN_INFO
*info
)
1041 SG_Pin
*This
= impl_from_IPin(iface
);
1043 TRACE("(%p)->(%p)\n", This
, info
);
1046 info
->pFilter
= &This
->sg
->filter
.IBaseFilter_iface
;
1047 IBaseFilter_AddRef(info
->pFilter
);
1048 info
->dir
= This
->dir
;
1049 lstrcpynW(info
->achName
,This
->name
,MAX_PIN_NAME
);
1054 static HRESULT WINAPI
1055 SampleGrabber_IPin_QueryDirection(IPin
*iface
, PIN_DIRECTION
*dir
)
1057 SG_Pin
*This
= impl_from_IPin(iface
);
1059 TRACE("(%p)->(%p)\n", This
, dir
);
1067 static HRESULT WINAPI
1068 SampleGrabber_IPin_QueryId(IPin
*iface
, LPWSTR
*id
)
1070 SG_Pin
*This
= impl_from_IPin(iface
);
1073 TRACE("(%p)->(%p)\n", This
, id
);
1076 len
= sizeof(WCHAR
)*(1+lstrlenW(This
->name
));
1077 *id
= CoTaskMemAlloc(len
);
1078 CopyMemory(*id
, This
->name
, len
);
1083 static HRESULT WINAPI
1084 SampleGrabber_IPin_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
*mtype
)
1086 TRACE("(%p)\n", mtype
);
1091 static HRESULT WINAPI
1092 SampleGrabber_IPin_EnumMediaTypes(IPin
*iface
, IEnumMediaTypes
**mtypes
)
1094 SG_Pin
*This
= impl_from_IPin(iface
);
1096 TRACE("(%p)->(%p)\n", This
, mtypes
);
1099 *mtypes
= mediaenum_create(This
->sg
->pin_in
.pair
? &This
->sg
->mtype
: NULL
, FALSE
);
1100 return *mtypes
? S_OK
: E_OUTOFMEMORY
;
1103 /* IPin - input pin */
1104 static HRESULT WINAPI
1105 SampleGrabber_In_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1107 SG_Pin
*This
= impl_from_IPin(iface
);
1109 TRACE("(%p)->(%p, %p) size = %u\n", This
, pins
, nPins
, (nPins
? *nPins
: 0));
1115 IPin_AddRef(&This
->sg
->pin_out
.IPin_iface
);
1116 *pins
= &This
->sg
->pin_out
.IPin_iface
;
1124 /* IPin - output pin */
1125 static HRESULT WINAPI
1126 SampleGrabber_Out_IPin_QueryInternalConnections(IPin
*iface
, IPin
**pins
, ULONG
*nPins
)
1128 WARN("(%p, %p): unexpected\n", pins
, nPins
);
1135 static HRESULT WINAPI
1136 SampleGrabber_IPin_EndOfStream(IPin
*iface
)
1143 static HRESULT WINAPI
1144 SampleGrabber_IPin_BeginFlush(IPin
*iface
)
1151 static HRESULT WINAPI
1152 SampleGrabber_IPin_EndFlush(IPin
*iface
)
1159 static HRESULT WINAPI
1160 SampleGrabber_IPin_NewSegment(IPin
*iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double rate
)
1167 /* SampleGrabber vtables and constructor */
1169 static const IBaseFilterVtbl IBaseFilter_VTable
=
1171 SampleGrabber_IBaseFilter_QueryInterface
,
1172 SampleGrabber_IBaseFilter_AddRef
,
1173 SampleGrabber_IBaseFilter_Release
,
1174 BaseFilterImpl_GetClassID
,
1175 SampleGrabber_IBaseFilter_Stop
,
1176 SampleGrabber_IBaseFilter_Pause
,
1177 SampleGrabber_IBaseFilter_Run
,
1178 BaseFilterImpl_GetState
,
1179 BaseFilterImpl_SetSyncSource
,
1180 BaseFilterImpl_GetSyncSource
,
1181 BaseFilterImpl_EnumPins
,
1182 SampleGrabber_IBaseFilter_FindPin
,
1183 BaseFilterImpl_QueryFilterInfo
,
1184 SampleGrabber_IBaseFilter_JoinFilterGraph
,
1185 SampleGrabber_IBaseFilter_QueryVendorInfo
,
1188 static const ISampleGrabberVtbl ISampleGrabber_VTable
=
1190 SampleGrabber_ISampleGrabber_QueryInterface
,
1191 SampleGrabber_ISampleGrabber_AddRef
,
1192 SampleGrabber_ISampleGrabber_Release
,
1193 SampleGrabber_ISampleGrabber_SetOneShot
,
1194 SampleGrabber_ISampleGrabber_SetMediaType
,
1195 SampleGrabber_ISampleGrabber_GetConnectedMediaType
,
1196 SampleGrabber_ISampleGrabber_SetBufferSamples
,
1197 SampleGrabber_ISampleGrabber_GetCurrentBuffer
,
1198 SampleGrabber_ISampleGrabber_GetCurrentSample
,
1199 SampleGrabber_ISampleGrabber_SetCallback
,
1202 static const IMemInputPinVtbl IMemInputPin_VTable
=
1204 SampleGrabber_IMemInputPin_QueryInterface
,
1205 SampleGrabber_IMemInputPin_AddRef
,
1206 SampleGrabber_IMemInputPin_Release
,
1207 SampleGrabber_IMemInputPin_GetAllocator
,
1208 SampleGrabber_IMemInputPin_NotifyAllocator
,
1209 SampleGrabber_IMemInputPin_GetAllocatorRequirements
,
1210 SampleGrabber_IMemInputPin_Receive
,
1211 SampleGrabber_IMemInputPin_ReceiveMultiple
,
1212 SampleGrabber_IMemInputPin_ReceiveCanBlock
,
1215 static const IPinVtbl IPin_In_VTable
=
1217 SampleGrabber_IPin_QueryInterface
,
1218 SampleGrabber_IPin_AddRef
,
1219 SampleGrabber_IPin_Release
,
1220 SampleGrabber_In_IPin_Connect
,
1221 SampleGrabber_In_IPin_ReceiveConnection
,
1222 SampleGrabber_In_IPin_Disconnect
,
1223 SampleGrabber_IPin_ConnectedTo
,
1224 SampleGrabber_IPin_ConnectionMediaType
,
1225 SampleGrabber_IPin_QueryPinInfo
,
1226 SampleGrabber_IPin_QueryDirection
,
1227 SampleGrabber_IPin_QueryId
,
1228 SampleGrabber_IPin_QueryAccept
,
1229 SampleGrabber_IPin_EnumMediaTypes
,
1230 SampleGrabber_In_IPin_QueryInternalConnections
,
1231 SampleGrabber_IPin_EndOfStream
,
1232 SampleGrabber_IPin_BeginFlush
,
1233 SampleGrabber_IPin_EndFlush
,
1234 SampleGrabber_IPin_NewSegment
,
1237 static const IPinVtbl IPin_Out_VTable
=
1239 SampleGrabber_IPin_QueryInterface
,
1240 SampleGrabber_IPin_AddRef
,
1241 SampleGrabber_IPin_Release
,
1242 SampleGrabber_Out_IPin_Connect
,
1243 SampleGrabber_Out_IPin_ReceiveConnection
,
1244 SampleGrabber_Out_IPin_Disconnect
,
1245 SampleGrabber_IPin_ConnectedTo
,
1246 SampleGrabber_IPin_ConnectionMediaType
,
1247 SampleGrabber_IPin_QueryPinInfo
,
1248 SampleGrabber_IPin_QueryDirection
,
1249 SampleGrabber_IPin_QueryId
,
1250 SampleGrabber_IPin_QueryAccept
,
1251 SampleGrabber_IPin_EnumMediaTypes
,
1252 SampleGrabber_Out_IPin_QueryInternalConnections
,
1253 SampleGrabber_IPin_EndOfStream
,
1254 SampleGrabber_IPin_BeginFlush
,
1255 SampleGrabber_IPin_EndFlush
,
1256 SampleGrabber_IPin_NewSegment
,
1259 HRESULT
SampleGrabber_create(IUnknown
*pUnkOuter
, LPVOID
*ppv
)
1261 SG_Impl
* obj
= NULL
;
1262 ISeekingPassThru
*passthru
;
1265 TRACE("(%p,%p)\n", ppv
, pUnkOuter
);
1267 obj
= CoTaskMemAlloc(sizeof(SG_Impl
));
1270 return E_OUTOFMEMORY
;
1272 ZeroMemory(obj
, sizeof(SG_Impl
));
1274 BaseFilter_Init(&obj
->filter
, &IBaseFilter_VTable
, &CLSID_SampleGrabber
,
1275 (DWORD_PTR
)(__FILE__
": SG_Impl.csFilter"), &basefunc_vtbl
);
1276 obj
->IUnknown_inner
.lpVtbl
= &samplegrabber_vtbl
;
1277 obj
->ISampleGrabber_iface
.lpVtbl
= &ISampleGrabber_VTable
;
1278 obj
->IMemInputPin_iface
.lpVtbl
= &IMemInputPin_VTable
;
1279 obj
->pin_in
.IPin_iface
.lpVtbl
= &IPin_In_VTable
;
1280 obj
->pin_in
.dir
= PINDIR_INPUT
;
1281 obj
->pin_in
.name
= pin_in_name
;
1282 obj
->pin_in
.sg
= obj
;
1283 obj
->pin_in
.pair
= NULL
;
1284 obj
->pin_out
.IPin_iface
.lpVtbl
= &IPin_Out_VTable
;
1285 obj
->pin_out
.dir
= PINDIR_OUTPUT
;
1286 obj
->pin_out
.name
= pin_out_name
;
1287 obj
->pin_out
.sg
= obj
;
1288 obj
->pin_out
.pair
= NULL
;
1289 obj
->mtype
.majortype
= GUID_NULL
;
1290 obj
->mtype
.subtype
= MEDIASUBTYPE_None
;
1291 obj
->mtype
.formattype
= FORMAT_None
;
1292 obj
->allocator
= NULL
;
1293 obj
->memOutput
= NULL
;
1294 obj
->grabberIface
= NULL
;
1295 obj
->grabberMethod
= -1;
1296 obj
->oneShot
= OneShot_None
;
1297 obj
->bufferLen
= -1;
1298 obj
->bufferData
= NULL
;
1301 obj
->outer_unk
= pUnkOuter
;
1303 obj
->outer_unk
= &obj
->IUnknown_inner
;
1305 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)obj
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&obj
->seekthru_unk
);
1308 IUnknown_QueryInterface(obj
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
1309 ISeekingPassThru_Init(passthru
, FALSE
, &obj
->pin_in
.IPin_iface
);
1310 ISeekingPassThru_Release(passthru
);
1312 *ppv
= &obj
->IUnknown_inner
;