The documentation specifies that preroll samples shouldn't be rendered, but the video renderer renders them anyway.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/videorenderer.c | 3 +++ dlls/quartz/videorenderer.c | 10 ---------- 2 files changed, 3 insertions(+), 10 deletions(-)
diff --git a/dlls/quartz/tests/videorenderer.c b/dlls/quartz/tests/videorenderer.c index 4ae320e0225..ac2cadc4b17 100644 --- a/dlls/quartz/tests/videorenderer.c +++ b/dlls/quartz/tests/videorenderer.c @@ -797,6 +797,9 @@ static HANDLE send_frame_time(IMemInputPin *sink, REFERENCE_TIME start_time, uns hr = IMediaSample_SetTime(sample, &start_time, &end_time); ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMediaSample_SetPreroll(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + params->sink = sink; params->sample = sample; thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL); diff --git a/dlls/quartz/videorenderer.c b/dlls/quartz/videorenderer.c index f635d9eaac0..eb6accf2d34 100644 --- a/dlls/quartz/videorenderer.c +++ b/dlls/quartz/videorenderer.c @@ -82,15 +82,6 @@ static void VideoRenderer_AutoShowWindow(struct video_renderer *This) ShowWindow(This->window.hwnd, SW_SHOW); }
-static HRESULT WINAPI VideoRenderer_ShouldDrawSampleNow(struct strmbase_renderer *filter, - IMediaSample *pSample, REFERENCE_TIME *start, REFERENCE_TIME *end) -{ - /* Preroll means the sample isn't shown, this is used for key frames and things like that */ - if (IMediaSample_IsPreroll(pSample) == S_OK) - return E_FAIL; - return S_FALSE; -} - static HRESULT WINAPI VideoRenderer_DoRenderSample(struct strmbase_renderer *iface, IMediaSample *pSample) { struct video_renderer *filter = impl_from_strmbase_renderer(iface); @@ -253,7 +244,6 @@ static const struct strmbase_renderer_ops renderer_ops = .renderer_init_stream = video_renderer_init_stream, .renderer_start_stream = video_renderer_start_stream, .renderer_stop_stream = video_renderer_stop_stream, - .pfnShouldDrawSampleNow = VideoRenderer_ShouldDrawSampleNow, .renderer_destroy = video_renderer_destroy, .renderer_query_interface = video_renderer_query_interface, .renderer_pin_query_interface = video_renderer_pin_query_interface,
The documentation specifies that preroll samples shouldn't be rendered, but the VMR9 renders them anyway.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/tests/vmr7.c | 3 +++ dlls/quartz/tests/vmr9.c | 3 +++ dlls/quartz/vmr9.c | 16 ---------------- 3 files changed, 6 insertions(+), 16 deletions(-)
diff --git a/dlls/quartz/tests/vmr7.c b/dlls/quartz/tests/vmr7.c index cf4675ce069..f1b19aa6634 100644 --- a/dlls/quartz/tests/vmr7.c +++ b/dlls/quartz/tests/vmr7.c @@ -983,6 +983,9 @@ static HANDLE send_frame(IMemInputPin *sink) hr = IMediaSample_SetTime(sample, &start_time, &end_time); ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMediaSample_SetPreroll(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + params->sink = sink; params->sample = sample; thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL); diff --git a/dlls/quartz/tests/vmr9.c b/dlls/quartz/tests/vmr9.c index cd4df58f791..e630deb8d74 100644 --- a/dlls/quartz/tests/vmr9.c +++ b/dlls/quartz/tests/vmr9.c @@ -1011,6 +1011,9 @@ static HANDLE send_frame_time(IMemInputPin *sink, REFERENCE_TIME start_time, DWO hr = IMediaSample_SetTime(sample, &start_time, &end_time); ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMediaSample_SetPreroll(sample, TRUE); + ok(hr == S_OK, "Got hr %#x.\n", hr); + params->sink = sink; params->sample = sample; thread = CreateThread(NULL, 0, frame_thread, params, 0, NULL); diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index aeaefd52c6b..a3f55011062 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -244,12 +244,6 @@ static HRESULT WINAPI VMR9_DoRenderSample(struct strmbase_renderer *iface, IMedi if (IMediaSample_IsSyncPoint(sample) == S_OK) info.dwFlags |= VMR9Sample_SyncPoint;
- /* If we render ourselves, and this is a preroll sample, discard it */ - if (info.dwFlags & VMR9Sample_Preroll) - { - return S_OK; - } - if (FAILED(hr = IMediaSample_GetPointer(sample, &data))) { ERR("Failed to get pointer to sample data, hr %#x.\n", hr); @@ -504,15 +498,6 @@ static void vmr_stop_stream(struct strmbase_renderer *iface) ResetEvent(This->run_event); }
-static HRESULT WINAPI VMR9_ShouldDrawSampleNow(struct strmbase_renderer *iface, - IMediaSample *pSample, REFERENCE_TIME *start, REFERENCE_TIME *end) -{ - /* Preroll means the sample isn't shown, this is used for key frames and things like that */ - if (IMediaSample_IsPreroll(pSample) == S_OK) - return E_FAIL; - return S_FALSE; -} - static HRESULT vmr_connect(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt) { struct quartz_vmr *filter = impl_from_IBaseFilter(&iface->filter.IBaseFilter_iface); @@ -668,7 +653,6 @@ static const struct strmbase_renderer_ops renderer_ops = .renderer_init_stream = vmr_init_stream, .renderer_start_stream = vmr_start_stream, .renderer_stop_stream = vmr_stop_stream, - .pfnShouldDrawSampleNow = VMR9_ShouldDrawSampleNow, .renderer_connect = vmr_connect, .pfnBreakConnect = VMR9_BreakConnect, .renderer_destroy = vmr_destroy,
The DirectSound renderer does a lot of things differently. To a large degree this is to be expected; it's an audio renderer and therefore needs to buffer much farther in advance. However, it also doesn't participate in quality management, doesn't block in Receive(), and has a few other mild differences in behaviour. Weighing the features implemented by the base renderer against the quirks necessary for the DirectSound renderer leads me to believe that it would be easier not to use that framework.
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/dsoundrender.c | 438 +++++++++++++++++++++++-------- dlls/quartz/tests/dsoundrender.c | 3 +- dlls/strmbase/strmbase_private.h | 4 - include/wine/strmbase.h | 4 + 4 files changed, 333 insertions(+), 116 deletions(-)
diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index fba206ecb60..a3155477fde 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -41,12 +41,25 @@ static const REFERENCE_TIME DSoundRenderer_Max_Fill = 150 * 10000;
struct dsound_render { - struct strmbase_renderer renderer; - - IBasicAudio IBasicAudio_iface; + struct strmbase_filter filter; + struct strmbase_passthrough passthrough; IAMDirectSound IAMDirectSound_iface; + IBasicAudio IBasicAudio_iface; + IQualityControl IQualityControl_iface; IUnknown *system_clock;
+ struct strmbase_sink sink; + + CRITICAL_SECTION stream_cs; + /* Signaled when the filter has completed a state change. The filter waits + * for this event in IBaseFilter::GetState(). */ + HANDLE state_event; + /* Signaled when a flush or state change occurs, i.e. anything that needs + * to immediately unblock the streaming thread. */ + HANDLE flush_event; + REFERENCE_TIME stream_start; + BOOL eos; + IDirectSound8 *dsound; LPDIRECTSOUNDBUFFER dsbuffer; DWORD buf_size; @@ -59,9 +72,14 @@ struct dsound_render LONG pan; };
-static struct dsound_render *impl_from_strmbase_renderer(struct strmbase_renderer *iface) +static struct dsound_render *impl_from_strmbase_pin(struct strmbase_pin *iface) { - return CONTAINING_RECORD(iface, struct dsound_render, renderer); + return CONTAINING_RECORD(iface, struct dsound_render, sink.pin); +} + +static struct dsound_render *impl_from_strmbase_filter(struct strmbase_filter *iface) +{ + return CONTAINING_RECORD(iface, struct dsound_render, filter); }
static struct dsound_render *impl_from_IBasicAudio(IBasicAudio *iface) @@ -76,7 +94,7 @@ static struct dsound_render *impl_from_IAMDirectSound(IAMDirectSound *iface)
static REFERENCE_TIME time_from_pos(struct dsound_render *This, DWORD pos) { - WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->renderer.sink.pin.mt.pbFormat; + WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->sink.pin.mt.pbFormat; REFERENCE_TIME ret = 10000000; ret = ret * pos / wfx->nAvgBytesPerSec; return ret; @@ -84,7 +102,7 @@ static REFERENCE_TIME time_from_pos(struct dsound_render *This, DWORD pos)
static DWORD pos_from_time(struct dsound_render *This, REFERENCE_TIME time) { - WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->renderer.sink.pin.mt.pbFormat; + WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->sink.pin.mt.pbFormat; REFERENCE_TIME ret = time; ret *= wfx->nAvgBytesPerSec; ret /= 10000000; @@ -94,7 +112,7 @@ static DWORD pos_from_time(struct dsound_render *This, REFERENCE_TIME time)
static void DSoundRender_UpdatePositions(struct dsound_render *This, DWORD *seqwritepos, DWORD *minwritepos) { - WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->renderer.sink.pin.mt.pbFormat; + WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->sink.pin.mt.pbFormat; BYTE *buf1, *buf2; DWORD size1, size2, playpos, writepos, old_writepos, old_playpos, adv; BOOL writepos_set = This->writepos < This->buf_size; @@ -133,17 +151,17 @@ static void DSoundRender_UpdatePositions(struct dsound_render *This, DWORD *seqw static HRESULT DSoundRender_GetWritePos(struct dsound_render *This, DWORD *ret_writepos, REFERENCE_TIME write_at, DWORD *pfree, DWORD *skip) { - WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->renderer.sink.pin.mt.pbFormat; + WAVEFORMATEX *wfx = (WAVEFORMATEX *)This->sink.pin.mt.pbFormat; DWORD writepos, min_writepos, playpos; REFERENCE_TIME max_lag = 50 * 10000; REFERENCE_TIME cur, writepos_t, delta_t;
DSoundRender_UpdatePositions(This, &writepos, &min_writepos); playpos = This->last_playpos; - if (This->renderer.filter.clock) + if (This->filter.clock) { - IReferenceClock_GetTime(This->renderer.filter.clock, &cur); - cur -= This->renderer.stream_start; + IReferenceClock_GetTime(This->filter.clock, &cur); + cur -= This->stream_start; } else write_at = -1;
@@ -212,7 +230,7 @@ end:
static HRESULT DSoundRender_HandleEndOfStream(struct dsound_render *This) { - while (This->renderer.filter.state == State_Running) + while (This->filter.state == State_Running) { DWORD pos1, pos2; DSoundRender_UpdatePositions(This, &pos1, &pos2); @@ -220,9 +238,9 @@ static HRESULT DSoundRender_HandleEndOfStream(struct dsound_render *This) break;
This->in_loop = 1; - LeaveCriticalSection(&This->renderer.csRenderLock); - WaitForSingleObject(This->renderer.flush_event, 10); - EnterCriticalSection(&This->renderer.csRenderLock); + LeaveCriticalSection(&This->stream_cs); + WaitForSingleObject(This->flush_event, 10); + EnterCriticalSection(&This->stream_cs); This->in_loop = 0; }
@@ -234,23 +252,23 @@ static HRESULT DSoundRender_SendSampleData(struct dsound_render *This, { HRESULT hr;
- while (size && This->renderer.filter.state != State_Stopped) { + while (size && This->filter.state != State_Stopped) { DWORD writepos, skip = 0, free, size1, size2, ret; BYTE *buf1, *buf2;
- if (This->renderer.filter.state == State_Running) + if (This->filter.state == State_Running) hr = DSoundRender_GetWritePos(This, &writepos, tStart, &free, &skip); else hr = S_FALSE;
if (hr != S_OK) { This->in_loop = 1; - LeaveCriticalSection(&This->renderer.csRenderLock); - ret = WaitForSingleObject(This->renderer.flush_event, 10); - EnterCriticalSection(&This->renderer.csRenderLock); + LeaveCriticalSection(&This->stream_cs); + ret = WaitForSingleObject(This->flush_event, 10); + EnterCriticalSection(&This->stream_cs); This->in_loop = 0; - if (This->renderer.sink.flushing || This->renderer.filter.state == State_Stopped) - return This->renderer.filter.state == State_Paused ? S_OK : VFW_E_WRONG_STATE; + if (This->sink.flushing || This->filter.state == State_Stopped) + return This->filter.state == State_Paused ? S_OK : VFW_E_WRONG_STATE; if (ret != WAIT_TIMEOUT) ERR("%x\n", ret); continue; @@ -281,26 +299,20 @@ static HRESULT DSoundRender_SendSampleData(struct dsound_render *This, return S_OK; }
-static HRESULT WINAPI DSoundRender_ShouldDrawSampleNow(struct strmbase_renderer *iface, - IMediaSample *sample, REFERENCE_TIME *start, REFERENCE_TIME *end) -{ - /* We time ourselves do not use the base renderers timing */ - return S_OK; -} - - -static HRESULT WINAPI DSoundRender_PrepareReceive(struct strmbase_renderer *iface, IMediaSample *pSample) +static HRESULT WINAPI DSoundRender_PrepareReceive(struct dsound_render *This, IMediaSample *pSample) { - struct dsound_render *This = impl_from_strmbase_renderer(iface); HRESULT hr; AM_MEDIA_TYPE *amt;
if (IMediaSample_GetMediaType(pSample, &amt) == S_OK) { - AM_MEDIA_TYPE *orig = &This->renderer.sink.pin.mt; + AM_MEDIA_TYPE *orig = &This->sink.pin.mt; WAVEFORMATEX *origfmt = (WAVEFORMATEX *)orig->pbFormat; WAVEFORMATEX *newfmt = (WAVEFORMATEX *)amt->pbFormat;
+ TRACE("Format change.\n"); + strmbase_dump_media_type(amt); + if (origfmt->wFormatTag == newfmt->wFormatTag && origfmt->nChannels == newfmt->nChannels && origfmt->nBlockAlign == newfmt->nBlockAlign && @@ -324,20 +336,13 @@ static HRESULT WINAPI DSoundRender_PrepareReceive(struct strmbase_renderer *ifac return S_OK; }
-static HRESULT WINAPI DSoundRender_DoRenderSample(struct strmbase_renderer *iface, IMediaSample *pSample) +static HRESULT WINAPI DSoundRender_DoRenderSample(struct dsound_render *This, IMediaSample *pSample) { - struct dsound_render *This = impl_from_strmbase_renderer(iface); LPBYTE pbSrcStream = NULL; LONG cbSrcStream = 0; REFERENCE_TIME tStart, tStop; HRESULT hr;
- TRACE("%p %p\n", iface, pSample); - - /* Slightly incorrect, Pause completes when a frame is received so we should signal - * pause completion here, but for sound playing a single frame doesn't make sense - */ - hr = IMediaSample_GetPointer(pSample, &pbSrcStream); if (FAILED(hr)) { @@ -363,39 +368,59 @@ static HRESULT WINAPI DSoundRender_DoRenderSample(struct strmbase_renderer *ifac return DSoundRender_SendSampleData(This, tStart, tStop, pbSrcStream, cbSrcStream); }
-static HRESULT WINAPI DSoundRender_CheckMediaType(struct strmbase_renderer *iface, const AM_MEDIA_TYPE * pmt) +static HRESULT WINAPI dsound_render_sink_Receive(struct strmbase_sink *iface, IMediaSample *sample) { - if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio)) + struct dsound_render *filter = impl_from_strmbase_pin(&iface->pin); + REFERENCE_TIME start, stop; + HRESULT hr; + + if (filter->eos || filter->sink.flushing) return S_FALSE;
- return S_OK; + if (filter->filter.state == State_Stopped) + return VFW_E_WRONG_STATE; + + if (FAILED(hr = DSoundRender_PrepareReceive(filter, sample))) + return hr; + + EnterCriticalSection(&filter->stream_cs); + + if (filter->filter.clock && SUCCEEDED(IMediaSample_GetTime(sample, &start, &stop))) + strmbase_passthrough_update_time(&filter->passthrough, start); + + if (filter->filter.state == State_Paused) + SetEvent(filter->state_event); + + hr = DSoundRender_DoRenderSample(filter, sample); + + LeaveCriticalSection(&filter->stream_cs); + return hr; }
-static void dsound_render_stop_stream(struct strmbase_renderer *iface) +static HRESULT dsound_render_sink_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) { - struct dsound_render *This = impl_from_strmbase_renderer(iface); + struct dsound_render *filter = impl_from_strmbase_pin(iface);
- TRACE("(%p/%p)->()\n", This, iface); + if (IsEqualGUID(iid, &IID_IMemInputPin)) + *out = &filter->sink.IMemInputPin_iface; + else + return E_NOINTERFACE;
- IDirectSoundBuffer_Stop(This->dsbuffer); - This->writepos = This->buf_size; + IUnknown_AddRef((IUnknown *)*out); + return S_OK; }
-static void dsound_render_start_stream(struct strmbase_renderer *iface) +static HRESULT dsound_render_sink_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE * pmt) { - struct dsound_render *This = impl_from_strmbase_renderer(iface); - - TRACE("(%p)\n", This); + if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Audio)) + return S_FALSE;
- if (This->renderer.sink.pin.peer) - { - IDirectSoundBuffer_Play(This->dsbuffer, 0, 0, DSBPLAY_LOOPING); - } + return S_OK; }
-static HRESULT dsound_render_connect(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt) +static HRESULT dsound_render_sink_connect(struct strmbase_sink *iface, IPin *peer, const AM_MEDIA_TYPE *mt) { - struct dsound_render *This = impl_from_strmbase_renderer(iface); + struct dsound_render *This = impl_from_strmbase_pin(&iface->pin); const WAVEFORMATEX *format = (WAVEFORMATEX *)mt->pbFormat; HRESULT hr = S_OK; DSBUFFERDESC buf_desc; @@ -436,47 +461,93 @@ static HRESULT dsound_render_connect(struct strmbase_renderer *iface, const AM_M return hr; }
-static HRESULT WINAPI DSoundRender_BreakConnect(struct strmbase_renderer *iface) +static void dsound_render_sink_disconnect(struct strmbase_sink *iface) { - struct dsound_render *This = impl_from_strmbase_renderer(iface); + struct dsound_render *This = impl_from_strmbase_pin(&iface->pin);
TRACE("(%p)->()\n", iface);
if (This->dsbuffer) IDirectSoundBuffer_Release(This->dsbuffer); This->dsbuffer = NULL; +} + +static HRESULT dsound_render_sink_eos(struct strmbase_sink *iface) +{ + struct dsound_render *filter = impl_from_strmbase_pin(&iface->pin); + IFilterGraph *graph = filter->filter.graph; + IMediaEventSink *event_sink; + + EnterCriticalSection(&filter->stream_cs);
+ filter->eos = TRUE; + + if (graph && SUCCEEDED(IFilterGraph_QueryInterface(graph, + &IID_IMediaEventSink, (void **)&event_sink))) + { + IMediaEventSink_Notify(event_sink, EC_COMPLETE, S_OK, + (LONG_PTR)&filter->filter.IBaseFilter_iface); + IMediaEventSink_Release(event_sink); + } + strmbase_passthrough_eos(&filter->passthrough); + SetEvent(filter->state_event); + + DSoundRender_HandleEndOfStream(filter); + + LeaveCriticalSection(&filter->stream_cs); return S_OK; }
-static HRESULT WINAPI DSoundRender_EndOfStream(struct strmbase_renderer *iface) +static HRESULT dsound_render_sink_begin_flush(struct strmbase_sink *iface) { - struct dsound_render *This = impl_from_strmbase_renderer(iface); - return DSoundRender_HandleEndOfStream(This); + struct dsound_render *filter = impl_from_strmbase_pin(&iface->pin); + + SetEvent(filter->flush_event); + return S_OK; }
-static HRESULT WINAPI DSoundRender_EndFlush(struct strmbase_renderer *iface) +static HRESULT dsound_render_sink_end_flush(struct strmbase_sink *iface) { - struct dsound_render *This = impl_from_strmbase_renderer(iface); + struct dsound_render *filter = impl_from_strmbase_pin(&iface->pin);
- if (This->dsbuffer) + EnterCriticalSection(&filter->stream_cs); + + filter->eos = FALSE; + strmbase_passthrough_invalidate_time(&filter->passthrough); + ResetEvent(filter->flush_event); + + if (filter->dsbuffer) { - LPBYTE buffer; + void *buffer; DWORD size;
/* Force a reset */ - IDirectSoundBuffer_Lock(This->dsbuffer, 0, 0, (LPVOID *)&buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER); + IDirectSoundBuffer_Lock(filter->dsbuffer, 0, 0, &buffer, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER); memset(buffer, 0, size); - IDirectSoundBuffer_Unlock(This->dsbuffer, buffer, size, NULL, 0); - This->writepos = This->buf_size; + IDirectSoundBuffer_Unlock(filter->dsbuffer, buffer, size, NULL, 0); + filter->writepos = filter->buf_size; }
+ LeaveCriticalSection(&filter->stream_cs); return S_OK; }
-static void dsound_render_destroy(struct strmbase_renderer *iface) +static const struct strmbase_sink_ops sink_ops = { - struct dsound_render *filter = impl_from_strmbase_renderer(iface); + .base.pin_query_interface = dsound_render_sink_query_interface, + .base.pin_query_accept = dsound_render_sink_query_accept, + .base.pin_get_media_type = strmbase_pin_get_media_type, + .pfnReceive = dsound_render_sink_Receive, + .sink_connect = dsound_render_sink_connect, + .sink_disconnect = dsound_render_sink_disconnect, + .sink_eos = dsound_render_sink_eos, + .sink_begin_flush = dsound_render_sink_begin_flush, + .sink_end_flush = dsound_render_sink_end_flush, +}; + +static void dsound_render_destroy(struct strmbase_filter *iface) +{ + struct dsound_render *filter = impl_from_strmbase_filter(iface);
if (filter->dsbuffer) IDirectSoundBuffer_Release(filter->dsbuffer); @@ -485,22 +556,49 @@ static void dsound_render_destroy(struct strmbase_renderer *iface) IDirectSound8_Release(filter->dsound); filter->dsound = NULL;
- strmbase_renderer_cleanup(&filter->renderer); + if (filter->sink.pin.peer) + IPin_Disconnect(filter->sink.pin.peer); + IPin_Disconnect(&filter->sink.pin.IPin_iface); + strmbase_sink_cleanup(&filter->sink); + + filter->stream_cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&filter->stream_cs); + + CloseHandle(filter->state_event); + CloseHandle(filter->flush_event); + + strmbase_passthrough_cleanup(&filter->passthrough); + strmbase_filter_cleanup(&filter->filter); free(filter);
InterlockedDecrement(&object_locks); }
-static HRESULT dsound_render_query_interface(struct strmbase_renderer *iface, REFIID iid, void **out) +static struct strmbase_pin *dsound_render_get_pin(struct strmbase_filter *iface, unsigned int index) { - struct dsound_render *filter = impl_from_strmbase_renderer(iface); + struct dsound_render *filter = impl_from_strmbase_filter(iface);
- if (IsEqualGUID(iid, &IID_IBasicAudio)) + if (index == 0) + return &filter->sink.pin; + return NULL; +} + +static HRESULT dsound_render_query_interface(struct strmbase_filter *iface, REFIID iid, void **out) +{ + struct dsound_render *filter = impl_from_strmbase_filter(iface); + + if (IsEqualGUID(iid, &IID_IAMDirectSound)) + *out = &filter->IAMDirectSound_iface; + else if (IsEqualGUID(iid, &IID_IBasicAudio)) *out = &filter->IBasicAudio_iface; + else if (IsEqualGUID(iid, &IID_IMediaPosition)) + *out = &filter->passthrough.IMediaPosition_iface; + else if (IsEqualGUID(iid, &IID_IMediaSeeking)) + *out = &filter->passthrough.IMediaSeeking_iface; + else if (IsEqualGUID(iid, &IID_IQualityControl)) + *out = &filter->IQualityControl_iface; else if (IsEqualGUID(iid, &IID_IReferenceClock)) return IUnknown_QueryInterface(filter->system_clock, iid, out); - else if (IsEqualGUID(iid, &IID_IAMDirectSound)) - *out = &filter->IAMDirectSound_iface; else return E_NOINTERFACE;
@@ -508,20 +606,77 @@ static HRESULT dsound_render_query_interface(struct strmbase_renderer *iface, RE return S_OK; }
-static const struct strmbase_renderer_ops renderer_ops = -{ - .pfnCheckMediaType = DSoundRender_CheckMediaType, - .pfnDoRenderSample = DSoundRender_DoRenderSample, - .renderer_start_stream = dsound_render_start_stream, - .renderer_stop_stream = dsound_render_stop_stream, - .pfnShouldDrawSampleNow = DSoundRender_ShouldDrawSampleNow, - .pfnPrepareReceive = DSoundRender_PrepareReceive, - .renderer_connect = dsound_render_connect, - .pfnBreakConnect = DSoundRender_BreakConnect, - .pfnEndOfStream = DSoundRender_EndOfStream, - .pfnEndFlush = DSoundRender_EndFlush, - .renderer_destroy = dsound_render_destroy, - .renderer_query_interface = dsound_render_query_interface, +static HRESULT dsound_render_init_stream(struct strmbase_filter *iface) +{ + struct dsound_render *filter = impl_from_strmbase_filter(iface); + + if (filter->sink.pin.peer) + ResetEvent(filter->state_event); + filter->eos = FALSE; + ResetEvent(filter->flush_event); + + return filter->sink.pin.peer ? S_FALSE : S_OK; +} + +static HRESULT dsound_render_start_stream(struct strmbase_filter *iface, REFERENCE_TIME start) +{ + struct dsound_render *filter = impl_from_strmbase_filter(iface); + + filter->stream_start = start; + + SetEvent(filter->state_event); + + if (filter->sink.pin.peer) + { + filter->eos = FALSE; + IDirectSoundBuffer_Play(filter->dsbuffer, 0, 0, DSBPLAY_LOOPING); + } + + return S_OK; +} + +static HRESULT dsound_render_stop_stream(struct strmbase_filter *iface) +{ + struct dsound_render *filter = impl_from_strmbase_filter(iface); + + if (filter->sink.pin.peer) + { + IDirectSoundBuffer_Stop(filter->dsbuffer); + filter->writepos = filter->buf_size; + } + return S_OK; +} + +static HRESULT dsound_render_cleanup_stream(struct strmbase_filter *iface) +{ + struct dsound_render *filter = impl_from_strmbase_filter(iface); + + strmbase_passthrough_invalidate_time(&filter->passthrough); + SetEvent(filter->state_event); + SetEvent(filter->flush_event); + + return S_OK; +} + +static HRESULT dsound_render_wait_state(struct strmbase_filter *iface, DWORD timeout) +{ + struct dsound_render *filter = impl_from_strmbase_filter(iface); + + if (WaitForSingleObject(filter->state_event, timeout) == WAIT_TIMEOUT) + return VFW_S_STATE_INTERMEDIATE; + return S_OK; +} + +static const struct strmbase_filter_ops filter_ops = +{ + .filter_destroy = dsound_render_destroy, + .filter_get_pin = dsound_render_get_pin, + .filter_query_interface = dsound_render_query_interface, + .filter_init_stream = dsound_render_init_stream, + .filter_start_stream = dsound_render_start_stream, + .filter_stop_stream = dsound_render_stop_stream, + .filter_cleanup_stream = dsound_render_cleanup_stream, + .filter_wait_state = dsound_render_wait_state, };
/*** IUnknown methods ***/ @@ -532,7 +687,7 @@ static HRESULT WINAPI Basicaudio_QueryInterface(IBasicAudio *iface,
TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
- return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppvObj); + return IUnknown_QueryInterface(This->filter.outer_unk, riid, ppvObj); }
static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) { @@ -540,7 +695,7 @@ static ULONG WINAPI Basicaudio_AddRef(IBasicAudio *iface) {
TRACE("(%p/%p)->()\n", This, iface);
- return IUnknown_AddRef(This->renderer.filter.outer_unk); + return IUnknown_AddRef(This->filter.outer_unk); }
static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) { @@ -548,7 +703,7 @@ static ULONG WINAPI Basicaudio_Release(IBasicAudio *iface) {
TRACE("(%p/%p)->()\n", This, iface);
- return IUnknown_Release(This->renderer.filter.outer_unk); + return IUnknown_Release(This->filter.outer_unk); }
HRESULT WINAPI basic_audio_GetTypeInfoCount(IBasicAudio *iface, UINT *count) @@ -685,7 +840,7 @@ static HRESULT WINAPI AMDirectSound_QueryInterface(IAMDirectSound *iface,
TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppvObj);
- return IUnknown_QueryInterface(This->renderer.filter.outer_unk, riid, ppvObj); + return IUnknown_QueryInterface(This->filter.outer_unk, riid, ppvObj); }
static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface) @@ -694,7 +849,7 @@ static ULONG WINAPI AMDirectSound_AddRef(IAMDirectSound *iface)
TRACE("(%p/%p)->()\n", This, iface);
- return IUnknown_AddRef(This->renderer.filter.outer_unk); + return IUnknown_AddRef(This->filter.outer_unk); }
static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface) @@ -703,7 +858,7 @@ static ULONG WINAPI AMDirectSound_Release(IAMDirectSound *iface)
TRACE("(%p/%p)->()\n", This, iface);
- return IUnknown_Release(This->renderer.filter.outer_unk); + return IUnknown_Release(This->filter.outer_unk); }
/*** IAMDirectSound methods ***/ @@ -794,6 +949,59 @@ static const IAMDirectSoundVtbl IAMDirectSound_Vtbl = AMDirectSound_GetFocusWindow };
+static struct dsound_render *impl_from_IQualityControl(IQualityControl *iface) +{ + return CONTAINING_RECORD(iface, struct dsound_render, IQualityControl_iface); +} + +static HRESULT WINAPI dsound_render_qc_QueryInterface(IQualityControl *iface, + REFIID iid, void **out) +{ + struct dsound_render *filter = impl_from_IQualityControl(iface); + return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out); +} + +static ULONG WINAPI dsound_render_qc_AddRef(IQualityControl *iface) +{ + struct dsound_render *filter = impl_from_IQualityControl(iface); + return IUnknown_AddRef(filter->filter.outer_unk); +} + +static ULONG WINAPI dsound_render_qc_Release(IQualityControl *iface) +{ + struct dsound_render *filter = impl_from_IQualityControl(iface); + return IUnknown_AddRef(filter->filter.outer_unk); +} + +static HRESULT WINAPI dsound_render_qc_Notify(IQualityControl *iface, + IBaseFilter *sender, Quality q) +{ + struct dsound_render *filter = impl_from_IQualityControl(iface); + + FIXME("filter %p, sender %p, type %#x, proportion %u, late %s, timestamp %s, stub!\n", + filter, sender, q.Type, q.Proportion, debugstr_time(q.Late), debugstr_time(q.TimeStamp)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI dsound_render_qc_SetSink(IQualityControl *iface, IQualityControl *sink) +{ + struct dsound_render *filter = impl_from_IQualityControl(iface); + + FIXME("filter %p, sink %p, stub!\n", filter, sink); + + return E_NOTIMPL; +} + +static const IQualityControlVtbl dsound_render_qc_vtbl = +{ + dsound_render_qc_QueryInterface, + dsound_render_qc_AddRef, + dsound_render_qc_Release, + dsound_render_qc_Notify, + dsound_render_qc_SetSink, +}; + HRESULT dsound_render_create(IUnknown *outer, IUnknown **out) { static const DSBUFFERDESC buffer_desc = { @@ -808,23 +1016,19 @@ HRESULT dsound_render_create(IUnknown *outer, IUnknown **out) if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
- strmbase_renderer_init(&object->renderer, outer, - &CLSID_DSoundRender, L"Audio Input pin (rendered)", &renderer_ops); + strmbase_filter_init(&object->filter, outer, &CLSID_DSoundRender, &filter_ops);
- if (FAILED(hr = system_clock_create(&object->renderer.filter.IUnknown_inner, &object->system_clock))) + if (FAILED(hr = system_clock_create(&object->filter.IUnknown_inner, &object->system_clock))) { - strmbase_renderer_cleanup(&object->renderer); + strmbase_filter_cleanup(&object->filter); free(object); return hr; }
- object->IBasicAudio_iface.lpVtbl = &IBasicAudio_Vtbl; - object->IAMDirectSound_iface.lpVtbl = &IAMDirectSound_Vtbl; - if (FAILED(hr = DirectSoundCreate8(NULL, &object->dsound, NULL))) { IUnknown_Release(object->system_clock); - strmbase_renderer_cleanup(&object->renderer); + strmbase_filter_cleanup(&object->filter); free(object); return hr; } @@ -834,7 +1038,7 @@ HRESULT dsound_render_create(IUnknown *outer, IUnknown **out) { IDirectSound8_Release(object->dsound); IUnknown_Release(object->system_clock); - strmbase_renderer_cleanup(&object->renderer); + strmbase_filter_cleanup(&object->filter); free(object); return hr; } @@ -846,8 +1050,22 @@ HRESULT dsound_render_create(IUnknown *outer, IUnknown **out) IDirectSoundBuffer_Release(buffer); }
+ strmbase_passthrough_init(&object->passthrough, (IUnknown *)&object->filter.IBaseFilter_iface); + ISeekingPassThru_Init(&object->passthrough.ISeekingPassThru_iface, TRUE, &object->sink.pin.IPin_iface); + + strmbase_sink_init(&object->sink, &object->filter, L"Audio Input pin (rendered)", &sink_ops, NULL); + + InitializeCriticalSection(&object->stream_cs); + object->stream_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": dsound_render.stream_cs"); + object->state_event = CreateEventW(NULL, TRUE, TRUE, NULL); + object->flush_event = CreateEventW(NULL, TRUE, TRUE, NULL); + + object->IBasicAudio_iface.lpVtbl = &IBasicAudio_Vtbl; + object->IAMDirectSound_iface.lpVtbl = &IAMDirectSound_Vtbl; + object->IQualityControl_iface.lpVtbl = &dsound_render_qc_vtbl; + TRACE("Created DirectSound renderer %p.\n", object); - *out = &object->renderer.filter.IUnknown_inner; + *out = &object->filter.IUnknown_inner;
return S_OK; } diff --git a/dlls/quartz/tests/dsoundrender.c b/dlls/quartz/tests/dsoundrender.c index 0e7fed4c259..9506abc7977 100644 --- a/dlls/quartz/tests/dsoundrender.c +++ b/dlls/quartz/tests/dsoundrender.c @@ -615,8 +615,7 @@ static const struct strmbase_filter_ops testfilter_ops =
static HRESULT testsource_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) { - todo_wine_if (IsEqualGUID(iid, &IID_IQualityControl)) - ok(!IsEqualGUID(iid, &IID_IQualityControl), "Unexpected query for IQualityControl.\n"); + ok(!IsEqualGUID(iid, &IID_IQualityControl), "Unexpected query for IQualityControl.\n"); return E_NOINTERFACE; }
diff --git a/dlls/strmbase/strmbase_private.h b/dlls/strmbase/strmbase_private.h index d589213b713..ff82d942813 100644 --- a/dlls/strmbase/strmbase_private.h +++ b/dlls/strmbase/strmbase_private.h @@ -58,8 +58,4 @@ void QualityControlRender_DoQOS(struct strmbase_qc *priv); void QualityControlRender_BeginRender(struct strmbase_qc *This, REFERENCE_TIME start, REFERENCE_TIME stop); void QualityControlRender_EndRender(struct strmbase_qc *This);
-void strmbase_passthrough_update_time(struct strmbase_passthrough *passthrough, REFERENCE_TIME time); -void strmbase_passthrough_invalidate_time(struct strmbase_passthrough *passthrough); -void strmbase_passthrough_eos(struct strmbase_passthrough *passthrough); - #endif /* __WINE_STRMBASE_PRIVATE_H */ diff --git a/include/wine/strmbase.h b/include/wine/strmbase.h index 2e84edb7cdd..9c3cdc4ac5e 100644 --- a/include/wine/strmbase.h +++ b/include/wine/strmbase.h @@ -271,6 +271,10 @@ struct strmbase_passthrough void strmbase_passthrough_init(struct strmbase_passthrough *passthrough, IUnknown *outer); void strmbase_passthrough_cleanup(struct strmbase_passthrough *passthrough);
+void strmbase_passthrough_eos(struct strmbase_passthrough *passthrough); +void strmbase_passthrough_invalidate_time(struct strmbase_passthrough *passthrough); +void strmbase_passthrough_update_time(struct strmbase_passthrough *passthrough, REFERENCE_TIME time); + struct strmbase_qc { IQualityControl IQualityControl_iface;
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/strmbase/renderer.c | 86 ++++++++++++---------------------------- include/wine/strmbase.h | 10 ----- 2 files changed, 25 insertions(+), 71 deletions(-)
diff --git a/dlls/strmbase/renderer.c b/dlls/strmbase/renderer.c index 939811bfa90..1f0a747a2ce 100644 --- a/dlls/strmbase/renderer.c +++ b/dlls/strmbase/renderer.c @@ -194,7 +194,6 @@ static HRESULT sink_eos(struct strmbase_sink *iface) struct strmbase_renderer *filter = impl_from_IPin(&iface->pin.IPin_iface); IFilterGraph *graph = filter->filter.graph; IMediaEventSink *event_sink; - HRESULT hr = S_OK;
EnterCriticalSection(&filter->csRenderLock);
@@ -210,11 +209,8 @@ static HRESULT sink_eos(struct strmbase_sink *iface) strmbase_passthrough_eos(&filter->passthrough); SetEvent(filter->state_event);
- if (filter->pFuncsTable->pfnEndOfStream) - hr = filter->pFuncsTable->pfnEndOfStream(filter); - LeaveCriticalSection(&filter->csRenderLock); - return hr; + return S_OK; }
static HRESULT sink_begin_flush(struct strmbase_sink *iface) @@ -229,7 +225,6 @@ static HRESULT sink_begin_flush(struct strmbase_sink *iface) static HRESULT sink_end_flush(struct strmbase_sink *iface) { struct strmbase_renderer *filter = impl_from_IPin(&iface->pin.IPin_iface); - HRESULT hr = S_OK;
EnterCriticalSection(&filter->csRenderLock);
@@ -238,11 +233,8 @@ static HRESULT sink_end_flush(struct strmbase_sink *iface) strmbase_passthrough_invalidate_time(&filter->passthrough); ResetEvent(filter->flush_event);
- if (filter->pFuncsTable->pfnEndFlush) - hr = filter->pFuncsTable->pfnEndFlush(filter); - LeaveCriticalSection(&filter->csRenderLock); - return hr; + return S_OK; }
static const struct strmbase_sink_ops sink_ops = @@ -277,9 +269,9 @@ void strmbase_renderer_cleanup(struct strmbase_renderer *filter)
HRESULT WINAPI BaseRendererImpl_Receive(struct strmbase_renderer *This, IMediaSample *pSample) { - HRESULT hr = S_OK; REFERENCE_TIME start, stop; AM_MEDIA_TYPE *pmt; + HRESULT hr;
TRACE("(%p)->%p\n", This, pSample);
@@ -301,16 +293,6 @@ HRESULT WINAPI BaseRendererImpl_Receive(struct strmbase_renderer *This, IMediaSa DeleteMediaType(pmt); }
- if (This->pFuncsTable->pfnPrepareReceive) - hr = This->pFuncsTable->pfnPrepareReceive(This, pSample); - if (FAILED(hr)) - { - if (hr == VFW_E_SAMPLE_REJECTED) - return S_OK; - else - return hr; - } - EnterCriticalSection(&This->csRenderLock); if (This->filter.state == State_Paused) SetEvent(This->state_event); @@ -318,59 +300,41 @@ HRESULT WINAPI BaseRendererImpl_Receive(struct strmbase_renderer *This, IMediaSa /* Wait for render Time */ if (This->filter.clock && SUCCEEDED(IMediaSample_GetTime(pSample, &start, &stop))) { - hr = S_FALSE; - strmbase_passthrough_update_time(&This->passthrough, start); - if (This->pFuncsTable->pfnShouldDrawSampleNow) - hr = This->pFuncsTable->pfnShouldDrawSampleNow(This, pSample, &start, &stop); - - if (hr == S_OK) - ;/* Do not wait: drop through */ - else if (hr == S_FALSE) - { - REFERENCE_TIME now; - DWORD_PTR cookie; + REFERENCE_TIME now; + DWORD_PTR cookie;
- IReferenceClock_GetTime(This->filter.clock, &now); + strmbase_passthrough_update_time(&This->passthrough, start);
- if (now - This->stream_start - start <= -10000) - { - HANDLE handles[2] = {This->advise_event, This->flush_event}; - DWORD ret; + IReferenceClock_GetTime(This->filter.clock, &now);
- IReferenceClock_AdviseTime(This->filter.clock, This->stream_start, - start, (HEVENT)This->advise_event, &cookie); + if (now - This->stream_start - start <= -10000) + { + HANDLE handles[2] = {This->advise_event, This->flush_event}; + DWORD ret;
- LeaveCriticalSection(&This->csRenderLock); + IReferenceClock_AdviseTime(This->filter.clock, This->stream_start, + start, (HEVENT)This->advise_event, &cookie);
- ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE); - IReferenceClock_Unadvise(This->filter.clock, cookie); + LeaveCriticalSection(&This->csRenderLock);
- if (ret == 1) - { - TRACE("Flush signaled, discarding current sample.\n"); - return S_OK; - } + ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE); + IReferenceClock_Unadvise(This->filter.clock, cookie);
- EnterCriticalSection(&This->csRenderLock); + if (ret == 1) + { + TRACE("Flush signaled, discarding current sample.\n"); + return S_OK; } - } - else - { - LeaveCriticalSection(&This->csRenderLock); - /* Drop Sample */ - return S_OK; + + EnterCriticalSection(&This->csRenderLock); } } else start = stop = -1;
- if (SUCCEEDED(hr)) - { - QualityControlRender_BeginRender(&This->qc, start, stop); - hr = This->pFuncsTable->pfnDoRenderSample(This, pSample); - QualityControlRender_EndRender(&This->qc); - } - + QualityControlRender_BeginRender(&This->qc, start, stop); + hr = This->pFuncsTable->pfnDoRenderSample(This, pSample); + QualityControlRender_EndRender(&This->qc); QualityControlRender_DoQOS(&This->qc);
LeaveCriticalSection(&This->csRenderLock); diff --git a/include/wine/strmbase.h b/include/wine/strmbase.h index 9c3cdc4ac5e..9e0d4e7d479 100644 --- a/include/wine/strmbase.h +++ b/include/wine/strmbase.h @@ -318,12 +318,6 @@ struct strmbase_renderer
typedef HRESULT (WINAPI *BaseRenderer_CheckMediaType)(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt); typedef HRESULT (WINAPI *BaseRenderer_DoRenderSample)(struct strmbase_renderer *iface, IMediaSample *sample); -typedef HRESULT (WINAPI *BaseRenderer_ShouldDrawSampleNow)(struct strmbase_renderer *iface, - IMediaSample *sample, REFERENCE_TIME *start, REFERENCE_TIME *end); -typedef HRESULT (WINAPI *BaseRenderer_PrepareReceive)(struct strmbase_renderer *iface, IMediaSample *sample); -typedef HRESULT (WINAPI *BaseRenderer_EndOfStream)(struct strmbase_renderer *iface); -typedef HRESULT (WINAPI *BaseRenderer_BeginFlush) (struct strmbase_renderer *iface); -typedef HRESULT (WINAPI *BaseRenderer_EndFlush) (struct strmbase_renderer *iface); typedef HRESULT (WINAPI *BaseRenderer_BreakConnect) (struct strmbase_renderer *iface);
struct strmbase_renderer_ops @@ -333,12 +327,8 @@ struct strmbase_renderer_ops void (*renderer_init_stream)(struct strmbase_renderer *iface); void (*renderer_start_stream)(struct strmbase_renderer *iface); void (*renderer_stop_stream)(struct strmbase_renderer *iface); - BaseRenderer_ShouldDrawSampleNow pfnShouldDrawSampleNow; - BaseRenderer_PrepareReceive pfnPrepareReceive; HRESULT (*renderer_connect)(struct strmbase_renderer *iface, const AM_MEDIA_TYPE *mt); BaseRenderer_BreakConnect pfnBreakConnect; - BaseRenderer_EndOfStream pfnEndOfStream; - BaseRenderer_EndFlush pfnEndFlush; void (*renderer_destroy)(struct strmbase_renderer *iface); HRESULT (*renderer_query_interface)(struct strmbase_renderer *iface, REFIID iid, void **out); HRESULT (*renderer_pin_query_interface)(struct strmbase_renderer *iface, REFIID iid, void **out);