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 a983defa732..67bd2a20c6b 100644 --- a/dlls/quartz/acmwrapper.c +++ b/dlls/quartz/acmwrapper.c @@ -37,8 +37,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz);
struct acm_wrapper { - 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 @@ struct acm_wrapper LONGLONG lasttime_sent; };
-static inline struct acm_wrapper *impl_from_TransformFilter( TransformFilter *iface ) +static inline struct acm_wrapper *impl_from_strmbase_filter(struct strmbase_filter *iface) { - return CONTAINING_RECORD(iface, struct acm_wrapper, tf); + return CONTAINING_RECORD(iface, struct acm_wrapper, filter); +} + +static HRESULT acm_wrapper_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) +{ + struct acm_wrapper *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) { - struct acm_wrapper *This = impl_from_TransformFilter(tf); + struct acm_wrapper *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) { - struct acm_wrapper *filter = impl_from_TransformFilter(iface); + struct acm_wrapper *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) { - struct acm_wrapper *This = impl_from_TransformFilter(tf); + struct acm_wrapper *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) +{ + struct acm_wrapper *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) { - struct acm_wrapper *pACM = impl_from_TransformFilter(tf); + struct acm_wrapper *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) +{ + struct acm_wrapper *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) +{ + struct acm_wrapper *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 struct acm_wrapper *impl_from_source_IQualityControl(IQualityControl *iface) +{ + return CONTAINING_RECORD(iface, struct acm_wrapper, source_IQualityControl_iface); +} + +static HRESULT WINAPI acm_wrapper_source_qc_QueryInterface(IQualityControl *iface, + REFIID iid, void **out) +{ + struct acm_wrapper *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) +{ + struct acm_wrapper *filter = impl_from_source_IQualityControl(iface); + return IPin_AddRef(&filter->source.pin.IPin_iface); +} + +static ULONG WINAPI acm_wrapper_source_qc_Release(IQualityControl *iface) +{ + struct acm_wrapper *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) +{ + struct acm_wrapper *filter = impl_from_source_IQualityControl(iface); + IQualityControl *peer; + HRESULT hr; + + 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) +{ + struct acm_wrapper *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) +{ + struct acm_wrapper *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) +{ + struct acm_wrapper *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) +{ + struct acm_wrapper *filter = impl_from_strmbase_filter(iface); + + BaseOutputPinImpl_Active(&filter->source); + return S_OK; +} + +static HRESULT acm_wrapper_cleanup_stream(struct strmbase_filter *iface) +{ + struct acm_wrapper *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 acm_wrapper_create(IUnknown *outer, IUnknown **out) { - struct acm_wrapper *This; + ISeekingPassThru *passthrough; + struct acm_wrapper *object; HRESULT hr;
- *out = NULL; + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY;
- hr = strmbase_transform_create(sizeof(*This), 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 d900b6e27d0..b91a77de463 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -38,51 +38,51 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz);
struct avi_decompressor { - 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; };
-static inline struct avi_decompressor *impl_from_TransformFilter( TransformFilter *iface ) +static struct avi_decompressor *impl_from_strmbase_filter(struct strmbase_filter *iface) { - return CONTAINING_RECORD(iface, struct avi_decompressor, tf); + return CONTAINING_RECORD(iface, struct avi_decompressor, filter); }
-static HRESULT WINAPI AVIDec_StartStreaming(TransformFilter* pTransformFilter) +static HRESULT avi_decompressor_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) { - struct avi_decompressor *This = impl_from_TransformFilter(pTransformFilter); - DWORD result; + struct avi_decompressor *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) { - struct avi_decompressor *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) { - struct avi_decompressor *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) +{ + struct avi_decompressor *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(struct avi_decompressor *This, REFERENCE_TIME tStar return 0; }
-static HRESULT WINAPI AVIDec_Receive(TransformFilter *tf, IMediaSample *pSample) +static HRESULT WINAPI avi_decompressor_sink_Receive(struct strmbase_sink *iface, IMediaSample *pSample) { - struct avi_decompressor *This = impl_from_TransformFilter(tf); + struct avi_decompressor *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) { - struct avi_decompressor *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) -{ - struct avi_decompressor *This = impl_from_TransformFilter(tf); + struct avi_decompressor *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) { - struct avi_decompressor *This = impl_from_TransformFilter(tf); + struct avi_decompressor *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) +{ + struct avi_decompressor *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) { - struct avi_decompressor *pAVI = impl_from_TransformFilter(tf); + struct avi_decompressor *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) +{ + struct avi_decompressor *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) +{ + struct avi_decompressor *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 struct avi_decompressor *impl_from_source_IQualityControl(IQualityControl *iface) +{ + return CONTAINING_RECORD(iface, struct avi_decompressor, source_IQualityControl_iface); +} + +static HRESULT WINAPI acm_wrapper_source_qc_QueryInterface(IQualityControl *iface, + REFIID iid, void **out) +{ + struct avi_decompressor *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) +{ + struct avi_decompressor *filter = impl_from_source_IQualityControl(iface); + return IPin_AddRef(&filter->source.pin.IPin_iface); +} + +static ULONG WINAPI acm_wrapper_source_qc_Release(IQualityControl *iface) +{ + struct avi_decompressor *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) +{ + struct avi_decompressor *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) +{ + struct avi_decompressor *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) +{ + struct avi_decompressor *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) +{ + struct avi_decompressor *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) +{ + struct avi_decompressor *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) +{ + struct avi_decompressor *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 avi_dec_create(IUnknown *outer, IUnknown **out) { - struct avi_decompressor *This; + struct avi_decompressor *object; + ISeekingPassThru *passthrough; HRESULT hr;
- *out = NULL; + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY;
- hr = strmbase_transform_create(sizeof(*This), 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 81d153d4c45..725e034ae27 100644 --- a/dlls/quartz/tests/avidec.c +++ b/dlls/quartz/tests/avidec.c @@ -701,7 +701,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); @@ -715,7 +715,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);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=66799
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/quartz/acmwrapper.c:37 error: patch failed: dlls/quartz/avidec.c:38 Task: Patch failed to apply
=== debiant (build log) ===
error: patch failed: dlls/quartz/acmwrapper.c:37 error: patch failed: dlls/quartz/avidec.c:38 Task: Patch failed to apply
=== debiant (build log) ===
error: patch failed: dlls/quartz/acmwrapper.c:37 error: patch failed: dlls/quartz/avidec.c:38 Task: Patch failed to apply
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;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=66800
Your paranoid android.
=== debiant (build log) ===
error: patch failed: dlls/quartz/acmwrapper.c:37 error: patch failed: dlls/quartz/avidec.c:38 Task: Patch failed to apply
=== debiant (build log) ===
error: patch failed: dlls/quartz/acmwrapper.c:37 error: patch failed: dlls/quartz/avidec.c:38 Task: Patch failed to apply
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/transform.c | 437 -------------------------------------- include/wine/strmbase.h | 50 ----- 2 files changed, 487 deletions(-) delete mode 100644 dlls/strmbase/transform.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 be5f993d2cf..0bcac13ebbc 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);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=66801
Your paranoid android.
=== debiant (build log) ===
error: patch failed: dlls/quartz/acmwrapper.c:37 error: patch failed: dlls/quartz/avidec.c:38 Task: Patch failed to apply
=== debiant (build log) ===
error: patch failed: dlls/quartz/acmwrapper.c:37 error: patch failed: dlls/quartz/avidec.c:38 Task: Patch failed to apply
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=66798
Your paranoid android.
=== build (build log) ===
error: patch failed: dlls/quartz/acmwrapper.c:37 Task: Patch failed to apply
=== debiant (build log) ===
error: patch failed: dlls/quartz/acmwrapper.c:37 Task: Patch failed to apply
=== debiant (build log) ===
error: patch failed: dlls/quartz/acmwrapper.c:37 Task: Patch failed to apply