Fixes: dd3d68e5d9e54b204168216da2da6bf6d1d8d296 Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- Thanks to Alistair Leslie-Hughes.
dlls/wineqtdecoder/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/dlls/wineqtdecoder/main.c b/dlls/wineqtdecoder/main.c index 6e0dd8c46b5..435951ba933 100644 --- a/dlls/wineqtdecoder/main.c +++ b/dlls/wineqtdecoder/main.c @@ -146,7 +146,6 @@ static struct class_factory video_decoder_cf = {{&class_factory_vtbl}, video_dec HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) { struct class_factory *factory; - HRESULT hr;
TRACE("clsid %s, iid %s, out %p.\n", debugstr_guid(clsid), debugstr_guid(iid), out);
@@ -193,7 +192,7 @@ static const REGFILTER2 reg_qt_splitter = .u.s2.rgPins2 = reg_qt_splitter_pins, };
-static const REGFILTERPINS2 reg_qt_splitter_pins[2] = +static const REGFILTERPINS2 reg_video_decoder_pins[2] = { { .nMediaTypes = 1,
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/quartz/acmwrapper.c | 318 ++++++++++++++++++++++++++++----- dlls/quartz/tests/acmwrapper.c | 20 +-- 2 files changed, 288 insertions(+), 50 deletions(-)
diff --git a/dlls/quartz/acmwrapper.c b/dlls/quartz/acmwrapper.c index aa34f3ae263..df55f094d57 100644 --- a/dlls/quartz/acmwrapper.c +++ b/dlls/quartz/acmwrapper.c @@ -37,8 +37,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz);
typedef struct ACMWrapperImpl { - TransformFilter tf; + struct strmbase_filter filter; + CRITICAL_SECTION stream_cs;
+ struct strmbase_source source; + IQualityControl source_IQualityControl_iface; + IQualityControl *source_qc_sink; + IUnknown *seeking; + + struct strmbase_sink sink; + + AM_MEDIA_TYPE mt; HACMSTREAM has; LPWAVEFORMATEX pWfOut;
@@ -46,14 +55,32 @@ typedef struct ACMWrapperImpl LONGLONG lasttime_sent; } ACMWrapperImpl;
-static inline ACMWrapperImpl *impl_from_TransformFilter( TransformFilter *iface ) +static inline ACMWrapperImpl *impl_from_strmbase_filter(struct strmbase_filter *iface) { - return CONTAINING_RECORD(iface, ACMWrapperImpl, tf); + return CONTAINING_RECORD(iface, ACMWrapperImpl, filter); +} + +static HRESULT acm_wrapper_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) +{ + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface->filter); + + if (IsEqualGUID(iid, &IID_IMemInputPin)) + *out = &filter->sink.IMemInputPin_iface; + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static HRESULT acm_wrapper_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) +{ + return S_OK; }
-static HRESULT WINAPI ACMWrapper_Receive(TransformFilter *tf, IMediaSample *pSample) +static HRESULT WINAPI acm_wrapper_sink_Receive(struct strmbase_sink *iface, IMediaSample *pSample) { - ACMWrapperImpl* This = impl_from_TransformFilter(tf); + ACMWrapperImpl *This = impl_from_strmbase_filter(iface->pin.filter); IMediaSample* pOutSample = NULL; DWORD cbDstStream, cbSrcStream; LPBYTE pbDstStream; @@ -65,10 +92,29 @@ static HRESULT WINAPI ACMWrapper_Receive(TransformFilter *tf, IMediaSample *pSam LONGLONG tStart = -1, tStop = -1, tMed; LONGLONG mtStart = -1, mtStop = -1, mtMed;
+ /* We do not expect pin connection state to change while the filter is + * running. This guarantee is necessary, since otherwise we would have to + * take the filter lock, and we can't take the filter lock from a streaming + * thread. */ + if (!This->source.pMemInputPin) + { + WARN("Source is not connected, returning VFW_E_NOT_CONNECTED.\n"); + return VFW_E_NOT_CONNECTED; + } + + if (This->filter.state == State_Stopped) + return VFW_E_WRONG_STATE; + + if (This->sink.flushing) + return S_FALSE; + + EnterCriticalSection(&This->stream_cs); + hr = IMediaSample_GetPointer(pSample, &pbSrcStream); if (FAILED(hr)) { ERR("Cannot get pointer to sample data (%x)\n", hr); + LeaveCriticalSection(&This->stream_cs); return hr; }
@@ -100,10 +146,11 @@ static HRESULT WINAPI ACMWrapper_Receive(TransformFilter *tf, IMediaSample *pSam
while(hr == S_OK && ash.cbSrcLength) { - hr = BaseOutputPinImpl_GetDeliveryBuffer(&This->tf.source, &pOutSample, NULL, NULL, 0); + hr = BaseOutputPinImpl_GetDeliveryBuffer(&This->source, &pOutSample, NULL, NULL, 0); if (FAILED(hr)) { ERR("Unable to get delivery buffer (%x)\n", hr); + LeaveCriticalSection(&This->stream_cs); return hr; } IMediaSample_SetPreroll(pOutSample, preroll); @@ -198,7 +245,7 @@ static HRESULT WINAPI ACMWrapper_Receive(TransformFilter *tf, IMediaSample *pSam
TRACE("Sample stop time: %s\n", debugstr_time(tStart));
- hr = IMemInputPin_Receive(This->tf.source.pMemInputPin, pOutSample); + hr = IMemInputPin_Receive(This->source.pMemInputPin, pOutSample); if (hr != S_OK && hr != VFW_E_NOT_CONNECTED) { if (FAILED(hr)) ERR("Error sending sample (%x)\n", hr); @@ -220,6 +267,7 @@ error: This->lasttime_real = tStop; This->lasttime_sent = tMed;
+ LeaveCriticalSection(&This->stream_cs); return hr; }
@@ -228,9 +276,9 @@ static BOOL is_audio_subtype(const GUID *guid) return !memcmp(&guid->Data2, &MEDIATYPE_Audio.Data2, sizeof(GUID) - sizeof(int)); }
-static HRESULT acm_wrapper_connect_sink(TransformFilter *iface, const AM_MEDIA_TYPE *mt) +static HRESULT acm_wrapper_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *mt) { - ACMWrapperImpl *filter = impl_from_TransformFilter(iface); + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface->pin.filter); const WAVEFORMATEX *wfx = (WAVEFORMATEX *)mt->pbFormat; HACMSTREAM drv; MMRESULT res; @@ -240,9 +288,9 @@ static HRESULT acm_wrapper_connect_sink(TransformFilter *iface, const AM_MEDIA_T || wfx->wFormatTag == WAVE_FORMAT_PCM || wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) return VFW_E_TYPE_NOT_ACCEPTED;
- CopyMediaType(&filter->tf.pmt, mt); - filter->tf.pmt.subtype.Data1 = WAVE_FORMAT_PCM; - filter->pWfOut = (WAVEFORMATEX *)filter->tf.pmt.pbFormat; + CopyMediaType(&filter->mt, mt); + filter->mt.subtype.Data1 = WAVE_FORMAT_PCM; + filter->pWfOut = (WAVEFORMATEX *)filter->mt.pbFormat; filter->pWfOut->wFormatTag = WAVE_FORMAT_PCM; filter->pWfOut->wBitsPerSample = 16; filter->pWfOut->nBlockAlign = filter->pWfOut->wBitsPerSample * filter->pWfOut->nChannels / 8; @@ -253,7 +301,7 @@ static HRESULT acm_wrapper_connect_sink(TransformFilter *iface, const AM_MEDIA_T if ((res = acmStreamOpen(&drv, NULL, (WAVEFORMATEX *)wfx, filter->pWfOut, NULL, 0, 0, 0))) { ERR("Failed to open stream, error %u.\n", res); - FreeMediaType(&filter->tf.pmt); + FreeMediaType(&filter->mt); return VFW_E_TYPE_NOT_ACCEPTED; }
@@ -262,34 +310,74 @@ static HRESULT acm_wrapper_connect_sink(TransformFilter *iface, const AM_MEDIA_T return S_OK; }
-static HRESULT WINAPI ACMWrapper_BreakConnect(TransformFilter *tf, PIN_DIRECTION dir) +static void acm_wrapper_sink_disconnect(struct strmbase_sink *iface) { - ACMWrapperImpl *This = impl_from_TransformFilter(tf); + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface->pin.filter);
- TRACE("(%p)->(%i)\n", This,dir); + if (filter->has) + acmStreamClose(filter->has, 0); + filter->has = 0; + filter->lasttime_real = filter->lasttime_sent = -1; +}
- if (dir == PINDIR_INPUT) - { - if (This->has) - acmStreamClose(This->has, 0); +static const struct strmbase_sink_ops sink_ops = +{ + .base.pin_query_interface = acm_wrapper_sink_query_interface, + .base.pin_query_accept = acm_wrapper_sink_query_accept, + .base.pin_get_media_type = strmbase_pin_get_media_type, + .pfnReceive = acm_wrapper_sink_Receive, + .sink_connect = acm_wrapper_sink_connect, + .sink_disconnect = acm_wrapper_sink_disconnect, +};
- This->has = 0; - This->lasttime_real = This->lasttime_sent = -1; - } +static HRESULT acm_wrapper_source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) +{ + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface->filter);
+ if (IsEqualGUID(iid, &IID_IQualityControl)) + *out = &filter->source_IQualityControl_iface; + else if (IsEqualGUID(iid, &IID_IMediaSeeking)) + return IUnknown_QueryInterface(filter->seeking, iid, out); + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown *)*out); return S_OK; }
-static HRESULT WINAPI ACMWrapper_DecideBufferSize(TransformFilter *tf, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) +static HRESULT acm_wrapper_source_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) { - ACMWrapperImpl *pACM = impl_from_TransformFilter(tf); + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface->filter); + + if (IsEqualGUID(&mt->majortype, &filter->mt.majortype) + && (IsEqualGUID(&mt->subtype, &filter->mt.subtype) + || IsEqualGUID(&filter->mt.subtype, &GUID_NULL))) + return S_OK; + return S_FALSE; +} + +static HRESULT acm_wrapper_source_get_media_type(struct strmbase_pin *iface, + unsigned int index, AM_MEDIA_TYPE *mt) +{ + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface->filter); + + if (index) + return VFW_S_NO_MORE_ITEMS; + CopyMediaType(mt, &filter->mt); + return S_OK; +} + +static HRESULT WINAPI acm_wrapper_source_DecideBufferSize(struct strmbase_source *iface, + IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) +{ + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface->pin.filter); ALLOCATOR_PROPERTIES actual;
if (!ppropInputRequest->cbAlign) ppropInputRequest->cbAlign = 1;
- if (ppropInputRequest->cbBuffer < pACM->pWfOut->nAvgBytesPerSec / 2) - ppropInputRequest->cbBuffer = pACM->pWfOut->nAvgBytesPerSec / 2; + if (ppropInputRequest->cbBuffer < filter->pWfOut->nAvgBytesPerSec / 2) + ppropInputRequest->cbBuffer = filter->pWfOut->nAvgBytesPerSec / 2;
if (!ppropInputRequest->cBuffers) ppropInputRequest->cBuffers = 1; @@ -297,28 +385,178 @@ static HRESULT WINAPI ACMWrapper_DecideBufferSize(TransformFilter *tf, IMemAlloc return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual); }
-static const TransformFilterFuncTable ACMWrapper_FuncsTable = { - .pfnDecideBufferSize = ACMWrapper_DecideBufferSize, - .pfnReceive = ACMWrapper_Receive, - .transform_connect_sink = acm_wrapper_connect_sink, - .pfnBreakConnect = ACMWrapper_BreakConnect, +static const struct strmbase_source_ops source_ops = +{ + .base.pin_query_interface = acm_wrapper_source_query_interface, + .base.pin_query_accept = acm_wrapper_source_query_accept, + .base.pin_get_media_type = acm_wrapper_source_get_media_type, + .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, + .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, + .pfnDecideBufferSize = acm_wrapper_source_DecideBufferSize, +}; + +static ACMWrapperImpl *impl_from_source_IQualityControl(IQualityControl *iface) +{ + return CONTAINING_RECORD(iface, ACMWrapperImpl, source_IQualityControl_iface); +} + +static HRESULT WINAPI acm_wrapper_source_qc_QueryInterface(IQualityControl *iface, + REFIID iid, void **out) +{ + ACMWrapperImpl *filter = impl_from_source_IQualityControl(iface); + return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out); +} + +static ULONG WINAPI acm_wrapper_source_qc_AddRef(IQualityControl *iface) +{ + ACMWrapperImpl *filter = impl_from_source_IQualityControl(iface); + return IPin_AddRef(&filter->source.pin.IPin_iface); +} + +static ULONG WINAPI acm_wrapper_source_qc_Release(IQualityControl *iface) +{ + ACMWrapperImpl *filter = impl_from_source_IQualityControl(iface); + return IPin_Release(&filter->source.pin.IPin_iface); +} + +static HRESULT WINAPI acm_wrapper_source_qc_Notify(IQualityControl *iface, + IBaseFilter *sender, Quality q) +{ + ACMWrapperImpl *filter = impl_from_source_IQualityControl(iface); + IQualityControl *peer; + HRESULT hr = S_OK; + + TRACE("filter %p, sender %p, type %#x, proportion %u, late %s, timestamp %s.\n", + filter, sender, q.Type, q.Proportion, debugstr_time(q.Late), debugstr_time(q.TimeStamp)); + + if (filter->source_qc_sink) + return IQualityControl_Notify(filter->source_qc_sink, &filter->filter.IBaseFilter_iface, q); + + if (filter->sink.pin.peer + && SUCCEEDED(IPin_QueryInterface(filter->sink.pin.peer, &IID_IQualityControl, (void **)&peer))) + { + hr = IQualityControl_Notify(peer, &filter->filter.IBaseFilter_iface, q); + IQualityControl_Release(peer); + } + return hr; +} + +static HRESULT WINAPI acm_wrapper_source_qc_SetSink(IQualityControl *iface, IQualityControl *sink) +{ + ACMWrapperImpl *filter = impl_from_source_IQualityControl(iface); + + TRACE("filter %p, sink %p.\n", filter, sink); + + filter->source_qc_sink = sink; + + return S_OK; +} + +static const IQualityControlVtbl source_qc_vtbl = +{ + acm_wrapper_source_qc_QueryInterface, + acm_wrapper_source_qc_AddRef, + acm_wrapper_source_qc_Release, + acm_wrapper_source_qc_Notify, + acm_wrapper_source_qc_SetSink, +}; + +static struct strmbase_pin *acm_wrapper_get_pin(struct strmbase_filter *iface, unsigned int index) +{ + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface); + + if (index == 0) + return &filter->sink.pin; + else if (index == 1) + return &filter->source.pin; + return NULL; +} + +static void acm_wrapper_destroy(struct strmbase_filter *iface) +{ + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface); + + if (filter->sink.pin.peer) + IPin_Disconnect(filter->sink.pin.peer); + IPin_Disconnect(&filter->sink.pin.IPin_iface); + + if (filter->source.pin.peer) + IPin_Disconnect(filter->source.pin.peer); + IPin_Disconnect(&filter->source.pin.IPin_iface); + + strmbase_sink_cleanup(&filter->sink); + strmbase_source_cleanup(&filter->source); + + filter->stream_cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&filter->stream_cs); + FreeMediaType(&filter->mt); + IUnknown_Release(filter->seeking); + strmbase_filter_cleanup(&filter->filter); + free(filter); +} + +static HRESULT acm_wrapper_init_stream(struct strmbase_filter *iface) +{ + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface); + + BaseOutputPinImpl_Active(&filter->source); + return S_OK; +} + +static HRESULT acm_wrapper_cleanup_stream(struct strmbase_filter *iface) +{ + ACMWrapperImpl *filter = impl_from_strmbase_filter(iface); + + BaseOutputPinImpl_Inactive(&filter->source); + return S_OK; +} + +static const struct strmbase_filter_ops filter_ops = +{ + .filter_get_pin = acm_wrapper_get_pin, + .filter_destroy = acm_wrapper_destroy, + .filter_init_stream = acm_wrapper_init_stream, + .filter_cleanup_stream = acm_wrapper_cleanup_stream, };
HRESULT ACMWrapper_create(IUnknown *outer, void **out) { + ISeekingPassThru *passthrough; + ACMWrapperImpl *object; HRESULT hr; - ACMWrapperImpl* This;
- *out = NULL; + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY;
- hr = strmbase_transform_create(sizeof(ACMWrapperImpl), outer, &CLSID_ACMWrapper, - &ACMWrapper_FuncsTable, (IBaseFilter **)&This); + strmbase_filter_init(&object->filter, outer, &CLSID_ACMWrapper, &filter_ops);
- if (FAILED(hr)) + InitializeCriticalSection(&object->stream_cs); + object->stream_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": acm_wrapper.stream_cs"); + + strmbase_sink_init(&object->sink, &object->filter, L"In", &sink_ops, NULL); + + strmbase_source_init(&object->source, &object->filter, L"Out", &source_ops); + object->source_IQualityControl_iface.lpVtbl = &source_qc_vtbl; + + if (FAILED(hr = CoCreateInstance(&CLSID_SeekingPassThru, + (IUnknown *)&object->source.pin.IPin_iface, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void **)&object->seeking))) + { + strmbase_sink_cleanup(&object->sink); + strmbase_source_cleanup(&object->source); + strmbase_filter_cleanup(&object->filter); + free(object); return hr; + }
- *out = &This->tf.filter.IUnknown_inner; - This->lasttime_real = This->lasttime_sent = -1; + IUnknown_QueryInterface(object->seeking, &IID_ISeekingPassThru, (void **)&passthrough); + ISeekingPassThru_Init(passthrough, FALSE, &object->sink.pin.IPin_iface); + ISeekingPassThru_Release(passthrough);
- return hr; + object->lasttime_real = object->lasttime_sent = -1; + + TRACE("Created ACM wrapper %p.\n", object); + *out = &object->filter.IUnknown_inner; + + return S_OK; } diff --git a/dlls/quartz/tests/acmwrapper.c b/dlls/quartz/tests/acmwrapper.c index 9c4fe4d0667..31b32b53ac9 100644 --- a/dlls/quartz/tests/acmwrapper.c +++ b/dlls/quartz/tests/acmwrapper.c @@ -446,42 +446,42 @@ static void test_unconnected_filter_state(void) ok(state == State_Stopped, "Got state %u.\n", state);
hr = IBaseFilter_Pause(filter); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IBaseFilter_GetState(filter, 0, &state); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(state == State_Paused, "Got state %u.\n", state); + ok(state == State_Paused, "Got state %u.\n", state);
hr = IBaseFilter_Run(filter, 0); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IBaseFilter_GetState(filter, 0, &state); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(state == State_Running, "Got state %u.\n", state); + ok(state == State_Running, "Got state %u.\n", state);
hr = IBaseFilter_Pause(filter); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IBaseFilter_GetState(filter, 0, &state); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(state == State_Paused, "Got state %u.\n", state); + ok(state == State_Paused, "Got state %u.\n", state);
hr = IBaseFilter_Stop(filter); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IBaseFilter_GetState(filter, 0, &state); ok(hr == S_OK, "Got hr %#x.\n", hr); ok(state == State_Stopped, "Got state %u.\n", state);
hr = IBaseFilter_Run(filter, 0); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IBaseFilter_GetState(filter, 0, &state); ok(hr == S_OK, "Got hr %#x.\n", hr); - todo_wine ok(state == State_Running, "Got state %u.\n", state); + ok(state == State_Running, "Got state %u.\n", state);
hr = IBaseFilter_Stop(filter); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IBaseFilter_GetState(filter, 0, &state); ok(hr == S_OK, "Got hr %#x.\n", hr);
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/quartz/avidec.c | 378 ++++++++++++++++++++++++++++--------- dlls/quartz/tests/avidec.c | 4 +- 2 files changed, 289 insertions(+), 93 deletions(-)
diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index abed957fa6d..4abc715be12 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -38,51 +38,51 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz);
typedef struct AVIDecImpl { - TransformFilter tf; + struct strmbase_filter filter; + CRITICAL_SECTION stream_cs;
+ struct strmbase_source source; + IQualityControl source_IQualityControl_iface; + IUnknown *seeking; + + struct strmbase_sink sink; + + AM_MEDIA_TYPE mt; HIC hvid; BITMAPINFOHEADER* pBihIn; BITMAPINFOHEADER* pBihOut; REFERENCE_TIME late; } AVIDecImpl;
-static inline AVIDecImpl *impl_from_TransformFilter( TransformFilter *iface ) +static AVIDecImpl *impl_from_strmbase_filter(struct strmbase_filter *iface) { - return CONTAINING_RECORD(iface, AVIDecImpl, tf); + return CONTAINING_RECORD(iface, AVIDecImpl, filter); }
-static HRESULT WINAPI AVIDec_StartStreaming(TransformFilter* pTransformFilter) +static HRESULT avi_decompressor_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) { - AVIDecImpl* This = impl_from_TransformFilter(pTransformFilter); - DWORD result; + AVIDecImpl *filter = impl_from_strmbase_filter(iface->filter);
- TRACE("(%p)->()\n", This); - This->late = -1; + if (IsEqualGUID(iid, &IID_IMemInputPin)) + *out = &filter->sink.IMemInputPin_iface; + else + return E_NOINTERFACE;
- result = ICDecompressBegin(This->hvid, This->pBihIn, This->pBihOut); - if (result != ICERR_OK) - { - ERR("Cannot start processing (%d)\n", result); - return E_FAIL; - } + IUnknown_AddRef((IUnknown *)*out); return S_OK; }
-static HRESULT WINAPI AVIDec_EndFlush(TransformFilter *pTransformFilter) { - AVIDecImpl* This = impl_from_TransformFilter(pTransformFilter); - This->late = -1; +static HRESULT avi_decompressor_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) +{ return S_OK; }
-static HRESULT WINAPI AVIDec_NotifyDrop(TransformFilter *pTransformFilter, IBaseFilter *sender, Quality qm) { - AVIDecImpl *This = impl_from_TransformFilter(pTransformFilter); - - EnterCriticalSection(&This->tf.filter.csFilter); - if (qm.Late > 0) - This->late = qm.Late + qm.TimeStamp; - else - This->late = -1; - LeaveCriticalSection(&This->tf.filter.csFilter); +static HRESULT avi_decompressor_sink_end_flush(struct strmbase_sink *iface) +{ + AVIDecImpl *filter = impl_from_strmbase_filter(iface->pin.filter); + filter->late = -1; + if (filter->source.pin.peer) + return IPin_EndFlush(filter->source.pin.peer); return S_OK; }
@@ -98,9 +98,9 @@ static int AVIDec_DropSample(AVIDecImpl *This, REFERENCE_TIME tStart) { return 0; }
-static HRESULT WINAPI AVIDec_Receive(TransformFilter *tf, IMediaSample *pSample) +static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, IMediaSample *pSample) { - AVIDecImpl* This = impl_from_TransformFilter(tf); + AVIDecImpl *This = impl_from_strmbase_filter(iface->pin.filter); HRESULT hr; DWORD res; IMediaSample* pOutSample = NULL; @@ -111,10 +111,29 @@ static HRESULT WINAPI AVIDec_Receive(TransformFilter *tf, IMediaSample *pSample) LONGLONG tStart, tStop; DWORD flags = 0;
+ /* We do not expect pin connection state to change while the filter is + * running. This guarantee is necessary, since otherwise we would have to + * take the filter lock, and we can't take the filter lock from a streaming + * thread. */ + if (!This->source.pMemInputPin) + { + WARN("Source is not connected, returning VFW_E_NOT_CONNECTED.\n"); + return VFW_E_NOT_CONNECTED; + } + + if (This->filter.state == State_Stopped) + return VFW_E_WRONG_STATE; + + if (This->sink.flushing) + return S_FALSE; + + EnterCriticalSection(&This->stream_cs); + hr = IMediaSample_GetPointer(pSample, &pbSrcStream); if (FAILED(hr)) { ERR("Cannot get pointer to sample data (%x)\n", hr); + LeaveCriticalSection(&This->stream_cs); return hr; }
@@ -125,9 +144,10 @@ static HRESULT WINAPI AVIDec_Receive(TransformFilter *tf, IMediaSample *pSample) /* Update input size to match sample size */ This->pBihIn->biSizeImage = cbSrcStream;
- hr = BaseOutputPinImpl_GetDeliveryBuffer(&This->tf.source, &pOutSample, NULL, NULL, 0); + hr = BaseOutputPinImpl_GetDeliveryBuffer(&This->source, &pOutSample, NULL, NULL, 0); if (FAILED(hr)) { ERR("Unable to get delivery buffer (%x)\n", hr); + LeaveCriticalSection(&This->stream_cs); return hr; }
@@ -138,12 +158,14 @@ static HRESULT WINAPI AVIDec_Receive(TransformFilter *tf, IMediaSample *pSample) if (FAILED(hr)) { ERR("Unable to get pointer to buffer (%x)\n", hr); IMediaSample_Release(pOutSample); + LeaveCriticalSection(&This->stream_cs); return hr; } cbDstStream = IMediaSample_GetSize(pOutSample); if (cbDstStream < This->pBihOut->biSizeImage) { ERR("Sample size is too small %d < %d\n", cbDstStream, This->pBihOut->biSizeImage); IMediaSample_Release(pOutSample); + LeaveCriticalSection(&This->stream_cs); return E_FAIL; }
@@ -162,6 +184,7 @@ static HRESULT WINAPI AVIDec_Receive(TransformFilter *tf, IMediaSample *pSample) /* Drop sample if it's intended to be dropped */ if (flags & ICDECOMPRESS_HURRYUP) { IMediaSample_Release(pOutSample); + LeaveCriticalSection(&This->stream_cs); return S_OK; }
@@ -183,36 +206,18 @@ static HRESULT WINAPI AVIDec_Receive(TransformFilter *tf, IMediaSample *pSample) else IMediaSample_SetMediaTime(pOutSample, NULL, NULL);
- hr = IMemInputPin_Receive(This->tf.source.pMemInputPin, pOutSample); + hr = IMemInputPin_Receive(This->source.pMemInputPin, pOutSample); if (hr != S_OK && hr != VFW_E_NOT_CONNECTED) ERR("Error sending sample (%x)\n", hr);
IMediaSample_Release(pOutSample); + LeaveCriticalSection(&This->stream_cs); return hr; }
-static HRESULT WINAPI AVIDec_StopStreaming(TransformFilter* pTransformFilter) +static HRESULT avi_decompressor_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *pmt) { - AVIDecImpl* This = impl_from_TransformFilter(pTransformFilter); - DWORD result; - - TRACE("(%p)->()\n", This); - - if (!This->hvid) - return S_OK; - - result = ICDecompressEnd(This->hvid); - if (result != ICERR_OK) - { - ERR("Cannot stop processing (%d)\n", result); - return E_FAIL; - } - return S_OK; -} - -static HRESULT avi_dec_connect_sink(TransformFilter *tf, const AM_MEDIA_TYPE *pmt) -{ - AVIDecImpl* This = impl_from_TransformFilter(tf); + AVIDecImpl *This = impl_from_strmbase_filter(iface->pin.filter); HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED;
/* Check root (GUID w/o FOURCC) */ @@ -233,12 +238,11 @@ static HRESULT avi_dec_connect_sink(TransformFilter *tf, const AM_MEDIA_TYPE *pm This->hvid = ICLocate(pmt->majortype.Data1, pmt->subtype.Data1, bmi, NULL, ICMODE_DECOMPRESS); if (This->hvid) { - AM_MEDIA_TYPE* outpmt = &This->tf.pmt; const CLSID* outsubtype; DWORD bih_size; DWORD output_depth = bmi->biBitCount; DWORD result; - FreeMediaType(outpmt); + FreeMediaType(&This->mt);
switch(bmi->biBitCount) { @@ -283,13 +287,13 @@ static HRESULT avi_dec_connect_sink(TransformFilter *tf, const AM_MEDIA_TYPE *pm }
/* Update output media type */ - CopyMediaType(outpmt, pmt); - outpmt->subtype = *outsubtype; + CopyMediaType(&This->mt, pmt); + This->mt.subtype = *outsubtype;
if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo)) - memcpy(&(((VIDEOINFOHEADER *)outpmt->pbFormat)->bmiHeader), This->pBihOut, This->pBihOut->biSize); + memcpy(&(((VIDEOINFOHEADER *)This->mt.pbFormat)->bmiHeader), This->pBihOut, This->pBihOut->biSize); else if (IsEqualIID(&pmt->formattype, &FORMAT_VideoInfo2)) - memcpy(&(((VIDEOINFOHEADER2 *)outpmt->pbFormat)->bmiHeader), This->pBihOut, This->pBihOut->biSize); + memcpy(&(((VIDEOINFOHEADER2 *)This->mt.pbFormat)->bmiHeader), This->pBihOut, This->pBihOut->biSize); else assert(0);
@@ -305,29 +309,71 @@ failed: return hr; }
-static HRESULT WINAPI AVIDec_BreakConnect(TransformFilter *tf, PIN_DIRECTION dir) +static void avi_decompressor_sink_disconnect(struct strmbase_sink *iface) { - AVIDecImpl *This = impl_from_TransformFilter(tf); + AVIDecImpl *filter = impl_from_strmbase_filter(iface->pin.filter); + + if (filter->hvid) + ICClose(filter->hvid); + CoTaskMemFree(filter->pBihIn); + CoTaskMemFree(filter->pBihOut); + filter->hvid = NULL; + filter->pBihIn = NULL; + filter->pBihOut = NULL; +}
- TRACE("(%p)->()\n", This); +static const struct strmbase_sink_ops sink_ops = +{ + .base.pin_query_interface = avi_decompressor_sink_query_interface, + .base.pin_query_accept = avi_decompressor_sink_query_accept, + .base.pin_get_media_type = strmbase_pin_get_media_type, + .pfnReceive = avi_decompressor_sink_Receive, + .sink_connect = avi_decompressor_sink_connect, + .sink_disconnect = avi_decompressor_sink_disconnect, + .sink_end_flush = avi_decompressor_sink_end_flush, +};
- if (dir == PINDIR_INPUT) - { - if (This->hvid) - ICClose(This->hvid); - CoTaskMemFree(This->pBihIn); - CoTaskMemFree(This->pBihOut); - This->hvid = NULL; - This->pBihIn = NULL; - This->pBihOut = NULL; - } +static HRESULT avi_decompressor_source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) +{ + AVIDecImpl *filter = impl_from_strmbase_filter(iface->filter); + + if (IsEqualGUID(iid, &IID_IQualityControl)) + *out = &filter->source_IQualityControl_iface; + else if (IsEqualGUID(iid, &IID_IMediaSeeking)) + return IUnknown_QueryInterface(filter->seeking, iid, out); + else + return E_NOINTERFACE;
+ IUnknown_AddRef((IUnknown *)*out); return S_OK; }
-static HRESULT WINAPI AVIDec_DecideBufferSize(TransformFilter *tf, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) +static HRESULT avi_decompressor_source_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) { - AVIDecImpl *pAVI = impl_from_TransformFilter(tf); + AVIDecImpl *filter = impl_from_strmbase_filter(iface->filter); + + if (IsEqualGUID(&mt->majortype, &filter->mt.majortype) + && (IsEqualGUID(&mt->subtype, &filter->mt.subtype) + || IsEqualGUID(&filter->mt.subtype, &GUID_NULL))) + return S_OK; + return S_FALSE; +} + +static HRESULT avi_decompressor_source_get_media_type(struct strmbase_pin *iface, + unsigned int index, AM_MEDIA_TYPE *mt) +{ + AVIDecImpl *filter = impl_from_strmbase_filter(iface->filter); + + if (index) + return VFW_S_NO_MORE_ITEMS; + CopyMediaType(mt, &filter->mt); + return S_OK; +} + +static HRESULT WINAPI avi_decompressor_source_DecideBufferSize(struct strmbase_source *iface, + IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) +{ + AVIDecImpl *pAVI = impl_from_strmbase_filter(iface->pin.filter); ALLOCATOR_PROPERTIES actual;
if (!ppropInputRequest->cbAlign) @@ -342,35 +388,185 @@ static HRESULT WINAPI AVIDec_DecideBufferSize(TransformFilter *tf, IMemAllocator return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual); }
-static const TransformFilterFuncTable AVIDec_FuncsTable = { - .pfnDecideBufferSize = AVIDec_DecideBufferSize, - .pfnStartStreaming = AVIDec_StartStreaming, - .pfnReceive = AVIDec_Receive, - .pfnStopStreaming = AVIDec_StopStreaming, - .transform_connect_sink = avi_dec_connect_sink, - .pfnBreakConnect = AVIDec_BreakConnect, - .pfnEndFlush = AVIDec_EndFlush, - .pfnNotify = AVIDec_NotifyDrop, +static const struct strmbase_source_ops source_ops = +{ + .base.pin_query_interface = avi_decompressor_source_query_interface, + .base.pin_query_accept = avi_decompressor_source_query_accept, + .base.pin_get_media_type = avi_decompressor_source_get_media_type, + .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, + .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, + .pfnDecideBufferSize = avi_decompressor_source_DecideBufferSize, +}; + +static AVIDecImpl *impl_from_source_IQualityControl(IQualityControl *iface) +{ + return CONTAINING_RECORD(iface, AVIDecImpl, source_IQualityControl_iface); +} + +static HRESULT WINAPI acm_wrapper_source_qc_QueryInterface(IQualityControl *iface, + REFIID iid, void **out) +{ + AVIDecImpl *filter = impl_from_source_IQualityControl(iface); + return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out); +} + +static ULONG WINAPI acm_wrapper_source_qc_AddRef(IQualityControl *iface) +{ + AVIDecImpl *filter = impl_from_source_IQualityControl(iface); + return IPin_AddRef(&filter->source.pin.IPin_iface); +} + +static ULONG WINAPI acm_wrapper_source_qc_Release(IQualityControl *iface) +{ + AVIDecImpl *filter = impl_from_source_IQualityControl(iface); + return IPin_Release(&filter->source.pin.IPin_iface); +} + +static HRESULT WINAPI acm_wrapper_source_qc_Notify(IQualityControl *iface, + IBaseFilter *sender, Quality q) +{ + AVIDecImpl *filter = impl_from_source_IQualityControl(iface); + + TRACE("filter %p, sender %p, type %#x, proportion %u, late %s, timestamp %s.\n", + filter, sender, q.Type, q.Proportion, debugstr_time(q.Late), debugstr_time(q.TimeStamp)); + + EnterCriticalSection(&filter->stream_cs); + if (q.Late > 0) + filter->late = q.Late + q.TimeStamp; + else + filter->late = -1; + LeaveCriticalSection(&filter->stream_cs); + return S_OK; +} + +static HRESULT WINAPI acm_wrapper_source_qc_SetSink(IQualityControl *iface, IQualityControl *sink) +{ + AVIDecImpl *filter = impl_from_source_IQualityControl(iface); + + TRACE("filter %p, sink %p.\n", filter, sink); + + return S_OK; +} + +static const IQualityControlVtbl source_qc_vtbl = +{ + acm_wrapper_source_qc_QueryInterface, + acm_wrapper_source_qc_AddRef, + acm_wrapper_source_qc_Release, + acm_wrapper_source_qc_Notify, + acm_wrapper_source_qc_SetSink, +}; + +static struct strmbase_pin *avi_decompressor_get_pin(struct strmbase_filter *iface, unsigned int index) +{ + AVIDecImpl *filter = impl_from_strmbase_filter(iface); + + if (index == 0) + return &filter->sink.pin; + else if (index == 1) + return &filter->source.pin; + return NULL; +} + +static void avi_decompressor_destroy(struct strmbase_filter *iface) +{ + AVIDecImpl *filter = impl_from_strmbase_filter(iface); + + if (filter->sink.pin.peer) + IPin_Disconnect(filter->sink.pin.peer); + IPin_Disconnect(&filter->sink.pin.IPin_iface); + + if (filter->source.pin.peer) + IPin_Disconnect(filter->source.pin.peer); + IPin_Disconnect(&filter->source.pin.IPin_iface); + + strmbase_sink_cleanup(&filter->sink); + strmbase_source_cleanup(&filter->source); + + filter->stream_cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&filter->stream_cs); + FreeMediaType(&filter->mt); + IUnknown_Release(filter->seeking); + strmbase_filter_cleanup(&filter->filter); + free(filter); +} + +static HRESULT avi_decompressor_init_stream(struct strmbase_filter *iface) +{ + AVIDecImpl *filter = impl_from_strmbase_filter(iface); + LRESULT res; + + filter->late = -1; + + if ((res = ICDecompressBegin(filter->hvid, filter->pBihIn, filter->pBihOut))) + { + ERR("ICDecompressBegin() failed, error %ld.\n", res); + return E_FAIL; + } + + BaseOutputPinImpl_Active(&filter->source); + return S_OK; +} + +static HRESULT avi_decompressor_cleanup_stream(struct strmbase_filter *iface) +{ + AVIDecImpl *filter = impl_from_strmbase_filter(iface); + LRESULT res; + + if (filter->hvid && (res = ICDecompressEnd(filter->hvid))) + { + ERR("ICDecompressEnd() failed, error %ld.\n", res); + return E_FAIL; + } + + BaseOutputPinImpl_Inactive(&filter->source); + return S_OK; +} + +static const struct strmbase_filter_ops filter_ops = +{ + .filter_get_pin = avi_decompressor_get_pin, + .filter_destroy = avi_decompressor_destroy, + .filter_init_stream = avi_decompressor_init_stream, + .filter_cleanup_stream = avi_decompressor_cleanup_stream, };
HRESULT AVIDec_create(IUnknown *outer, void **out) { + AVIDecImpl *object; + ISeekingPassThru *passthrough; HRESULT hr; - AVIDecImpl * This;
- *out = NULL; + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY;
- hr = strmbase_transform_create(sizeof(AVIDecImpl), outer, &CLSID_AVIDec, - &AVIDec_FuncsTable, (IBaseFilter **)&This); + strmbase_filter_init(&object->filter, outer, &CLSID_AVIDec, &filter_ops);
- if (FAILED(hr)) + InitializeCriticalSection(&object->stream_cs); + object->stream_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": avi_decompressor.stream_cs"); + + strmbase_sink_init(&object->sink, &object->filter, L"In", &sink_ops, NULL); + + strmbase_source_init(&object->source, &object->filter, L"Out", &source_ops); + object->source_IQualityControl_iface.lpVtbl = &source_qc_vtbl; + + if (FAILED(hr = CoCreateInstance(&CLSID_SeekingPassThru, + (IUnknown *)&object->source.pin.IPin_iface, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void **)&object->seeking))) + { + strmbase_sink_cleanup(&object->sink); + strmbase_source_cleanup(&object->source); + strmbase_filter_cleanup(&object->filter); + free(object); return hr; + }
- This->hvid = NULL; - This->pBihIn = NULL; - This->pBihOut = NULL; + IUnknown_QueryInterface(object->seeking, &IID_ISeekingPassThru, (void **)&passthrough); + ISeekingPassThru_Init(passthrough, FALSE, &object->sink.pin.IPin_iface); + ISeekingPassThru_Release(passthrough);
- *out = &This->tf.filter.IUnknown_inner; + TRACE("Created AVI decompressor %p.\n", object); + *out = &object->filter.IUnknown_inner;
- return hr; + return S_OK; } diff --git a/dlls/quartz/tests/avidec.c b/dlls/quartz/tests/avidec.c index b406a4861b9..1eafb9b3293 100644 --- a/dlls/quartz/tests/avidec.c +++ b/dlls/quartz/tests/avidec.c @@ -644,7 +644,7 @@ static void test_unconnected_filter_state(void) todo_wine ok(state == State_Paused, "Got state %u.\n", state);
hr = IBaseFilter_Stop(filter); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IBaseFilter_GetState(filter, 0, &state); ok(hr == S_OK, "Got hr %#x.\n", hr); @@ -658,7 +658,7 @@ static void test_unconnected_filter_state(void) todo_wine ok(state == State_Running, "Got state %u.\n", state);
hr = IBaseFilter_Stop(filter); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IBaseFilter_GetState(filter, 0, &state); ok(hr == S_OK, "Got hr %#x.\n", hr);
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/wineqtdecoder/Makefile.in | 3 +- dlls/wineqtdecoder/qtvdecoder.c | 261 +++++++++++++++++++++++--------- 2 files changed, 193 insertions(+), 71 deletions(-)
diff --git a/dlls/wineqtdecoder/Makefile.in b/dlls/wineqtdecoder/Makefile.in index b7db9b7c243..2b7179f2316 100644 --- a/dlls/wineqtdecoder/Makefile.in +++ b/dlls/wineqtdecoder/Makefile.in @@ -14,8 +14,7 @@ C_SRCS = \ qtutils.c \ qtvdecoder.c \ qualitycontrol.c \ - seeking.c \ - transform.c + seeking.c
RC_SRCS = \ rsrc.rc diff --git a/dlls/wineqtdecoder/qtvdecoder.c b/dlls/wineqtdecoder/qtvdecoder.c index 5417124782c..eaaf30acdb0 100644 --- a/dlls/wineqtdecoder/qtvdecoder.c +++ b/dlls/wineqtdecoder/qtvdecoder.c @@ -134,7 +134,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(qtdecoder);
typedef struct QTVDecoderImpl { - TransformFilter tf; + struct strmbase_filter filter; + CRITICAL_SECTION stream_cs; + + struct strmbase_source source; + IUnknown *seeking; + + struct strmbase_sink sink;
ImageDescriptionHandle hImageDescription; CFMutableDictionaryRef outputBufferAttributes; @@ -142,17 +148,29 @@ typedef struct QTVDecoderImpl HRESULT decodeHR;
DWORD outputSize; - } QTVDecoderImpl;
-static inline QTVDecoderImpl *impl_from_IBaseFilter( IBaseFilter *iface ) +static inline QTVDecoderImpl *impl_from_strmbase_filter(struct strmbase_filter *iface) { - return CONTAINING_RECORD(iface, QTVDecoderImpl, tf.filter.IBaseFilter_iface); + return CONTAINING_RECORD(iface, QTVDecoderImpl, filter); }
-static inline QTVDecoderImpl *impl_from_TransformFilter( TransformFilter *iface ) +static HRESULT video_decoder_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) { - return CONTAINING_RECORD(iface, QTVDecoderImpl, tf.filter); + QTVDecoderImpl *filter = impl_from_strmbase_filter(iface->filter); + + if (IsEqualGUID(iid, &IID_IMemInputPin)) + *out = &filter->sink.IMemInputPin_iface; + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static HRESULT video_decoder_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) +{ + return S_OK; }
static void trackingCallback( @@ -185,8 +203,8 @@ static void trackingCallback( return; }
- EnterCriticalSection(&This->tf.csReceive); - hr = BaseOutputPinImpl_GetDeliveryBuffer(&This->tf.source, &pOutSample, NULL, NULL, 0); + EnterCriticalSection(&This->stream_cs); + hr = BaseOutputPinImpl_GetDeliveryBuffer(&This->source, &pOutSample, NULL, NULL, 0); if (FAILED(hr)) { ERR("Unable to get delivery buffer (%x)\n", hr); goto error; @@ -236,44 +254,21 @@ static void trackingCallback( IMediaSample_SetTime(pOutSample, &tStart, &tStop); }
- hr = IMemInputPin_Receive(This->tf.source.pMemInputPin, pOutSample); + hr = IMemInputPin_Receive(This->source.pMemInputPin, pOutSample); if (hr != S_OK && hr != VFW_E_NOT_CONNECTED) ERR("Error sending sample (%x)\n", hr);
error: - LeaveCriticalSection(&This->tf.csReceive); + LeaveCriticalSection(&This->stream_cs); if (pOutSample) IMediaSample_Release(pOutSample);
This->decodeHR = hr; }
-static HRESULT WINAPI QTVDecoder_StartStreaming(TransformFilter* pTransformFilter) -{ - QTVDecoderImpl* This = impl_from_TransformFilter(pTransformFilter); - OSErr err = noErr; - ICMDecompressionSessionOptionsRef sessionOptions = NULL; - ICMDecompressionTrackingCallbackRecord trackingCallbackRecord; - - TRACE("(%p)->()\n", This); - - trackingCallbackRecord.decompressionTrackingCallback = trackingCallback; - trackingCallbackRecord.decompressionTrackingRefCon = (void*)This; - - err = ICMDecompressionSessionCreate(NULL, This->hImageDescription, sessionOptions, This->outputBufferAttributes, &trackingCallbackRecord, &This->decompressionSession); - - if (err != noErr) - { - ERR("Error with ICMDecompressionSessionCreate %i\n",err); - return E_FAIL; - } - - return S_OK; -} - -static HRESULT WINAPI QTVDecoder_Receive(TransformFilter *tf, IMediaSample *pSample) +static HRESULT WINAPI video_decoder_Receive(struct strmbase_sink *iface, IMediaSample *pSample) { - QTVDecoderImpl* This = impl_from_TransformFilter(tf); + QTVDecoderImpl *This = impl_from_strmbase_filter(iface->pin.filter); HRESULT hr; DWORD cbSrcStream; LPBYTE pbSrcStream; @@ -284,6 +279,8 @@ static HRESULT WINAPI QTVDecoder_Receive(TransformFilter *tf, IMediaSample *pSam OSStatus err = noErr; LONGLONG tStart, tStop;
+ EnterCriticalSection(&This->stream_cs); + hr = IMediaSample_GetPointer(pSample, &pbSrcStream); if (FAILED(hr)) { @@ -321,28 +318,16 @@ static HRESULT WINAPI QTVDecoder_Receive(TransformFilter *tf, IMediaSample *pSam hr = This->decodeHR;
error: + LeaveCriticalSection(&This->stream_cs); return hr; }
-static HRESULT WINAPI QTVDecoder_StopStreaming(TransformFilter* pTransformFilter) -{ - QTVDecoderImpl* This = impl_from_TransformFilter(pTransformFilter); - - TRACE("(%p)->()\n", This); - - if (This->decompressionSession) - ICMDecompressionSessionRelease(This->decompressionSession); - This->decompressionSession = NULL; - - return S_OK; -} - -static HRESULT video_decoder_connect_sink(TransformFilter *tf, const AM_MEDIA_TYPE *pmt) +static HRESULT video_decoder_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *pmt) { - QTVDecoderImpl* This = impl_from_TransformFilter(tf); + QTVDecoderImpl *This = impl_from_strmbase_filter(iface->pin.filter); HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED; OSErr err = noErr; - AM_MEDIA_TYPE *outpmt = &This->tf.pmt; + AM_MEDIA_TYPE *outpmt = &This->mt; CFNumberRef n = NULL;
FreeMediaType(outpmt); @@ -461,11 +446,9 @@ failed: return hr; }
-static HRESULT WINAPI QTVDecoder_BreakConnect(TransformFilter *tf, PIN_DIRECTION dir) +static void video_decoder_sink_disconnect(struct strmbase_sink *iface) { - QTVDecoderImpl *This = impl_from_TransformFilter(tf); - - TRACE("(%p)->()\n", This); + QTVDecoderImpl *This = impl_from_strmbase_filter(iface->pin.filter);
if (This->hImageDescription) DisposeHandle((Handle)This->hImageDescription); @@ -474,16 +457,58 @@ static HRESULT WINAPI QTVDecoder_BreakConnect(TransformFilter *tf, PIN_DIRECTION
This->hImageDescription = NULL; This->outputBufferAttributes = NULL; +} + +static const struct strmbase_sink_ops sink_ops = +{ + .base.pin_query_interface = video_decoder_sink_query_interface, + .base.pin_query_accept = video_decoder_sink_query_accept, + .base.pin_get_media_type = strmbase_pin_get_media_type, + .pfnReceive = video_decoder_sink_Receive, + .sink_connect = video_decoder_sink_connect, + .sink_disconnect = video_decoder_sink_disconnect, +}; + +static HRESULT video_decoder_source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) +{ + QTVDecoderImpl *filter = impl_from_strmbase_filter(iface->filter);
+ if (IsEqualGUID(iid, &IID_IMediaSeeking)) + return IUnknown_QueryInterface(filter->seeking, iid, out); + else + return E_NOINTERFACE; + + IUnknown_AddRef((IUnknown *)*out); return S_OK; }
-static HRESULT WINAPI QTVDecoder_DecideBufferSize(TransformFilter *tf, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) +static HRESULT video_decoder_source_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) { - QTVDecoderImpl *This = impl_from_TransformFilter(tf); - ALLOCATOR_PROPERTIES actual; + QTVDecoderImpl *filter = impl_from_strmbase_filter(iface->filter); + + if (IsEqualGUID(&mt->majortype, &filter->mt.majortype) + && (IsEqualGUID(&mt->subtype, &filter->mt.subtype) + || IsEqualGUID(&filter->mt.subtype, &GUID_NULL))) + return S_OK; + return S_FALSE; +} + +static HRESULT video_decoder_source_get_media_type(struct strmbase_pin *iface, + unsigned int index, AM_MEDIA_TYPE *mt) +{ + QTVDecoderImpl *filter = impl_from_strmbase_filter(iface->filter); + + if (index) + return VFW_S_NO_MORE_ITEMS; + CopyMediaType(mt, &filter->mt); + return S_OK; +}
- TRACE("()\n"); +static HRESULT WINAPI video_decoder_DecideBufferSize(struct strmbase_source *iface, + IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) +{ + QTVDecoderImpl *This = impl_from_strmbase_filter(iface->pin.filter); + ALLOCATOR_PROPERTIES actual;
if (!ppropInputRequest->cbAlign) ppropInputRequest->cbAlign = 1; @@ -497,13 +522,89 @@ static HRESULT WINAPI QTVDecoder_DecideBufferSize(TransformFilter *tf, IMemAlloc return IMemAllocator_SetProperties(pAlloc, ppropInputRequest, &actual); }
-static const TransformFilterFuncTable QTVDecoder_FuncsTable = { - .pfnDecideBufferSize = QTVDecoder_DecideBufferSize, - .pfnStartStreaming = QTVDecoder_StartStreaming, - .pfnReceive = QTVDecoder_Receive, - .pfnStopStreaming = QTVDecoder_StopStreaming, - .transform_connect_sink = video_decoder_connect_sink, - .pfnBreakConnect = QTVDecoder_BreakConnect, +static const struct strmbase_source_ops source_ops = +{ + .base.pin_query_interface = video_decoder_source_query_interface, + .base.pin_query_accept = video_decoder_source_query_accept, + .base.pin_get_media_type = video_decoder_source_get_media_type, + .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, + .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, + .pfnDecideBufferSize = video_decoder_source_DecideBufferSize, +}; + +static struct strmbase_pin *video_decoder_get_pin(struct strmbase_filter *iface, unsigned int index) +{ + QTVDecoderImpl *filter = impl_from_strmbase_filter(iface); + + if (index == 0) + return &filter->sink.pin; + else if (index == 1) + return &filter->source.pin; + return NULL; +} + +static void video_decoder_destroy(struct strmbase_filter *iface) +{ + QTVDecoderImpl *filter = impl_from_strmbase_filter(iface); + + if (filter->sink.pin.peer) + IPin_Disconnect(filter->sink.pin.peer); + IPin_Disconnect(&filter->sink.pin.IPin_iface); + + if (filter->source.pin.peer) + IPin_Disconnect(filter->source.pin.peer); + IPin_Disconnect(&filter->source.pin.IPin_iface); + + strmbase_sink_cleanup(&filter->sink); + strmbase_source_cleanup(&filter->source); + + filter->stream_cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&filter->stream_cs); + FreeMediaType(&filter->mt); + IUnknown_Release(filter->seeking); + strmbase_filter_cleanup(&filter->filter); + free(filter); +} + +static HRESULT video_decoder_init_stream(struct strmbase_filter *iface) +{ + QTVDecoderImpl *This = impl_from_strmbase_filter(iface); + + OSErr err = noErr; + ICMDecompressionSessionOptionsRef sessionOptions = NULL; + ICMDecompressionTrackingCallbackRecord trackingCallbackRecord; + + trackingCallbackRecord.decompressionTrackingCallback = trackingCallback; + trackingCallbackRecord.decompressionTrackingRefCon = (void*)This; + + err = ICMDecompressionSessionCreate(NULL, This->hImageDescription, sessionOptions, This->outputBufferAttributes, &trackingCallbackRecord, &This->decompressionSession); + + if (err != noErr) + { + ERR("Error with ICMDecompressionSessionCreate %i\n",err); + return E_FAIL; + } + + return BaseOutputPinImpl_Active(&This->source); +} + +static HRESULT video_decoder_cleanup_stream(struct strmbase_filter *iface) +{ + QTVDecoderImpl* This = impl_from_TransformFilter(pTransformFilter); + + if (This->decompressionSession) + ICMDecompressionSessionRelease(This->decompressionSession); + This->decompressionSession = NULL; + + return BaseOutputPinImpl_Inactive(&This->source); +} + +static const struct strmbase_filter_ops filter_ops = +{ + .filter_get_pin = video_decoder_get_pin, + .filter_destroy = video_decoder_destroy, + .filter_init_stream = video_decoder_init_stream, + .filter_cleanup_stream = video_decoder_cleanup_stream, };
HRESULT video_decoder_create(IUnknown *outer, IUnknown **out) @@ -511,10 +612,32 @@ HRESULT video_decoder_create(IUnknown *outer, IUnknown **out) QTVDecoderImpl *object; HRESULT hr;
- hr = strmbase_transform_create(sizeof(QTVDecoderImpl), outer, &CLSID_QTVDecoder, - &QTVDecoder_FuncsTable, (IBaseFilter **)&object); - if (FAILED(hr)) + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + strmbase_filter_init(&object->filter, outer, &CLSID_QTVDecoder, &filter_ops); + + InitializeCriticalSection(&object->stream_cs); + object->stream_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": QTVDecoderImpl.stream_cs"); + + strmbase_sink_init(&object->sink, &object->filter, L"In", &sink_ops, NULL); + + strmbase_source_init(&object->source, &object->filter, L"Out", &source_ops); + + if (FAILED(hr = CoCreateInstance(&CLSID_SeekingPassThru, + (IUnknown *)&object->source.pin.IPin_iface, CLSCTX_INPROC_SERVER, + &IID_IUnknown, (void **)&object->seeking))) + { + strmbase_sink_cleanup(&object->sink); + strmbase_source_cleanup(&object->source); + strmbase_filter_cleanup(&object->filter); + free(object); return hr; + } + + IUnknown_QueryInterface(object->seeking, &IID_ISeekingPassThru, (void **)&passthrough); + ISeekingPassThru_Init(passthrough, FALSE, &object->sink.pin.IPin_iface); + ISeekingPassThru_Release(passthrough);
TRACE("Created video decoder %p.\n", object); *out = &object->tf.filter.IUnknown_inner;
This is providing very little of value. The code in Receive() and in the state management methods should probably be moved to the base pin and filter respectively; the media type management is just wrong (and our two extant transforms should not handle it the same way anyway), and most of the rest just passes through to the transform's own callback table.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/strmbase/Makefile.in | 1 - dlls/strmbase/transform.c | 437 -------------------------------------- include/wine/strmbase.h | 50 ----- 3 files changed, 488 deletions(-) delete mode 100644 dlls/strmbase/transform.c
diff --git a/dlls/strmbase/Makefile.in b/dlls/strmbase/Makefile.in index e3fc30957e3..0832b3e6213 100644 --- a/dlls/strmbase/Makefile.in +++ b/dlls/strmbase/Makefile.in @@ -10,6 +10,5 @@ C_SRCS = \ qualitycontrol.c \ renderer.c \ seeking.c \ - transform.c \ video.c \ window.c diff --git a/dlls/strmbase/transform.c b/dlls/strmbase/transform.c deleted file mode 100644 index 2c75156c1bf..00000000000 --- a/dlls/strmbase/transform.c +++ /dev/null @@ -1,437 +0,0 @@ -/* - * Transform Filter (Base for decoders, etc...) - * - * Copyright 2005 Christian Costa - * Copyright 2010 Aric Stewart, CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "strmbase_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(strmbase); - -static const WCHAR wcsInputPinName[] = {'I','n',0}; -static const WCHAR wcsOutputPinName[] = {'O','u','t',0}; - -static inline TransformFilter *impl_from_strmbase_filter(struct strmbase_filter *iface) -{ - return CONTAINING_RECORD(iface, TransformFilter, filter); -} - -static inline TransformFilter *impl_from_sink_IPin(IPin *iface) -{ - return CONTAINING_RECORD(iface, TransformFilter, sink.pin.IPin_iface); -} - -static HRESULT sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *pmt) -{ - return S_OK; -} - -static HRESULT WINAPI TransformFilter_Input_Receive(struct strmbase_sink *This, IMediaSample *pInSample) -{ - TransformFilter *pTransform = impl_from_sink_IPin(&This->pin.IPin_iface); - HRESULT hr; - - TRACE("%p\n", This); - - /* We do not expect pin connection state to change while the filter is - * running. This guarantee is necessary, since otherwise we would have to - * take the filter lock, and we can't take the filter lock from a streaming - * thread. */ - if (!pTransform->source.pMemInputPin) - { - WARN("Source is not connected, returning VFW_E_NOT_CONNECTED.\n"); - return VFW_E_NOT_CONNECTED; - } - - EnterCriticalSection(&pTransform->csReceive); - if (pTransform->filter.state == State_Stopped) - { - LeaveCriticalSection(&pTransform->csReceive); - return VFW_E_WRONG_STATE; - } - - if (This->flushing) - { - LeaveCriticalSection(&pTransform->csReceive); - return S_FALSE; - } - - if (pTransform->pFuncsTable->pfnReceive) - hr = pTransform->pFuncsTable->pfnReceive(pTransform, pInSample); - else - hr = S_FALSE; - - LeaveCriticalSection(&pTransform->csReceive); - return hr; -} - -static inline TransformFilter *impl_from_source_IPin(IPin *iface) -{ - return CONTAINING_RECORD(iface, TransformFilter, source.pin.IPin_iface); -} - -static HRESULT source_query_accept(struct strmbase_pin *This, const AM_MEDIA_TYPE *pmt) -{ - TransformFilter *pTransformFilter = impl_from_source_IPin(&This->IPin_iface); - AM_MEDIA_TYPE* outpmt = &pTransformFilter->pmt; - - if (IsEqualIID(&pmt->majortype, &outpmt->majortype) - && (IsEqualIID(&pmt->subtype, &outpmt->subtype) || IsEqualIID(&outpmt->subtype, &GUID_NULL))) - return S_OK; - return S_FALSE; -} - -static HRESULT WINAPI TransformFilter_Output_DecideBufferSize(struct strmbase_source *This, - IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) -{ - TransformFilter *pTransformFilter = impl_from_source_IPin(&This->pin.IPin_iface); - return pTransformFilter->pFuncsTable->pfnDecideBufferSize(pTransformFilter, pAlloc, ppropInputRequest); -} - -static HRESULT source_get_media_type(struct strmbase_pin *This, unsigned int iPosition, AM_MEDIA_TYPE *pmt) -{ - TransformFilter *pTransform = impl_from_source_IPin(&This->IPin_iface); - - if (iPosition > 0) - return VFW_S_NO_MORE_ITEMS; - CopyMediaType(pmt, &pTransform->pmt); - return S_OK; -} - -static struct strmbase_pin *transform_get_pin(struct strmbase_filter *iface, unsigned int index) -{ - TransformFilter *filter = impl_from_strmbase_filter(iface); - - if (index == 0) - return &filter->sink.pin; - else if (index == 1) - return &filter->source.pin; - return NULL; -} - -static void transform_destroy(struct strmbase_filter *iface) -{ - TransformFilter *filter = impl_from_strmbase_filter(iface); - - if (filter->sink.pin.peer) - IPin_Disconnect(filter->sink.pin.peer); - IPin_Disconnect(&filter->sink.pin.IPin_iface); - - if (filter->source.pin.peer) - IPin_Disconnect(filter->source.pin.peer); - IPin_Disconnect(&filter->source.pin.IPin_iface); - - strmbase_sink_cleanup(&filter->sink); - strmbase_source_cleanup(&filter->source); - - filter->csReceive.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&filter->csReceive); - FreeMediaType(&filter->pmt); - IUnknown_Release(filter->seekthru_unk); - strmbase_filter_cleanup(&filter->filter); - CoTaskMemFree(filter); -} - -static HRESULT transform_init_stream(struct strmbase_filter *iface) -{ - TransformFilter *filter = impl_from_strmbase_filter(iface); - HRESULT hr = S_OK; - - EnterCriticalSection(&filter->csReceive); - - if (filter->pFuncsTable->pfnStartStreaming) - hr = filter->pFuncsTable->pfnStartStreaming(filter); - if (SUCCEEDED(hr)) - hr = BaseOutputPinImpl_Active(&filter->source); - - LeaveCriticalSection(&filter->csReceive); - - return hr; -} - -static HRESULT transform_cleanup_stream(struct strmbase_filter *iface) -{ - TransformFilter *filter = impl_from_strmbase_filter(iface); - HRESULT hr = S_OK; - - EnterCriticalSection(&filter->csReceive); - - if (filter->pFuncsTable->pfnStopStreaming) - hr = filter->pFuncsTable->pfnStopStreaming(filter); - if (SUCCEEDED(hr)) - hr = BaseOutputPinImpl_Inactive(&filter->source); - - LeaveCriticalSection(&filter->csReceive); - - return hr; -} - -static const struct strmbase_filter_ops filter_ops = -{ - .filter_get_pin = transform_get_pin, - .filter_destroy = transform_destroy, - .filter_init_stream = transform_init_stream, - .filter_cleanup_stream = transform_cleanup_stream, -}; - -static HRESULT sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) -{ - TransformFilter *filter = impl_from_sink_IPin(&iface->IPin_iface); - - if (IsEqualGUID(iid, &IID_IMemInputPin)) - *out = &filter->sink.IMemInputPin_iface; - else - return E_NOINTERFACE; - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; -} - -static HRESULT sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *mt) -{ - TransformFilter *filter = impl_from_sink_IPin(&iface->pin.IPin_iface); - - if (filter->pFuncsTable->transform_connect_sink) - return filter->pFuncsTable->transform_connect_sink(filter, mt); - return S_OK; -} - -static void sink_disconnect(struct strmbase_sink *iface) -{ - TransformFilter *filter = impl_from_sink_IPin(&iface->pin.IPin_iface); - - if (filter->pFuncsTable->pfnBreakConnect) - filter->pFuncsTable->pfnBreakConnect(filter, PINDIR_INPUT); -} - -static HRESULT sink_eos(struct strmbase_sink *iface) -{ - TransformFilter *filter = impl_from_sink_IPin(&iface->pin.IPin_iface); - - if (filter->source.pin.peer) - return IPin_EndOfStream(filter->source.pin.peer); - return VFW_E_NOT_CONNECTED; -} - -static HRESULT sink_begin_flush(struct strmbase_sink *iface) -{ - TransformFilter *filter = impl_from_sink_IPin(&iface->pin.IPin_iface); - if (filter->source.pin.peer) - return IPin_BeginFlush(filter->source.pin.peer); - return S_OK; -} - -static HRESULT sink_end_flush(struct strmbase_sink *iface) -{ - TransformFilter *filter = impl_from_sink_IPin(&iface->pin.IPin_iface); - HRESULT hr = S_OK; - - if (filter->pFuncsTable->pfnEndFlush) - hr = filter->pFuncsTable->pfnEndFlush(filter); - if (SUCCEEDED(hr) && filter->source.pin.peer) - hr = IPin_EndFlush(filter->source.pin.peer); - return hr; -} - -static HRESULT sink_new_segment(struct strmbase_sink *iface, - REFERENCE_TIME start, REFERENCE_TIME stop, double rate) -{ - TransformFilter *filter = impl_from_sink_IPin(&iface->pin.IPin_iface); - if (filter->source.pin.peer) - return IPin_NewSegment(filter->source.pin.peer, start, stop, rate); - return S_OK; -} - -static const struct strmbase_sink_ops sink_ops = -{ - .base.pin_query_accept = sink_query_accept, - .base.pin_get_media_type = strmbase_pin_get_media_type, - .base.pin_query_interface = sink_query_interface, - .pfnReceive = TransformFilter_Input_Receive, - .sink_connect = sink_connect, - .sink_disconnect = sink_disconnect, - .sink_eos = sink_eos, - .sink_begin_flush = sink_begin_flush, - .sink_end_flush = sink_end_flush, - .sink_new_segment = sink_new_segment, -}; - -static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) -{ - TransformFilter *filter = impl_from_source_IPin(&iface->IPin_iface); - - if (IsEqualGUID(iid, &IID_IQualityControl)) - *out = &filter->source_IQualityControl_iface; - else if (IsEqualGUID(iid, &IID_IMediaSeeking)) - return IUnknown_QueryInterface(filter->seekthru_unk, iid, out); - else - return E_NOINTERFACE; - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; -} - -static const struct strmbase_source_ops source_ops = -{ - .base.pin_query_accept = source_query_accept, - .base.pin_get_media_type = source_get_media_type, - .base.pin_query_interface = source_query_interface, - .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, - .pfnDecideBufferSize = TransformFilter_Output_DecideBufferSize, - .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, -}; - -static TransformFilter *impl_from_source_IQualityControl(IQualityControl *iface) -{ - return CONTAINING_RECORD(iface, TransformFilter, source_IQualityControl_iface); -} - -static HRESULT WINAPI transform_source_qc_QueryInterface(IQualityControl *iface, - REFIID iid, void **out) -{ - TransformFilter *filter = impl_from_source_IQualityControl(iface); - return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out); -} - -static ULONG WINAPI transform_source_qc_AddRef(IQualityControl *iface) -{ - TransformFilter *filter = impl_from_source_IQualityControl(iface); - return IPin_AddRef(&filter->source.pin.IPin_iface); -} - -static ULONG WINAPI transform_source_qc_Release(IQualityControl *iface) -{ - TransformFilter *filter = impl_from_source_IQualityControl(iface); - return IPin_Release(&filter->source.pin.IPin_iface); -} - -HRESULT WINAPI TransformFilterImpl_Notify(TransformFilter *filter, IBaseFilter *sender, Quality q) -{ - IQualityControl *peer; - HRESULT hr = S_FALSE; - - if (filter->source_qc_sink) - return IQualityControl_Notify(filter->source_qc_sink, &filter->filter.IBaseFilter_iface, q); - - if (filter->sink.pin.peer - && SUCCEEDED(IPin_QueryInterface(filter->sink.pin.peer, &IID_IQualityControl, (void **)&peer))) - { - hr = IQualityControl_Notify(peer, &filter->filter.IBaseFilter_iface, q); - IQualityControl_Release(peer); - } - return hr; -} - -static HRESULT WINAPI transform_source_qc_Notify(IQualityControl *iface, - IBaseFilter *sender, Quality q) -{ - TransformFilter *filter = impl_from_source_IQualityControl(iface); - - TRACE("filter %p, sender %p, type %#x, proportion %u, late %s, timestamp %s.\n", - filter, sender, q.Type, q.Proportion, debugstr_time(q.Late), debugstr_time(q.TimeStamp)); - - if (filter->pFuncsTable->pfnNotify) - return filter->pFuncsTable->pfnNotify(filter, sender, q); - return TransformFilterImpl_Notify(filter, sender, q); -} - -static HRESULT WINAPI transform_source_qc_SetSink(IQualityControl *iface, IQualityControl *sink) -{ - TransformFilter *filter = impl_from_source_IQualityControl(iface); - - TRACE("filter %p, sink %p.\n", filter, sink); - - filter->source_qc_sink = sink; - - return S_OK; -} - -static const IQualityControlVtbl source_qc_vtbl = -{ - transform_source_qc_QueryInterface, - transform_source_qc_AddRef, - transform_source_qc_Release, - transform_source_qc_Notify, - transform_source_qc_SetSink, -}; - -static HRESULT strmbase_transform_init(IUnknown *outer, const CLSID *clsid, - const TransformFilterFuncTable *func_table, TransformFilter *filter) -{ - ISeekingPassThru *passthru; - HRESULT hr; - - strmbase_filter_init(&filter->filter, outer, clsid, &filter_ops); - - InitializeCriticalSection(&filter->csReceive); - filter->csReceive.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": TransformFilter.csReceive"); - - /* pTransformFilter is already allocated */ - filter->pFuncsTable = func_table; - ZeroMemory(&filter->pmt, sizeof(filter->pmt)); - - strmbase_sink_init(&filter->sink, &filter->filter, wcsInputPinName, &sink_ops, NULL); - - strmbase_source_init(&filter->source, &filter->filter, wcsOutputPinName, &source_ops); - filter->source_IQualityControl_iface.lpVtbl = &source_qc_vtbl; - - filter->seekthru_unk = NULL; - hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown *)&filter->filter.IBaseFilter_iface, - CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&filter->seekthru_unk); - if (SUCCEEDED(hr)) - { - IUnknown_QueryInterface(filter->seekthru_unk, &IID_ISeekingPassThru, (void **)&passthru); - ISeekingPassThru_Init(passthru, FALSE, &filter->sink.pin.IPin_iface); - ISeekingPassThru_Release(passthru); - } - - if (FAILED(hr)) - { - strmbase_sink_cleanup(&filter->sink); - strmbase_source_cleanup(&filter->source); - strmbase_filter_cleanup(&filter->filter); - } - - return hr; -} - -HRESULT strmbase_transform_create(LONG filter_size, IUnknown *outer, const CLSID *pClsid, - const TransformFilterFuncTable *pFuncsTable, IBaseFilter **ppTransformFilter) -{ - TransformFilter* pTf; - - *ppTransformFilter = NULL; - - assert(filter_size >= sizeof(TransformFilter)); - - pTf = CoTaskMemAlloc(filter_size); - - if (!pTf) - return E_OUTOFMEMORY; - - ZeroMemory(pTf, filter_size); - - if (SUCCEEDED(strmbase_transform_init(outer, pClsid, pFuncsTable, pTf))) - { - *ppTransformFilter = &pTf->filter.IBaseFilter_iface; - return S_OK; - } - - CoTaskMemFree(pTf); - return E_FAIL; -} diff --git a/include/wine/strmbase.h b/include/wine/strmbase.h index 6fc4cc08b3e..2a7d642986c 100644 --- a/include/wine/strmbase.h +++ b/include/wine/strmbase.h @@ -160,56 +160,6 @@ void strmbase_filter_init(struct strmbase_filter *filter, IUnknown *outer, const CLSID *clsid, const struct strmbase_filter_ops *func_table); void strmbase_filter_cleanup(struct strmbase_filter *filter);
-/* Transform Filter */ -typedef struct TransformFilter -{ - struct strmbase_filter filter; - - struct strmbase_source source; - IQualityControl source_IQualityControl_iface; - IQualityControl *source_qc_sink; - - struct strmbase_sink sink; - - AM_MEDIA_TYPE pmt; - CRITICAL_SECTION csReceive; - - const struct TransformFilterFuncTable * pFuncsTable; - /* IMediaSeeking and IMediaPosition are implemented by ISeekingPassThru */ - IUnknown *seekthru_unk; -} TransformFilter; - -typedef HRESULT (WINAPI *TransformFilter_DecideBufferSize) (TransformFilter *iface, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest); -typedef HRESULT (WINAPI *TransformFilter_StartStreaming) (TransformFilter *iface); -typedef HRESULT (WINAPI *TransformFilter_StopStreaming) (TransformFilter *iface); -typedef HRESULT (WINAPI *TransformFilter_Receive) (TransformFilter* iface, IMediaSample* pIn); -typedef HRESULT (WINAPI *TransformFilter_BreakConnect) (TransformFilter *iface, PIN_DIRECTION dir); -typedef HRESULT (WINAPI *TransformFilter_CheckInputType) (TransformFilter *iface, const AM_MEDIA_TYPE *pMediaType); -typedef HRESULT (WINAPI *TransformFilter_EndOfStream) (TransformFilter *iface); -typedef HRESULT (WINAPI *TransformFilter_BeginFlush) (TransformFilter *iface); -typedef HRESULT (WINAPI *TransformFilter_EndFlush) (TransformFilter *iface); -typedef HRESULT (WINAPI *TransformFilter_NewSegment) (TransformFilter *iface, -REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); -typedef HRESULT (WINAPI *TransformFilter_Notify) (TransformFilter *iface, IBaseFilter *sender, Quality qm); - -typedef struct TransformFilterFuncTable { - /* Required */ - TransformFilter_DecideBufferSize pfnDecideBufferSize; - /* Optional */ - TransformFilter_StartStreaming pfnStartStreaming; - TransformFilter_Receive pfnReceive; - TransformFilter_StopStreaming pfnStopStreaming; - HRESULT (*transform_connect_sink)(TransformFilter *filter, const AM_MEDIA_TYPE *mt); - TransformFilter_BreakConnect pfnBreakConnect; - TransformFilter_EndFlush pfnEndFlush; - TransformFilter_Notify pfnNotify; -} TransformFilterFuncTable; - -HRESULT WINAPI TransformFilterImpl_Notify(TransformFilter *iface, IBaseFilter *sender, Quality qm); - -HRESULT strmbase_transform_create(LONG filter_size, IUnknown *outer, const CLSID *clsid, - const TransformFilterFuncTable *func_table, IBaseFilter **filter); - /* Source Seeking */ typedef HRESULT (WINAPI *SourceSeeking_ChangeRate)(IMediaSeeking *iface); typedef HRESULT (WINAPI *SourceSeeking_ChangeStart)(IMediaSeeking *iface);