-- v4: qasf: Configure WMReader stream selection in asf_reader_init_stream. qasf: Configure WMReader stream format in asf_reader_init_stream. winegstreamer: Implement IWMOutputMediaProps_SetMediaType. qasf: Implement ASF Reader filter init_stream and cleanup_stream. qasf: Implement ASF Reader filter pin DecideBufferSize. qasf: Implement ASF Reader filter pin_get_media_type.
From: Rémi Bernon rbernon@codeweavers.com
And name pins accordingly.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/qasf/asfreader.c | 58 ++++++++++++++++++++++++++++++++++++- dlls/qasf/tests/asfreader.c | 4 +-- 2 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index 13b6e2d7bbe..8c042e72773 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -48,6 +48,52 @@ struct asf_reader struct asf_stream streams[16]; };
+static inline struct asf_stream *impl_from_strmbase_pin(struct strmbase_pin *iface) +{ + return CONTAINING_RECORD(iface, struct asf_stream, source.pin); +} + +static inline struct asf_reader *asf_reader_from_asf_stream(struct asf_stream *stream) +{ + return CONTAINING_RECORD(stream, struct asf_reader, streams[stream->index]); +} + +static HRESULT asf_stream_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *media_type) +{ + struct asf_stream *stream = impl_from_strmbase_pin(iface); + struct asf_reader *filter = asf_reader_from_asf_stream(stream); + IWMOutputMediaProps *props; + AM_MEDIA_TYPE *mt; + DWORD size; + HRESULT hr; + + TRACE("iface %p, index %u, media_type %p.\n", iface, index, media_type); + + if (FAILED(IWMReader_GetOutputFormat(filter->reader, stream->index, index, &props))) + return VFW_S_NO_MORE_ITEMS; + + if (FAILED(hr = IWMOutputMediaProps_GetMediaType(props, NULL, &size))) + { + IWMOutputMediaProps_Release(props); + return hr; + } + + if (!(mt = malloc(size))) + { + IWMOutputMediaProps_Release(props); + return E_OUTOFMEMORY; + } + + hr = IWMOutputMediaProps_GetMediaType(props, (WM_MEDIA_TYPE *)mt, &size); + if (SUCCEEDED(hr)) + hr = CopyMediaType(media_type, mt); + + free(mt); + + IWMOutputMediaProps_Release(props); + return hr; +} + static inline struct asf_reader *impl_from_strmbase_filter(struct strmbase_filter *iface) { return CONTAINING_RECORD(iface, struct asf_reader, filter); @@ -120,6 +166,7 @@ static HRESULT WINAPI asf_reader_DecideBufferSize(struct strmbase_source *iface,
static const struct strmbase_source_ops source_ops = { + .base.pin_get_media_type = asf_stream_get_media_type, .pfnDecideAllocator = BaseOutputPinImpl_DecideAllocator, .pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection, .pfnDecideBufferSize = asf_reader_DecideBufferSize, @@ -275,6 +322,7 @@ static HRESULT WINAPI reader_callback_OnStatus(IWMReaderCallback *iface, WMT_STA WMT_ATTR_DATATYPE type, BYTE *value, void *context) { struct asf_reader *filter = impl_from_IWMReaderCallback(iface)->filter; + AM_MEDIA_TYPE stream_media_type = {0}; DWORD i, stream_count; WCHAR name[MAX_PATH];
@@ -304,7 +352,15 @@ static HRESULT WINAPI reader_callback_OnStatus(IWMReaderCallback *iface, WMT_STA for (i = 0; i < stream_count; ++i) { struct asf_stream *stream = filter->streams + i; - swprintf(name, ARRAY_SIZE(name), L"Raw Stream %u", stream->index); + + if (FAILED(hr = asf_stream_get_media_type(&stream->source.pin, 0, &stream_media_type))) + WARN("Failed to get stream media type, hr %#lx.\n", hr); + if (IsEqualGUID(&stream_media_type.majortype, &MEDIATYPE_Video)) + swprintf(name, ARRAY_SIZE(name), L"Raw Video %u", stream->index); + else + swprintf(name, ARRAY_SIZE(name), L"Raw Audio %u", stream->index); + FreeMediaType(&stream_media_type); + strmbase_source_init(&stream->source, &filter->filter, name, &source_ops); } filter->stream_count = stream_count; diff --git a/dlls/qasf/tests/asfreader.c b/dlls/qasf/tests/asfreader.c index 494d0384ac8..ed78a856003 100644 --- a/dlls/qasf/tests/asfreader.c +++ b/dlls/qasf/tests/asfreader.c @@ -231,13 +231,11 @@ static void check_pin(IPin *pin, IBaseFilter *expect_filter, PIN_DIRECTION expec ok(hr == S_OK, "Got hr %#lx.\n", hr); ok(info.pFilter == expect_filter, "Got filter %p.\n", info.pFilter); ok(info.dir == expect_dir, "Got dir %#x.\n", info.dir); - todo_wine ok(!wcscmp(info.achName, expect_name), "Got name %s.\n", debugstr_w(info.achName)); IBaseFilter_Release(info.pFilter);
hr = IPin_QueryId(pin, &id); ok(hr == S_OK, "Got hr %#lx.\n", hr); - todo_wine ok(!wcscmp(id, expect_id), "Got id %s.\n", debugstr_w(id)); CoTaskMemFree(id);
@@ -253,7 +251,7 @@ static void check_pin(IPin *pin, IBaseFilter *expect_filter, PIN_DIRECTION expec FreeMediaType(mt); CoTaskMemFree(mt); } - todo_wine + todo_wine_if(IsEqualGUID(&expect_mt[0].majortype, &MEDIATYPE_Video)) ok(i == expect_mt_count, "Got %u types.\n", i); ok(hr == S_FALSE, "Got hr %#lx.\n", hr); IEnumMediaTypes_Release(enum_mt);
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/qasf/asfreader.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index 8c042e72773..4fa9136982d 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -160,8 +160,29 @@ static const struct strmbase_filter_ops filter_ops = static HRESULT WINAPI asf_reader_DecideBufferSize(struct strmbase_source *iface, IMemAllocator *allocator, ALLOCATOR_PROPERTIES *req_props) { - FIXME("iface %p, allocator %p, req_props %p stub!\n", iface, allocator, req_props); - return E_NOTIMPL; + struct asf_stream *stream = impl_from_strmbase_pin(&iface->pin); + unsigned int buffer_size = 16384; + ALLOCATOR_PROPERTIES ret_props; + + TRACE("iface %p, allocator %p, req_props %p.\n", iface, allocator, req_props); + + if (IsEqualGUID(&stream->source.pin.mt.formattype, &FORMAT_VideoInfo)) + { + VIDEOINFOHEADER *format = (VIDEOINFOHEADER *)stream->source.pin.mt.pbFormat; + buffer_size = format->bmiHeader.biSizeImage; + } + else if (IsEqualGUID(&stream->source.pin.mt.formattype, &FORMAT_WaveFormatEx) + && (IsEqualGUID(&stream->source.pin.mt.subtype, &MEDIASUBTYPE_PCM) + || IsEqualGUID(&stream->source.pin.mt.subtype, &MEDIASUBTYPE_IEEE_FLOAT))) + { + WAVEFORMATEX *format = (WAVEFORMATEX *)stream->source.pin.mt.pbFormat; + buffer_size = format->nAvgBytesPerSec; + } + + req_props->cBuffers = max(req_props->cBuffers, 1); + req_props->cbBuffer = max(req_props->cbBuffer, buffer_size); + req_props->cbAlign = max(req_props->cbAlign, 1); + return IMemAllocator_SetProperties(allocator, req_props, &ret_props); }
static const struct strmbase_source_ops source_ops =
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/qasf/asfreader.c | 69 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+)
diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index 4fa9136982d..db976f36752 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -150,11 +150,66 @@ static HRESULT asf_reader_query_interface(struct strmbase_filter *iface, REFIID return E_NOINTERFACE; }
+static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) +{ + struct asf_reader *filter = impl_from_strmbase_filter(iface); + HRESULT hr; + int i; + + TRACE("iface %p\n", iface); + + for (i = 0; i < filter->stream_count; ++i) + { + struct asf_stream *stream = filter->streams + i; + + if (!stream->source.pin.peer) + continue; + + hr = IMemAllocator_Commit(stream->source.pAllocator); + if (FAILED(hr)) + { + WARN("Failed to commit stream %u allocator, hr %#lx\n", i, hr); + continue; + } + + hr = IPin_NewSegment(stream->source.pin.peer, 0, 0, 1); + if (FAILED(hr)) + { + WARN("Failed to start stream %u new segment, hr %#lx\n", i, hr); + continue; + } + } + + return IWMReader_Start(filter->reader, 0, 0, 1, NULL); +} + +static HRESULT asf_reader_cleanup_stream(struct strmbase_filter *iface) +{ + struct asf_reader *filter = impl_from_strmbase_filter(iface); + int i; + + TRACE("iface %p\n", iface); + + for (i = 0; i < filter->stream_count; ++i) + { + struct asf_stream *stream = filter->streams + i; + + if (!stream->source.pin.peer) + continue; + + IMemAllocator_Decommit(stream->source.pAllocator); + } + + return S_OK; +} + static const struct strmbase_filter_ops filter_ops = { .filter_get_pin = asf_reader_get_pin, .filter_destroy = asf_reader_destroy, .filter_query_interface = asf_reader_query_interface, + .filter_init_stream = asf_reader_init_stream, + .filter_cleanup_stream = asf_reader_cleanup_stream, };
static HRESULT WINAPI asf_reader_DecideBufferSize(struct strmbase_source *iface, @@ -390,6 +445,20 @@ static HRESULT WINAPI reader_callback_OnStatus(IWMReaderCallback *iface, WMT_STA BaseFilterImpl_IncrementPinVersion(&filter->filter); break;
+ case WMT_END_OF_STREAMING: + EnterCriticalSection(&filter->filter.filter_cs); + for (i = 0; i < filter->stream_count; ++i) + { + struct asf_stream *stream = filter->streams + i; + + if (!stream->source.pin.peer) + continue; + + IPin_EndOfStream(stream->source.pin.peer); + } + LeaveCriticalSection(&filter->filter.filter_cs); + break; + default: WARN("Ignoring status %#x.\n", status); break;
On 6/15/22 01:58, Rémi Bernon wrote:
+static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) +{
- struct asf_reader *filter = impl_from_strmbase_filter(iface);
- HRESULT hr;
- int i;
- TRACE("iface %p\n", iface);
- for (i = 0; i < filter->stream_count; ++i)
- {
struct asf_stream *stream = filter->streams + i;
if (!stream->source.pin.peer)
continue;
hr = IMemAllocator_Commit(stream->source.pAllocator);
if (FAILED(hr))
{
WARN("Failed to commit stream %u allocator, hr %#lx\n", i, hr);
continue;
}
hr = IPin_NewSegment(stream->source.pin.peer, 0, 0, 1);
if (FAILED(hr))
{
WARN("Failed to start stream %u new segment, hr %#lx\n", i, hr);
continue;
}
- }
- return IWMReader_Start(filter->reader, 0, 0, 1, NULL);
+}
+static HRESULT asf_reader_cleanup_stream(struct strmbase_filter *iface) +{
- struct asf_reader *filter = impl_from_strmbase_filter(iface);
- int i;
- TRACE("iface %p\n", iface);
Shouldn't the reader be stopped here?
- for (i = 0; i < filter->stream_count; ++i)
- {
struct asf_stream *stream = filter->streams + i;
if (!stream->source.pin.peer)
continue;
IMemAllocator_Decommit(stream->source.pAllocator);
- }
- return S_OK;
+}
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winegstreamer/wm_reader.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 03adea8a318..a235f2d15c6 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -116,8 +116,12 @@ static HRESULT WINAPI output_props_GetMediaType(IWMOutputMediaProps *iface, WM_M
static HRESULT WINAPI output_props_SetMediaType(IWMOutputMediaProps *iface, WM_MEDIA_TYPE *mt) { - FIXME("iface %p, mt %p, stub!\n", iface, mt); - return E_NOTIMPL; + const struct output_props *props = impl_from_IWMOutputMediaProps(iface); + + TRACE("iface %p, mt %p.\n", iface, mt); + + FreeMediaType((AM_MEDIA_TYPE *)&props->mt); + return CopyMediaType((AM_MEDIA_TYPE *)&props->mt, (AM_MEDIA_TYPE *)mt); }
static HRESULT WINAPI output_props_GetStreamGroupName(IWMOutputMediaProps *iface, WCHAR *name, WORD *len)
On 6/15/22 01:58, Rémi Bernon wrote:
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/winegstreamer/wm_reader.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 03adea8a318..a235f2d15c6 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -116,8 +116,12 @@ static HRESULT WINAPI output_props_GetMediaType(IWMOutputMediaProps *iface, WM_M
static HRESULT WINAPI output_props_SetMediaType(IWMOutputMediaProps *iface, WM_MEDIA_TYPE *mt) {
- FIXME("iface %p, mt %p, stub!\n", iface, mt);
- return E_NOTIMPL;
const struct output_props *props = impl_from_IWMOutputMediaProps(iface);
TRACE("iface %p, mt %p.\n", iface, mt);
FreeMediaType((AM_MEDIA_TYPE *)&props->mt);
return CopyMediaType((AM_MEDIA_TYPE *)&props->mt, (AM_MEDIA_TYPE *)mt); }
static HRESULT WINAPI output_props_GetStreamGroupName(IWMOutputMediaProps *iface, WCHAR *name, WORD *len)
I think this deserves tests. The lack of media type validation in particular is concerning.
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/qasf/asfreader.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index db976f36752..6db1a5ca01f 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -161,6 +161,7 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) for (i = 0; i < filter->stream_count; ++i) { struct asf_stream *stream = filter->streams + i; + IWMOutputMediaProps *props;
if (!stream->source.pin.peer) continue; @@ -178,6 +179,23 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) WARN("Failed to start stream %u new segment, hr %#lx\n", i, hr); continue; } + + hr = IWMReader_GetOutputFormat(filter->reader, stream->index, 0, &props); + if (FAILED(hr)) + { + WARN("Failed to get stream %u output format, hr %#lx\n", i, hr); + continue; + } + + hr = IWMOutputMediaProps_SetMediaType(props, (WM_MEDIA_TYPE *)&stream->source.pin.mt); + if (SUCCEEDED(hr)) + hr = IWMReader_SetOutputProps(filter->reader, stream->index, props); + IWMOutputMediaProps_Release(props); + if (FAILED(hr)) + { + WARN("Failed to set stream %u output format, hr %#lx\n", i, hr); + continue; + } }
return IWMReader_Start(filter->reader, 0, 0, 1, NULL);
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/qasf/asfreader.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index 6db1a5ca01f..40011cb4b30 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -153,11 +153,23 @@ static HRESULT asf_reader_query_interface(struct strmbase_filter *iface, REFIID static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) { struct asf_reader *filter = impl_from_strmbase_filter(iface); + WMT_STREAM_SELECTION selections[ARRAY_SIZE(filter->streams)]; + WORD stream_numbers[ARRAY_SIZE(filter->streams)]; + IWMReaderAdvanced *reader_advanced; HRESULT hr; int i;
TRACE("iface %p\n", iface);
+ if (FAILED(hr = IWMReader_QueryInterface(filter->reader, &IID_IWMReaderAdvanced, (void **)&reader_advanced))) + return hr; + + for (i = 0; i < ARRAY_SIZE(selections); ++i) + { + stream_numbers[i] = i + 1; + selections[i] = WMT_OFF; + } + for (i = 0; i < filter->stream_count; ++i) { struct asf_stream *stream = filter->streams + i; @@ -196,8 +208,18 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) WARN("Failed to set stream %u output format, hr %#lx\n", i, hr); continue; } + + selections[i] = WMT_ON; }
+ hr = IWMReaderAdvanced_SetStreamsSelected(reader_advanced, filter->stream_count, stream_numbers, selections); + if (FAILED(hr)) + { + WARN("Failed to set stream selection, hr %#lx\n", hr); + } + + IWMReaderAdvanced_Release(reader_advanced); + return IWMReader_Start(filter->reader, 0, 0, 1, NULL); }
On 6/15/22 01:58, Rémi Bernon wrote:
From: Rémi Bernon rbernon@codeweavers.com
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/qasf/asfreader.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c index 6db1a5ca01f..40011cb4b30 100644 --- a/dlls/qasf/asfreader.c +++ b/dlls/qasf/asfreader.c @@ -153,11 +153,23 @@ static HRESULT asf_reader_query_interface(struct strmbase_filter *iface, REFIID static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) { struct asf_reader *filter = impl_from_strmbase_filter(iface);
WMT_STREAM_SELECTION selections[ARRAY_SIZE(filter->streams)];
WORD stream_numbers[ARRAY_SIZE(filter->streams)];
IWMReaderAdvanced *reader_advanced; HRESULT hr; int i;
TRACE("iface %p\n", iface);
if (FAILED(hr = IWMReader_QueryInterface(filter->reader, &IID_IWMReaderAdvanced, (void **)&reader_advanced)))
return hr;
for (i = 0; i < ARRAY_SIZE(selections); ++i)
{
stream_numbers[i] = i + 1;
selections[i] = WMT_OFF;
}
Can we move this into the below loop?
for (i = 0; i < filter->stream_count; ++i) { struct asf_stream *stream = filter->streams + i;
@@ -196,8 +208,18 @@ static HRESULT asf_reader_init_stream(struct strmbase_filter *iface) WARN("Failed to set stream %u output format, hr %#lx\n", i, hr); continue; }
selections[i] = WMT_ON; }
hr = IWMReaderAdvanced_SetStreamsSelected(reader_advanced, filter->stream_count, stream_numbers, selections);
if (FAILED(hr))
{
WARN("Failed to set stream selection, hr %#lx\n", hr);
}
IWMReaderAdvanced_Release(reader_advanced);
return IWMReader_Start(filter->reader, 0, 0, 1, NULL);
}