This fixes media replay for BlazeBlue.
From: Ziqing Hui zhui@codeweavers.com
This fixes media replay for BlazeBlue. --- dlls/qasf/asfreader.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index 91fdc6fbb34..6aa04453f27 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -286,8 +286,32 @@ static inline struct asf_stream *impl_from_IMediaSeeking(IMediaSeeking *iface)
static HRESULT WINAPI media_seeking_ChangeCurrent(IMediaSeeking *iface) { - FIXME("iface %p stub!\n", iface); - return S_OK; + struct asf_stream *stream = impl_from_IMediaSeeking(iface); + struct asf_reader *filter = asf_reader_from_asf_stream(stream); + SourceSeeking *seek = &stream->seek; + HRESULT hr; + UINT i; + + TRACE("iface %p.\n", iface); + + for (i = 0; i < filter->stream_count; ++i) + { + if (FAILED(IPin_BeginFlush(stream->source.pin.peer))) + WARN("Failed to BeginFlush for stream %u.\n", i); + } + + hr = IBaseFilter_Stop(&filter->filter.IBaseFilter_iface); + + for (i = 0; i < filter->stream_count; ++i) + { + if (FAILED(IPin_EndFlush(stream->source.pin.peer))) + WARN("Failed to EndFlush for stream %u.\n", i); + } + + if (hr == S_OK) + hr = IWMReader_Start(filter->reader, seek->llCurrent, seek->llDuration, seek->dRate, NULL); + + return hr; }
static HRESULT WINAPI media_seeking_ChangeStop(IMediaSeeking *iface)
Do I need to add a test patch for this?
As if it's that easy. I wasted 2 weeks on this 😂😭
On Wed Sep 24 12:57:37 2025 +0000, Bernhard Kölbl wrote:
As if it's that easy. I wasted 2 weeks on this 😂😭
The patch is easy, but figuring out how to easily do this is not too easy.
* We should be respecting the AM_SEEKING_NoFlush flags.
* We should check for stopped state; we don't want to flush anything if not stopped.
* Stopping the filter seems wrong. Did you mean to stop the IWMReader? I don't think even that's necessary, though.
Do I need to add a test patch for this?
I'm not sure that there's a way to reliably test.
- We should be respecting the AM_SEEKING_NoFlush flags.
OK, I'll add this in new version.
- We should check for stopped state; we don't want to flush anything if not stopped.
- Stopping the filter seems wrong. Did you mean to stop the IWMReader? I don't think even that's necessary, though.
I don't think so. See https://learn.microsoft.com/en-us/windows/win32/directshow/supporting-seekin....
The document talks about seeking on condition of streaming thread running, so I don't think we should only send flush command downstream in stop state. If not in stop state, we drop the pending buffers by flushing, downstream filters chould handle this.
Stopping the filter is necessary, it finally calls asf_reader_cleanup_stream() to decommit the allocator to prevent futher buffer allocating. Buffer allocating failure makes upstream filters unable to send more buffers downstream, which is what we expected when we are seeking. If we don't, there may be race conditions, although I can not precisely says what condition it is.
I don't think so. See https://learn.microsoft.com/en-us/windows/win32/directshow/supporting-seekin....
Okay, I'm surprised it recommends actually calling Stop() [though note that you also have to put it back in paused state afterward, which this patch is missing]. Stop() is a bit of a heavy hammer, though, and I don't think we need it here.
The document talks about seeking on condition of streaming thread running, so I don't think we should only send flush command downstream in stop state. If not in stop state, we drop the pending buffers by flushing, downstream filters chould handle this.
Stopping the filter is necessary, it finally calls asf_reader_cleanup_stream() to decommit the allocator to prevent futher buffer allocating. Buffer allocating failure makes upstream filters unable to send more buffers downstream, which is what we expected when we are seeking. If we don't, there may be race conditions, although I can not precisely says what condition it is.
You don't need to stop the filter to prevent that. In fact, that's exactly what flushing is for.
You don't need to stop the filter to prevent that. In fact, that's exactly what flushing is for.
Decommit the allocator is needed, becides, we need to stop the reader thread, which means we need to stop the IWMReader. And that's exactly what asf_reader_cleanup_stream() does. So maybe we could replace IBaseFiler_Stop() with asf_reader_cleanup_stream()?
[though note that you also have to put it back in paused state afterward, which this patch is missing]
I'm not sure if Pause() are necessary, the Pause() in the document is to restart the thread and start pushing data again. We have IWMReader_Start() which did this.
You don't need to stop the filter to prevent that. In fact, that's exactly what flushing is for.
Decommit the allocator is needed,
Why? Why isn't flushing enough?
becides, we need to stop the reader thread, which means we need to stop the IWMReader. And that's exactly what asf_reader_cleanup_stream() does. So maybe we could replace IBaseFiler_Stop() with asf_reader_cleanup_stream()?
Just IWMReader_Stop() would be enough.
[though note that you also have to put it back in paused state afterward, which this patch is missing]
I'm not sure if Pause() are necessary, the Pause() in the document is to restart the thread and start pushing data again. We have IWMReader_Start() which did this.
Well, you can't leave the filter in stopped state. SetPositions() isn't supposed to change the state. If you are going to call IBaseFilter_Stop() then you need to call IBaseFilter_Pause(). If you're only going to call IWMReader_Start() then you should only call IWMReader_Stop().
[though note that you also have to put it back in paused state afterward, which this patch is missing]
I'm not sure if Pause() are necessary, the Pause() in the document is to restart the thread and start pushing data again. We have IWMReader_Start() which did this.
Well, you can't leave the filter in stopped state. SetPositions() isn't supposed to change the state. If you are going to call IBaseFilter_Stop() then you need to call IBaseFilter_Pause(). If you're only going to call IWMReader_Start() then you should only call IWMReader_Stop().
OK, I see, I'll change it in next version.