2 * Transform Filter (Base for decoders, etc...)
4 * Copyright 2005 Christian Costa
5 * Copyright 2010 Aric Stewart, CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "strmbase_private.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(strmbase
);
26 static const WCHAR wcsInputPinName
[] = {'I','n',0};
27 static const WCHAR wcsOutputPinName
[] = {'O','u','t',0};
29 static inline TransformFilter
*impl_from_strmbase_filter(struct strmbase_filter
*iface
)
31 return CONTAINING_RECORD(iface
, TransformFilter
, filter
);
34 static inline TransformFilter
*impl_from_sink_IPin(IPin
*iface
)
36 return CONTAINING_RECORD(iface
, TransformFilter
, sink
.pin
.IPin_iface
);
39 static HRESULT
sink_query_accept(struct strmbase_pin
*iface
, const AM_MEDIA_TYPE
*pmt
)
41 TransformFilter
*pTransform
= impl_from_sink_IPin(&iface
->IPin_iface
);
45 if (pTransform
->pFuncsTable
->pfnCheckInputType
)
46 return pTransform
->pFuncsTable
->pfnCheckInputType(pTransform
, pmt
);
47 /* Assume OK if there's no query method (the connection will fail if
52 static HRESULT WINAPI
TransformFilter_Input_Receive(struct strmbase_sink
*This
, IMediaSample
*pInSample
)
54 TransformFilter
*pTransform
= impl_from_sink_IPin(&This
->pin
.IPin_iface
);
59 /* We do not expect pin connection state to change while the filter is
60 * running. This guarantee is necessary, since otherwise we would have to
61 * take the filter lock, and we can't take the filter lock from a streaming
63 if (!pTransform
->source
.pMemInputPin
)
65 WARN("Source is not connected, returning VFW_E_NOT_CONNECTED.\n");
66 return VFW_E_NOT_CONNECTED
;
69 EnterCriticalSection(&pTransform
->csReceive
);
70 if (pTransform
->filter
.state
== State_Stopped
)
72 LeaveCriticalSection(&pTransform
->csReceive
);
73 return VFW_E_WRONG_STATE
;
78 LeaveCriticalSection(&pTransform
->csReceive
);
82 if (pTransform
->pFuncsTable
->pfnReceive
)
83 hr
= pTransform
->pFuncsTable
->pfnReceive(pTransform
, pInSample
);
87 LeaveCriticalSection(&pTransform
->csReceive
);
91 static inline TransformFilter
*impl_from_source_IPin(IPin
*iface
)
93 return CONTAINING_RECORD(iface
, TransformFilter
, source
.pin
.IPin_iface
);
96 static HRESULT
source_query_accept(struct strmbase_pin
*This
, const AM_MEDIA_TYPE
*pmt
)
98 TransformFilter
*pTransformFilter
= impl_from_source_IPin(&This
->IPin_iface
);
99 AM_MEDIA_TYPE
* outpmt
= &pTransformFilter
->pmt
;
101 if (IsEqualIID(&pmt
->majortype
, &outpmt
->majortype
)
102 && (IsEqualIID(&pmt
->subtype
, &outpmt
->subtype
) || IsEqualIID(&outpmt
->subtype
, &GUID_NULL
)))
107 static HRESULT WINAPI
TransformFilter_Output_DecideBufferSize(struct strmbase_source
*This
,
108 IMemAllocator
*pAlloc
, ALLOCATOR_PROPERTIES
*ppropInputRequest
)
110 TransformFilter
*pTransformFilter
= impl_from_source_IPin(&This
->pin
.IPin_iface
);
111 return pTransformFilter
->pFuncsTable
->pfnDecideBufferSize(pTransformFilter
, pAlloc
, ppropInputRequest
);
114 static HRESULT
source_get_media_type(struct strmbase_pin
*This
, unsigned int iPosition
, AM_MEDIA_TYPE
*pmt
)
116 TransformFilter
*pTransform
= impl_from_source_IPin(&This
->IPin_iface
);
119 return VFW_S_NO_MORE_ITEMS
;
120 CopyMediaType(pmt
, &pTransform
->pmt
);
124 static struct strmbase_pin
*transform_get_pin(struct strmbase_filter
*iface
, unsigned int index
)
126 TransformFilter
*filter
= impl_from_strmbase_filter(iface
);
129 return &filter
->sink
.pin
;
131 return &filter
->source
.pin
;
135 static void transform_destroy(struct strmbase_filter
*iface
)
137 TransformFilter
*filter
= impl_from_strmbase_filter(iface
);
139 if (filter
->sink
.pin
.peer
)
140 IPin_Disconnect(filter
->sink
.pin
.peer
);
141 IPin_Disconnect(&filter
->sink
.pin
.IPin_iface
);
143 if (filter
->source
.pin
.peer
)
144 IPin_Disconnect(filter
->source
.pin
.peer
);
145 IPin_Disconnect(&filter
->source
.pin
.IPin_iface
);
147 strmbase_sink_cleanup(&filter
->sink
);
148 strmbase_source_cleanup(&filter
->source
);
150 filter
->csReceive
.DebugInfo
->Spare
[0] = 0;
151 DeleteCriticalSection(&filter
->csReceive
);
152 FreeMediaType(&filter
->pmt
);
153 IUnknown_Release(filter
->seekthru_unk
);
154 strmbase_filter_cleanup(&filter
->filter
);
155 CoTaskMemFree(filter
);
158 static HRESULT
transform_init_stream(struct strmbase_filter
*iface
)
160 TransformFilter
*filter
= impl_from_strmbase_filter(iface
);
163 EnterCriticalSection(&filter
->csReceive
);
165 if (filter
->pFuncsTable
->pfnStartStreaming
)
166 hr
= filter
->pFuncsTable
->pfnStartStreaming(filter
);
168 hr
= BaseOutputPinImpl_Active(&filter
->source
);
170 LeaveCriticalSection(&filter
->csReceive
);
175 static HRESULT
transform_cleanup_stream(struct strmbase_filter
*iface
)
177 TransformFilter
*filter
= impl_from_strmbase_filter(iface
);
180 EnterCriticalSection(&filter
->csReceive
);
182 if (filter
->pFuncsTable
->pfnStopStreaming
)
183 hr
= filter
->pFuncsTable
->pfnStopStreaming(filter
);
185 hr
= BaseOutputPinImpl_Inactive(&filter
->source
);
187 LeaveCriticalSection(&filter
->csReceive
);
192 static const struct strmbase_filter_ops filter_ops
=
194 .filter_get_pin
= transform_get_pin
,
195 .filter_destroy
= transform_destroy
,
196 .filter_init_stream
= transform_init_stream
,
197 .filter_cleanup_stream
= transform_cleanup_stream
,
200 static HRESULT
sink_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
202 TransformFilter
*filter
= impl_from_sink_IPin(&iface
->IPin_iface
);
204 if (IsEqualGUID(iid
, &IID_IMemInputPin
))
205 *out
= &filter
->sink
.IMemInputPin_iface
;
207 return E_NOINTERFACE
;
209 IUnknown_AddRef((IUnknown
*)*out
);
213 static HRESULT
sink_connect(struct strmbase_sink
*iface
, IPin
*peer
, const AM_MEDIA_TYPE
*mt
)
215 TransformFilter
*filter
= impl_from_sink_IPin(&iface
->pin
.IPin_iface
);
217 if (filter
->pFuncsTable
->transform_connect_sink
)
218 return filter
->pFuncsTable
->transform_connect_sink(filter
, mt
);
222 static void sink_disconnect(struct strmbase_sink
*iface
)
224 TransformFilter
*filter
= impl_from_sink_IPin(&iface
->pin
.IPin_iface
);
226 if (filter
->pFuncsTable
->pfnBreakConnect
)
227 filter
->pFuncsTable
->pfnBreakConnect(filter
, PINDIR_INPUT
);
230 static HRESULT
sink_eos(struct strmbase_sink
*iface
)
232 TransformFilter
*filter
= impl_from_sink_IPin(&iface
->pin
.IPin_iface
);
234 if (filter
->source
.pin
.peer
)
235 return IPin_EndOfStream(filter
->source
.pin
.peer
);
236 return VFW_E_NOT_CONNECTED
;
239 static HRESULT
sink_begin_flush(struct strmbase_sink
*iface
)
241 TransformFilter
*filter
= impl_from_sink_IPin(&iface
->pin
.IPin_iface
);
244 if (filter
->pFuncsTable
->pfnBeginFlush
)
245 hr
= filter
->pFuncsTable
->pfnBeginFlush(filter
);
246 if (SUCCEEDED(hr
) && filter
->source
.pin
.peer
)
247 hr
= IPin_BeginFlush(filter
->source
.pin
.peer
);
251 static HRESULT
sink_end_flush(struct strmbase_sink
*iface
)
253 TransformFilter
*filter
= impl_from_sink_IPin(&iface
->pin
.IPin_iface
);
256 if (filter
->pFuncsTable
->pfnEndFlush
)
257 hr
= filter
->pFuncsTable
->pfnEndFlush(filter
);
258 if (SUCCEEDED(hr
) && filter
->source
.pin
.peer
)
259 hr
= IPin_EndFlush(filter
->source
.pin
.peer
);
263 static HRESULT
sink_new_segment(struct strmbase_sink
*iface
,
264 REFERENCE_TIME start
, REFERENCE_TIME stop
, double rate
)
266 TransformFilter
*filter
= impl_from_sink_IPin(&iface
->pin
.IPin_iface
);
269 if (filter
->pFuncsTable
->pfnNewSegment
)
270 hr
= filter
->pFuncsTable
->pfnNewSegment(filter
, start
, stop
, rate
);
271 if (SUCCEEDED(hr
) && filter
->source
.pin
.peer
)
272 hr
= IPin_NewSegment(filter
->source
.pin
.peer
, start
, stop
, rate
);
276 static const struct strmbase_sink_ops sink_ops
=
278 .base
.pin_query_accept
= sink_query_accept
,
279 .base
.pin_get_media_type
= strmbase_pin_get_media_type
,
280 .base
.pin_query_interface
= sink_query_interface
,
281 .pfnReceive
= TransformFilter_Input_Receive
,
282 .sink_connect
= sink_connect
,
283 .sink_disconnect
= sink_disconnect
,
284 .sink_eos
= sink_eos
,
285 .sink_begin_flush
= sink_begin_flush
,
286 .sink_end_flush
= sink_end_flush
,
287 .sink_new_segment
= sink_new_segment
,
290 static HRESULT
source_query_interface(struct strmbase_pin
*iface
, REFIID iid
, void **out
)
292 TransformFilter
*filter
= impl_from_source_IPin(&iface
->IPin_iface
);
294 if (IsEqualGUID(iid
, &IID_IQualityControl
))
295 *out
= &filter
->source_IQualityControl_iface
;
296 else if (IsEqualGUID(iid
, &IID_IMediaSeeking
))
297 return IUnknown_QueryInterface(filter
->seekthru_unk
, iid
, out
);
299 return E_NOINTERFACE
;
301 IUnknown_AddRef((IUnknown
*)*out
);
305 static const struct strmbase_source_ops source_ops
=
307 .base
.pin_query_accept
= source_query_accept
,
308 .base
.pin_get_media_type
= source_get_media_type
,
309 .base
.pin_query_interface
= source_query_interface
,
310 .pfnAttemptConnection
= BaseOutputPinImpl_AttemptConnection
,
311 .pfnDecideBufferSize
= TransformFilter_Output_DecideBufferSize
,
312 .pfnDecideAllocator
= BaseOutputPinImpl_DecideAllocator
,
315 static TransformFilter
*impl_from_source_IQualityControl(IQualityControl
*iface
)
317 return CONTAINING_RECORD(iface
, TransformFilter
, source_IQualityControl_iface
);
320 static HRESULT WINAPI
transform_source_qc_QueryInterface(IQualityControl
*iface
,
321 REFIID iid
, void **out
)
323 TransformFilter
*filter
= impl_from_source_IQualityControl(iface
);
324 return IPin_QueryInterface(&filter
->source
.pin
.IPin_iface
, iid
, out
);
327 static ULONG WINAPI
transform_source_qc_AddRef(IQualityControl
*iface
)
329 TransformFilter
*filter
= impl_from_source_IQualityControl(iface
);
330 return IPin_AddRef(&filter
->source
.pin
.IPin_iface
);
333 static ULONG WINAPI
transform_source_qc_Release(IQualityControl
*iface
)
335 TransformFilter
*filter
= impl_from_source_IQualityControl(iface
);
336 return IPin_Release(&filter
->source
.pin
.IPin_iface
);
339 HRESULT WINAPI
TransformFilterImpl_Notify(TransformFilter
*filter
, IBaseFilter
*sender
, Quality q
)
341 IQualityControl
*peer
;
342 HRESULT hr
= S_FALSE
;
344 if (filter
->source_qc_sink
)
345 return IQualityControl_Notify(filter
->source_qc_sink
, &filter
->filter
.IBaseFilter_iface
, q
);
347 if (filter
->sink
.pin
.peer
348 && SUCCEEDED(IPin_QueryInterface(filter
->sink
.pin
.peer
, &IID_IQualityControl
, (void **)&peer
)))
350 hr
= IQualityControl_Notify(peer
, &filter
->filter
.IBaseFilter_iface
, q
);
351 IQualityControl_Release(peer
);
356 static HRESULT WINAPI
transform_source_qc_Notify(IQualityControl
*iface
,
357 IBaseFilter
*sender
, Quality q
)
359 TransformFilter
*filter
= impl_from_source_IQualityControl(iface
);
361 TRACE("filter %p, sender %p, type %#x, proportion %u, late %s, timestamp %s.\n",
362 filter
, sender
, q
.Type
, q
.Proportion
, debugstr_time(q
.Late
), debugstr_time(q
.TimeStamp
));
364 if (filter
->pFuncsTable
->pfnNotify
)
365 return filter
->pFuncsTable
->pfnNotify(filter
, sender
, q
);
366 return TransformFilterImpl_Notify(filter
, sender
, q
);
369 static HRESULT WINAPI
transform_source_qc_SetSink(IQualityControl
*iface
, IQualityControl
*sink
)
371 TransformFilter
*filter
= impl_from_source_IQualityControl(iface
);
373 TRACE("filter %p, sink %p.\n", filter
, sink
);
375 filter
->source_qc_sink
= sink
;
380 static const IQualityControlVtbl source_qc_vtbl
=
382 transform_source_qc_QueryInterface
,
383 transform_source_qc_AddRef
,
384 transform_source_qc_Release
,
385 transform_source_qc_Notify
,
386 transform_source_qc_SetSink
,
389 static HRESULT
strmbase_transform_init(IUnknown
*outer
, const CLSID
*clsid
,
390 const TransformFilterFuncTable
*func_table
, TransformFilter
*filter
)
392 ISeekingPassThru
*passthru
;
395 strmbase_filter_init(&filter
->filter
, outer
, clsid
, &filter_ops
);
397 InitializeCriticalSection(&filter
->csReceive
);
398 filter
->csReceive
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TransformFilter.csReceive");
400 /* pTransformFilter is already allocated */
401 filter
->pFuncsTable
= func_table
;
402 ZeroMemory(&filter
->pmt
, sizeof(filter
->pmt
));
404 strmbase_sink_init(&filter
->sink
, &filter
->filter
, wcsInputPinName
, &sink_ops
, NULL
);
406 strmbase_source_init(&filter
->source
, &filter
->filter
, wcsOutputPinName
, &source_ops
);
407 filter
->source_IQualityControl_iface
.lpVtbl
= &source_qc_vtbl
;
409 filter
->seekthru_unk
= NULL
;
410 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)&filter
->filter
.IBaseFilter_iface
,
411 CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void **)&filter
->seekthru_unk
);
414 IUnknown_QueryInterface(filter
->seekthru_unk
, &IID_ISeekingPassThru
, (void **)&passthru
);
415 ISeekingPassThru_Init(passthru
, FALSE
, &filter
->sink
.pin
.IPin_iface
);
416 ISeekingPassThru_Release(passthru
);
421 strmbase_sink_cleanup(&filter
->sink
);
422 strmbase_source_cleanup(&filter
->source
);
423 strmbase_filter_cleanup(&filter
->filter
);
429 HRESULT
strmbase_transform_create(LONG filter_size
, IUnknown
*outer
, const CLSID
*pClsid
,
430 const TransformFilterFuncTable
*pFuncsTable
, IBaseFilter
**ppTransformFilter
)
432 TransformFilter
* pTf
;
434 *ppTransformFilter
= NULL
;
436 assert(filter_size
>= sizeof(TransformFilter
));
438 pTf
= CoTaskMemAlloc(filter_size
);
441 return E_OUTOFMEMORY
;
443 ZeroMemory(pTf
, filter_size
);
445 if (SUCCEEDED(strmbase_transform_init(outer
, pClsid
, pFuncsTable
, pTf
)))
447 *ppTransformFilter
= &pTf
->filter
.IBaseFilter_iface
;