ReactOS 0.4.17-dev-966-gf06eace
smartteefilter.c
Go to the documentation of this file.
1/*
2 * Implementation of the SmartTee filter
3 *
4 * Copyright 2015 Damjan Jovanovic
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21#include "qcap_private.h"
22
24
25typedef struct {
28 struct strmbase_source capture, preview;
30
32{
34}
35
37{
38 return impl_from_strmbase_filter(pin->filter);
39}
40
41static struct strmbase_pin *smart_tee_get_pin(struct strmbase_filter *iface, unsigned int index)
42{
44
45 if (index == 0)
46 return &filter->sink.pin;
47 else if (index == 1)
48 return &filter->capture.pin;
49 else if (index == 2)
50 return &filter->preview.pin;
51 return NULL;
52}
53
54static void smart_tee_destroy(struct strmbase_filter *iface)
55{
57
62 free(filter);
63}
64
66{
67 return iface->state == State_Paused ? VFW_S_CANT_CUE : S_OK;
68}
69
70static const struct strmbase_filter_ops filter_ops =
71{
72 .filter_get_pin = smart_tee_get_pin,
73 .filter_destroy = smart_tee_destroy,
74 .filter_wait_state = smart_tee_wait_state,
75};
76
78{
80 TRACE("(%p, AM_MEDIA_TYPE(%p))\n", This, pmt);
81 if (!pmt)
83 /* We'll take any media type, but the output pins will later
84 * struggle to connect downstream. */
85 return S_OK;
86}
87
89 unsigned int iPosition, AM_MEDIA_TYPE *amt)
90{
92 HRESULT hr;
93 TRACE("(%p)->(%d, %p)\n", This, iPosition, amt);
94 if (iPosition)
95 return S_FALSE;
96 EnterCriticalSection(&This->filter.filter_cs);
97 if (This->sink.pin.peer)
98 {
99 CopyMediaType(amt, &This->sink.pin.mt);
100 hr = S_OK;
101 }
102 else
103 hr = S_FALSE;
104 LeaveCriticalSection(&This->filter.filter_cs);
105 return hr;
106}
107
108static HRESULT sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
109{
111
112 if (IsEqualGUID(iid, &IID_IMemInputPin))
113 *out = &filter->sink.IMemInputPin_iface;
114 else
115 return E_NOINTERFACE;
116
117 IUnknown_AddRef((IUnknown *)*out);
118 return S_OK;
119}
120
122{
123 REFERENCE_TIME startTime, endTime;
124 BOOL haveStartTime = TRUE, haveEndTime = TRUE;
125 IMediaSample *outputSample = NULL;
126 BYTE *ptrIn, *ptrOut;
127 AM_MEDIA_TYPE *mediaType = NULL;
128 HRESULT hr;
129
130 hr = IMediaSample_GetTime(inputSample, &startTime, &endTime);
131 if (hr == S_OK)
132 ;
133 else if (hr == VFW_S_NO_STOP_TIME)
134 haveEndTime = FALSE;
135 else if (hr == VFW_E_SAMPLE_TIME_NOT_SET)
136 haveStartTime = haveEndTime = FALSE;
137 else
138 goto end;
139
140 hr = IMemAllocator_GetBuffer(allocator, &outputSample,
141 haveStartTime ? &startTime : NULL, haveEndTime ? &endTime : NULL, 0);
142 if (FAILED(hr)) goto end;
143 if (IMediaSample_GetSize(outputSample) < IMediaSample_GetActualDataLength(inputSample)) {
144 ERR("insufficient space in sample\n");
146 goto end;
147 }
148
149 hr = IMediaSample_SetTime(outputSample, haveStartTime ? &startTime : NULL, haveEndTime ? &endTime : NULL);
150 if (FAILED(hr)) goto end;
151
152 hr = IMediaSample_GetPointer(inputSample, &ptrIn);
153 if (FAILED(hr)) goto end;
154 hr = IMediaSample_GetPointer(outputSample, &ptrOut);
155 if (FAILED(hr)) goto end;
156 memcpy(ptrOut, ptrIn, IMediaSample_GetActualDataLength(inputSample));
157 IMediaSample_SetActualDataLength(outputSample, IMediaSample_GetActualDataLength(inputSample));
158
159 hr = IMediaSample_SetDiscontinuity(outputSample, IMediaSample_IsDiscontinuity(inputSample) == S_OK);
160 if (FAILED(hr)) goto end;
161
162 haveStartTime = haveEndTime = TRUE;
163 hr = IMediaSample_GetMediaTime(inputSample, &startTime, &endTime);
164 if (hr == S_OK)
165 ;
166 else if (hr == VFW_S_NO_STOP_TIME)
167 haveEndTime = FALSE;
168 else if (hr == VFW_E_MEDIA_TIME_NOT_SET)
169 haveStartTime = haveEndTime = FALSE;
170 else
171 goto end;
172 hr = IMediaSample_SetMediaTime(outputSample, haveStartTime ? &startTime : NULL, haveEndTime ? &endTime : NULL);
173 if (FAILED(hr)) goto end;
174
175 hr = IMediaSample_GetMediaType(inputSample, &mediaType);
176 if (FAILED(hr)) goto end;
177 if (hr == S_OK) {
178 hr = IMediaSample_SetMediaType(outputSample, mediaType);
179 if (FAILED(hr)) goto end;
180 }
181
182 hr = IMediaSample_SetPreroll(outputSample, IMediaSample_IsPreroll(inputSample) == S_OK);
183 if (FAILED(hr)) goto end;
184
185 hr = IMediaSample_SetSyncPoint(outputSample, IMediaSample_IsSyncPoint(inputSample) == S_OK);
186 if (FAILED(hr)) goto end;
187
188end:
189 if (mediaType)
190 DeleteMediaType(mediaType);
191 if (FAILED(hr) && outputSample) {
192 IMediaSample_Release(outputSample);
193 outputSample = NULL;
194 }
195 *pOutputSample = outputSample;
196 return hr;
197}
198
200{
202 IMediaSample *captureSample = NULL;
203 IMediaSample *previewSample = NULL;
204 HRESULT hrCapture = VFW_E_NOT_CONNECTED, hrPreview = VFW_E_NOT_CONNECTED;
205
206 TRACE("(%p)->(%p)\n", This, inputSample);
207
208 /* Modifying the image coming out of one pin doesn't modify the image
209 * coming out of the other. MSDN claims the filter doesn't copy,
210 * but unless it somehow uses copy-on-write, I just don't see how
211 * that's possible. */
212
213 /* FIXME: we should ideally do each of these in a separate thread */
214 EnterCriticalSection(&This->filter.filter_cs);
215 if (This->capture.pin.peer)
216 hrCapture = copy_sample(inputSample, This->capture.pAllocator, &captureSample);
217 LeaveCriticalSection(&This->filter.filter_cs);
218 if (SUCCEEDED(hrCapture) && This->capture.pMemInputPin)
219 hrCapture = IMemInputPin_Receive(This->capture.pMemInputPin, captureSample);
220 if (captureSample)
221 IMediaSample_Release(captureSample);
222
223 EnterCriticalSection(&This->filter.filter_cs);
224 if (This->preview.pin.peer)
225 hrPreview = copy_sample(inputSample, This->preview.pAllocator, &previewSample);
226 LeaveCriticalSection(&This->filter.filter_cs);
227 /* No timestamps on preview stream: */
228 if (SUCCEEDED(hrPreview))
229 hrPreview = IMediaSample_SetTime(previewSample, NULL, NULL);
230 if (SUCCEEDED(hrPreview) && This->preview.pMemInputPin)
231 hrPreview = IMemInputPin_Receive(This->preview.pMemInputPin, previewSample);
232 if (previewSample)
233 IMediaSample_Release(previewSample);
234
235 /* FIXME: how to merge the HRESULTs from the 2 pins? */
236 if (SUCCEEDED(hrCapture))
237 return hrCapture;
238 else
239 return hrPreview;
240}
241
242static const struct strmbase_sink_ops sink_ops =
243{
244 .base.pin_query_accept = sink_query_accept,
245 .base.pin_get_media_type = sink_get_media_type,
246 .base.pin_query_interface = sink_query_interface,
247 .pfnReceive = SmartTeeFilterInput_Receive,
248};
249
251{
252 FIXME("(%p) stub\n", base);
253 return S_OK;
254}
255
257 unsigned int index, AM_MEDIA_TYPE *mt)
258{
260 HRESULT hr = S_OK;
261
263
264 if (!filter->sink.pin.peer)
266 else if (!index)
267 CopyMediaType(mt, &filter->sink.pin.mt);
268 else
270
272 return hr;
273}
274
276 IMemInputPin *pPin, IMemAllocator **pAlloc)
277{
279 TRACE("(%p, %p, %p)\n", This, pPin, pAlloc);
280 *pAlloc = This->sink.pAllocator;
281 IMemAllocator_AddRef(This->sink.pAllocator);
282 return IMemInputPin_NotifyAllocator(pPin, This->sink.pAllocator, TRUE);
283}
284
285static const struct strmbase_source_ops capture_ops =
286{
287 .base.pin_query_accept = capture_query_accept,
288 .base.pin_get_media_type = source_get_media_type,
289 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
290 .pfnDecideAllocator = SmartTeeFilterCapture_DecideAllocator,
291};
292
294{
295 FIXME("(%p) stub\n", base);
296 return S_OK;
297}
298
300 IMemInputPin *pPin, IMemAllocator **pAlloc)
301{
303 TRACE("(%p, %p, %p)\n", This, pPin, pAlloc);
304 *pAlloc = This->sink.pAllocator;
305 IMemAllocator_AddRef(This->sink.pAllocator);
306 return IMemInputPin_NotifyAllocator(pPin, This->sink.pAllocator, TRUE);
307}
308
309static const struct strmbase_source_ops preview_ops =
310{
311 .base.pin_query_accept = preview_query_accept,
312 .base.pin_get_media_type = source_get_media_type,
313 .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
314 .pfnDecideAllocator = SmartTeeFilterPreview_DecideAllocator,
315};
316
318{
320 HRESULT hr;
321
322 if (!(object = calloc(1, sizeof(*object))))
323 return E_OUTOFMEMORY;
324
325 strmbase_filter_init(&object->filter, outer, &CLSID_SmartTee, &filter_ops);
326 strmbase_sink_init(&object->sink, &object->filter, L"Input", &sink_ops, NULL);
327 hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER,
328 &IID_IMemAllocator, (void **)&object->sink.pAllocator);
329 if (FAILED(hr))
330 {
332 free(object);
333 return hr;
334 }
335
336 strmbase_source_init(&object->capture, &object->filter, L"Capture", &capture_ops);
337 strmbase_source_init(&object->preview, &object->filter, L"Preview", &preview_ops);
338
339 TRACE("Created smart tee %p.\n", object);
340 *out = &object->filter.IUnknown_inner;
341 return S_OK;
342}
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
static previewinfo preview
Definition: print.c:56
#define FIXME(fmt,...)
Definition: precomp.h:53
#define ERR(fmt,...)
Definition: precomp.h:57
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define free
Definition: debug_ros.c:5
HRESULT hr
Definition: delayimp.cpp:582
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context, REFIID riid, void **obj)
Definition: combase.c:1685
static ULONGLONG startTime
Definition: main.c:113
LONGLONG REFERENCE_TIME
Definition: dmusicks.h:9
#define L(x)
Definition: resources.c:13
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint end
Definition: gl.h:1545
GLuint index
Definition: glext.h:6031
GLsizei GLenum GLboolean sink
Definition: glext.h:5672
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static IUnknown * outer
Definition: compobj.c:82
#define IsEqualGUID(rguid1, rguid2)
Definition: guiddef.h:147
#define REFIID
Definition: guiddef.h:118
#define calloc
Definition: rosglue.h:14
static HRESULT sink_get_media_type(struct strmbase_pin *base, unsigned int iPosition, AM_MEDIA_TYPE *amt)
static SmartTeeFilter * impl_from_strmbase_filter(struct strmbase_filter *filter)
static void smart_tee_destroy(struct strmbase_filter *iface)
static SmartTeeFilter * impl_from_strmbase_pin(struct strmbase_pin *pin)
static struct strmbase_pin * smart_tee_get_pin(struct strmbase_filter *iface, unsigned int index)
static HRESULT WINAPI SmartTeeFilterCapture_DecideAllocator(struct strmbase_source *base, IMemInputPin *pPin, IMemAllocator **pAlloc)
static HRESULT WINAPI SmartTeeFilterInput_Receive(struct strmbase_sink *base, IMediaSample *inputSample)
static const struct strmbase_source_ops preview_ops
static HRESULT source_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt)
static HRESULT WINAPI SmartTeeFilterPreview_DecideAllocator(struct strmbase_source *base, IMemInputPin *pPin, IMemAllocator **pAlloc)
static const struct strmbase_sink_ops sink_ops
static HRESULT capture_query_accept(struct strmbase_pin *base, const AM_MEDIA_TYPE *amt)
static HRESULT sink_query_accept(struct strmbase_pin *base, const AM_MEDIA_TYPE *pmt)
static const struct strmbase_filter_ops filter_ops
static HRESULT smart_tee_wait_state(struct strmbase_filter *iface, DWORD timeout)
static HRESULT copy_sample(IMediaSample *inputSample, IMemAllocator *allocator, IMediaSample **pOutputSample)
HRESULT smart_tee_create(IUnknown *outer, IUnknown **out)
static HRESULT preview_query_accept(struct strmbase_pin *base, const AM_MEDIA_TYPE *amt)
static const struct strmbase_source_ops capture_ops
static HRESULT sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out)
#define TRACE(s)
Definition: solgame.cpp:4
HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *pDest, const AM_MEDIA_TYPE *pSrc)
Definition: mediatype.c:150
void strmbase_source_init(struct strmbase_source *pin, struct strmbase_filter *filter, const WCHAR *name, const struct strmbase_source_ops *func_table)
Definition: pin.c:765
void strmbase_sink_cleanup(struct strmbase_sink *pin)
Definition: pin.c:1185
void strmbase_sink_init(struct strmbase_sink *pin, struct strmbase_filter *filter, const WCHAR *name, const struct strmbase_sink_ops *ops, IMemAllocator *allocator)
Definition: pin.c:1168
void strmbase_filter_cleanup(struct strmbase_filter *filter)
Definition: filter.c:540
void strmbase_source_cleanup(struct strmbase_source *pin)
Definition: pin.c:778
void strmbase_filter_init(struct strmbase_filter *filter, IUnknown *outer, const CLSID *clsid, const struct strmbase_filter_ops *func_table)
Definition: filter.c:517
HRESULT WINAPI BaseOutputPinImpl_AttemptConnection(struct strmbase_source *pin, IPin *peer, const AM_MEDIA_TYPE *mt)
Definition: pin.c:710
void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pMediaType)
Definition: mediatype.c:193
Definition: filter.c:165
IBaseFilter * filter
Definition: filtergraph.c:75
FILTER_STATE state
Definition: strmbase.h:151
struct strmbase_pin pin
Definition: strmbase.h:79
Definition: dhcpd.h:248
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
#define VFW_E_SAMPLE_TIME_NOT_SET
Definition: vfwmsgs.h:104
#define VFW_E_MEDIA_TIME_NOT_SET
Definition: vfwmsgs.h:105
#define VFW_E_TYPE_NOT_ACCEPTED
Definition: vfwmsgs.h:81
#define VFW_S_CANT_CUE
Definition: vfwmsgs.h:33
#define VFW_S_NO_STOP_TIME
Definition: vfwmsgs.h:34
#define VFW_E_BUFFER_OVERFLOW
Definition: vfwmsgs.h:52
#define VFW_S_NO_MORE_ITEMS
Definition: vfwmsgs.h:19
#define VFW_E_NOT_CONNECTED
Definition: vfwmsgs.h:48
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define WINAPI
Definition: msvc.h:6
#define S_FALSE
Definition: winerror.h:3451
#define E_NOINTERFACE
Definition: winerror.h:3479
unsigned char BYTE
Definition: xxhash.c:193