Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 3 ++ dlls/winegstreamer/quartz_parser.c | 2 +- dlls/winegstreamer/wm_reader.c | 47 ++++++++++++++++++++++++++++++ dlls/winegstreamer/wm_syncreader.c | 10 ++++--- dlls/wmvcore/tests/wmvcore.c | 9 +----- 5 files changed, 58 insertions(+), 13 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 9219a86c094..278fc132ccf 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -102,6 +102,7 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; HRESULT wave_parser_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN;
bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format); +bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format);
BOOL init_gstreamer(void) DECLSPEC_HIDDEN;
@@ -160,5 +161,7 @@ HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps **props); void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops); HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream); +HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, + IWMOutputMediaProps *props);
#endif /* __GST_PRIVATE_INCLUDED__ */ diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c index 0862a75b7ef..4e7e22a64ea 100644 --- a/dlls/winegstreamer/quartz_parser.c +++ b/dlls/winegstreamer/quartz_parser.c @@ -540,7 +540,7 @@ static bool amt_to_wg_format_video(const AM_MEDIA_TYPE *mt, struct wg_format *fo return false; }
-static bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) +bool amt_to_wg_format(const AM_MEDIA_TYPE *mt, struct wg_format *format) { memset(format, 0, sizeof(*format));
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 79a89c9a332..21e08b5834f 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -140,6 +140,14 @@ static const struct IWMOutputMediaPropsVtbl output_props_vtbl = output_props_GetConnectionName, };
+static struct output_props *unsafe_impl_from_IWMOutputMediaProps(IWMOutputMediaProps *iface) +{ + if (!iface) + return NULL; + assert(iface->lpVtbl == &output_props_vtbl); + return impl_from_IWMOutputMediaProps(iface); +} + static IWMOutputMediaProps *output_props_create(const struct wg_format *format) { struct output_props *object; @@ -1382,6 +1390,45 @@ HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output, return *props ? S_OK : E_OUTOFMEMORY; }
+HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, + IWMOutputMediaProps *props_iface) +{ + struct output_props *props = unsafe_impl_from_IWMOutputMediaProps(props_iface); + struct wg_format format, pref_format; + struct wm_stream *stream; + + strmbase_dump_media_type(&props->mt); + + if (!amt_to_wg_format(&props->mt, &format)) + { + ERR("Failed to convert media type to winegstreamer format.\n"); + return E_FAIL; + } + + EnterCriticalSection(&reader->cs); + + if (!(stream = get_stream_by_output_number(reader, output))) + { + LeaveCriticalSection(&reader->cs); + return E_INVALIDARG; + } + + wg_parser_stream_get_preferred_format(stream->wg_stream, &pref_format); + if (pref_format.major_type != format.major_type) + { + /* R.U.S.E sets the type of the wrong stream, apparently by accident. */ + LeaveCriticalSection(&reader->cs); + WARN("Major types don't match; returning NS_E_INCOMPATIBLE_FORMAT.\n"); + return NS_E_INCOMPATIBLE_FORMAT; + } + + stream->format = format; + wg_parser_stream_enable(stream->wg_stream, &format); + + LeaveCriticalSection(&reader->cs); + return S_OK; +} + void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops) { reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl; diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c index 54c53dee3bd..f9728211661 100644 --- a/dlls/winegstreamer/wm_syncreader.c +++ b/dlls/winegstreamer/wm_syncreader.c @@ -186,11 +186,13 @@ static HRESULT WINAPI WMSyncReader_OpenStream(IWMSyncReader2 *iface, IStream *st return wm_reader_open_stream(&reader->reader, stream); }
-static HRESULT WINAPI WMSyncReader_SetOutputProps(IWMSyncReader2 *iface, DWORD output_num, IWMOutputMediaProps *output) +static HRESULT WINAPI WMSyncReader_SetOutputProps(IWMSyncReader2 *iface, DWORD output, IWMOutputMediaProps *props) { - struct sync_reader *This = impl_from_IWMSyncReader2(iface); - FIXME("(%p)->(%u %p): stub!\n", This, output_num, output); - return E_NOTIMPL; + struct sync_reader *reader = impl_from_IWMSyncReader2(iface); + + TRACE("reader %p, output %u, props %p.\n", reader, output, props); + + return wm_reader_set_output_props(&reader->reader, output, props); }
static HRESULT WINAPI WMSyncReader_SetOutputSetting(IWMSyncReader2 *iface, DWORD output_num, const WCHAR *name, diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index ebfdfdf0107..e07e6241a4c 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -789,14 +789,7 @@ static void test_sync_reader_types(void) check_video_type(mt);
hr = IWMSyncReader_SetOutputProps(reader, output_number, output_props); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - if (hr != S_OK) - { - ref = IWMOutputMediaProps_Release(output_props); - ok(!ref, "Got outstanding refcount %d.\n", ref); - winetest_pop_context(); - continue; - } + ok(hr == S_OK, "Got hr %#x.\n", hr); hr = IWMSyncReader_SetOutputProps(reader, 1 - output_number, output_props); if (!i) todo_wine ok(hr == ASF_E_BADMEDIATYPE, "Got hr %#x.\n", hr);
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 5 + dlls/winegstreamer/wm_reader.c | 192 +++++++++++++++++++++++++++++ dlls/winegstreamer/wm_syncreader.c | 41 +++++- dlls/wmvcore/tests/wmvcore.c | 12 +- include/wmsdkidl.idl | 7 ++ 5 files changed, 245 insertions(+), 12 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index 278fc132ccf..a9c361366b3 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -121,6 +121,7 @@ struct wm_stream struct wm_reader *reader; struct wg_parser_stream *wg_stream; WORD index; + bool eos; struct wg_format format; };
@@ -159,6 +160,10 @@ HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output, HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output, DWORD *count); HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps **props); +struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, + WORD stream_number); +HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, + INSSBuffer **sample, QWORD *pts, QWORD *duration, DWORD *flags); void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops); HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream); HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 21e08b5834f..71adfac5a42 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -167,6 +167,101 @@ static IWMOutputMediaProps *output_props_create(const struct wg_format *format) return &object->IWMOutputMediaProps_iface; }
+struct buffer +{ + INSSBuffer INSSBuffer_iface; + LONG refcount; +}; + +static struct buffer *impl_from_INSSBuffer(INSSBuffer *iface) +{ + return CONTAINING_RECORD(iface, struct buffer, INSSBuffer_iface); +} + +static HRESULT WINAPI buffer_QueryInterface(INSSBuffer *iface, REFIID iid, void **out) +{ + struct buffer *buffer = impl_from_INSSBuffer(iface); + + TRACE("buffer %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_INSSBuffer)) + *out = &buffer->INSSBuffer_iface; + else + { + *out = NULL; + WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI buffer_AddRef(INSSBuffer *iface) +{ + struct buffer *buffer = impl_from_INSSBuffer(iface); + ULONG refcount = InterlockedIncrement(&buffer->refcount); + + TRACE("%p increasing refcount to %u.\n", buffer, refcount); + + return refcount; +} + +static ULONG WINAPI buffer_Release(INSSBuffer *iface) +{ + struct buffer *buffer = impl_from_INSSBuffer(iface); + ULONG refcount = InterlockedDecrement(&buffer->refcount); + + TRACE("%p decreasing refcount to %u.\n", buffer, refcount); + + if (!refcount) + free(buffer); + + return refcount; +} + +static HRESULT WINAPI buffer_GetLength(INSSBuffer *iface, DWORD *size) +{ + FIXME("iface %p, size %p, stub!\n", iface, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI buffer_SetLength(INSSBuffer *iface, DWORD size) +{ + FIXME("iface %p, size %u, stub!\n", iface, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI buffer_GetMaxLength(INSSBuffer *iface, DWORD *size) +{ + FIXME("iface %p, size %p, stub!\n", iface, size); + return E_NOTIMPL; +} + +static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data) +{ + FIXME("iface %p, data %p, stub!\n", iface, data); + return E_NOTIMPL; +} + +static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size) +{ + FIXME("iface %p, data %p, size %p, stub!\n", iface, data, size); + return E_NOTIMPL; +} + +static const INSSBufferVtbl buffer_vtbl = +{ + buffer_QueryInterface, + buffer_AddRef, + buffer_Release, + buffer_GetLength, + buffer_SetLength, + buffer_GetMaxLength, + buffer_GetBuffer, + buffer_GetBufferAndLength, +}; + struct stream_config { IWMStreamConfig IWMStreamConfig_iface; @@ -1231,8 +1326,15 @@ HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream) if (stream->format.u.video.format == WG_VIDEO_FORMAT_I420) stream->format.u.video.format = WG_VIDEO_FORMAT_YV12; } + wg_parser_stream_enable(stream->wg_stream, &stream->format); }
+ wg_parser_end_flush(reader->wg_parser); + /* We probably discarded events because streams weren't enabled yet. + * Now that they're all enabled seek back to the start again. */ + wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, 0, 0, + AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); + LeaveCriticalSection(&reader->cs); return S_OK;
@@ -1281,6 +1383,14 @@ HRESULT wm_reader_close(struct wm_reader *reader) return S_OK; }
+struct wm_stream *wm_reader_get_stream_by_stream_number(struct wm_reader *reader, WORD stream_number) +{ + if (stream_number && stream_number <= reader->stream_count) + return &reader->streams[stream_number - 1]; + WARN("Invalid stream number %u.\n", stream_number); + return NULL; +} + HRESULT wm_reader_get_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps **props) { struct wm_stream *stream; @@ -1429,6 +1539,88 @@ HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, return S_OK; }
+static const char *get_major_type_string(enum wg_major_type type) +{ + switch (type) + { + case WG_MAJOR_TYPE_AUDIO: + return "audio"; + case WG_MAJOR_TYPE_VIDEO: + return "video"; + case WG_MAJOR_TYPE_UNKNOWN: + return "unknown"; + } + assert(0); + return NULL; +} + +HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, + INSSBuffer **ret_sample, QWORD *pts, QWORD *duration, DWORD *flags) +{ + struct wg_parser_stream *wg_stream = stream->wg_stream; + struct wg_parser_event event; + struct buffer *object; + + if (stream->eos) + return NS_E_NO_MORE_SAMPLES; + + for (;;) + { + if (!wg_parser_stream_get_event(wg_stream, &event)) + { + FIXME("Stream is flushing.\n"); + return E_NOTIMPL; + } + + TRACE("Got event of type %#x for %s stream %p.\n", event.type, + get_major_type_string(stream->format.major_type), stream); + + switch (event.type) + { + case WG_PARSER_EVENT_BUFFER: + /* FIXME: Should these be pooled? */ + if (!(object = calloc(1, sizeof(*object)))) + { + wg_parser_stream_release_buffer(wg_stream); + return E_OUTOFMEMORY; + } + + object->INSSBuffer_iface.lpVtbl = &buffer_vtbl; + object->refcount = 1; + + wg_parser_stream_release_buffer(wg_stream); + + if (!event.u.buffer.has_pts) + FIXME("Missing PTS.\n"); + if (!event.u.buffer.has_duration) + FIXME("Missing duration.\n"); + + *pts = event.u.buffer.pts; + *duration = event.u.buffer.duration; + *flags = 0; + if (event.u.buffer.discontinuity) + *flags |= WM_SF_DISCONTINUITY; + if (!event.u.buffer.delta) + *flags |= WM_SF_CLEANPOINT; + + TRACE("Created buffer %p.\n", object); + *ret_sample = &object->INSSBuffer_iface; + return S_OK; + + case WG_PARSER_EVENT_EOS: + stream->eos = true; + TRACE("End of stream.\n"); + return NS_E_NO_MORE_SAMPLES; + + case WG_PARSER_EVENT_SEGMENT: + break; + + case WG_PARSER_EVENT_NONE: + assert(0); + } + } +} + void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops) { reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl; diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c index f9728211661..a2cc747e9bf 100644 --- a/dlls/winegstreamer/wm_syncreader.c +++ b/dlls/winegstreamer/wm_syncreader.c @@ -76,13 +76,42 @@ static HRESULT WINAPI WMSyncReader_GetMaxStreamSampleSize(IWMSyncReader2 *iface, return E_NOTIMPL; }
-static HRESULT WINAPI WMSyncReader_GetNextSample(IWMSyncReader2 *iface, WORD stream, INSSBuffer **sample, - QWORD *sample_time, QWORD *sample_duration, DWORD *flags, DWORD *output_num, WORD *stream_num) +static HRESULT WINAPI WMSyncReader_GetNextSample(IWMSyncReader2 *iface, + WORD stream_number, INSSBuffer **sample, QWORD *pts, QWORD *duration, + DWORD *flags, DWORD *output_number, WORD *ret_stream_number) { - struct sync_reader *This = impl_from_IWMSyncReader2(iface); - FIXME("(%p)->(%d %p %p %p %p %p %p): stub!\n", This, stream, sample, sample_time, - sample_duration, flags, output_num, stream_num); - return E_NOTIMPL; + struct sync_reader *reader = impl_from_IWMSyncReader2(iface); + struct wm_stream *stream; + HRESULT hr; + + TRACE("reader %p, stream_number %u, sample %p, pts %p, duration %p," + " flags %p, output_number %p, ret_stream_number %p.\n", + reader, stream_number, sample, pts, duration, flags, output_number, ret_stream_number); + + EnterCriticalSection(&reader->reader.cs); + + if (!stream_number) + { + FIXME("Reading from all streams is not implemented yet.\n"); + hr = E_NOTIMPL; + } + else + { + if (!(stream = wm_reader_get_stream_by_stream_number(&reader->reader, stream_number))) + { + LeaveCriticalSection(&reader->reader.cs); + return E_INVALIDARG; + } + + hr = wm_reader_get_stream_sample(stream, sample, pts, duration, flags); + if (hr == S_OK && output_number) + *output_number = stream->index; + if (ret_stream_number) + *ret_stream_number = stream->index + 1; + } + + LeaveCriticalSection(&reader->reader.cs); + return hr; }
static HRESULT WINAPI WMSyncReader_GetOutputCount(IWMSyncReader2 *iface, DWORD *count) diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index e07e6241a4c..dabeb054530 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -500,7 +500,7 @@ static void test_sync_reader_streaming(void) hr = IWMSyncReader_GetNextSample(reader, stream_numbers[j], &sample, &pts, &duration, &flags, &output_number, &stream_number); if (first) - todo_wine ok(hr == S_OK, "Expected at least one valid sample; got hr %#x.\n", hr); + ok(hr == S_OK, "Expected at least one valid sample; got hr %#x.\n", hr); else if (eos[j]) ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); else @@ -527,7 +527,7 @@ static void test_sync_reader_streaming(void) eos[j] = true; }
- todo_wine ok(stream_number == stream_numbers[j], "Expected stream number %u, got %u.\n", + ok(stream_number == stream_numbers[j], "Expected stream number %u, got %u.\n", stream_numbers[j], stream_number); } first = false; @@ -535,11 +535,11 @@ static void test_sync_reader_streaming(void)
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample, &pts, &duration, &flags, NULL, NULL); - todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[1], &sample, &pts, &duration, &flags, NULL, NULL); - todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
hr = IWMSyncReader_SetRange(reader, 0, 0); todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); @@ -593,11 +593,11 @@ static void test_sync_reader_streaming(void)
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample, &pts, &duration, &flags, NULL, NULL); - todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[1], &sample, &pts, &duration, &flags, NULL, NULL); - todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
hr = IWMSyncReader_Close(reader); ok(hr == S_OK, "Got hr %#x.\n", hr); diff --git a/include/wmsdkidl.idl b/include/wmsdkidl.idl index f276d642a03..55142f47e93 100644 --- a/include/wmsdkidl.idl +++ b/include/wmsdkidl.idl @@ -81,6 +81,13 @@ typedef struct _WMReaderClientInfo WCHAR *wszPlayerUserAgent; } WM_READER_CLIENTINFO;
+enum +{ + WM_SF_CLEANPOINT = 0x1, + WM_SF_DISCONTINUITY = 0x2, + WM_SF_DATALOSS = 0x4, +}; + typedef enum WMT_ATTR_DATATYPE { WMT_TYPE_DWORD = 0,
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/wm_reader.c | 22 +++++++++++++++++++--- dlls/wmvcore/tests/wmvcore.c | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 71adfac5a42..e708ed4bfa6 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -171,6 +171,9 @@ struct buffer { INSSBuffer INSSBuffer_iface; LONG refcount; + + DWORD size; + BYTE data[1]; };
static struct buffer *impl_from_INSSBuffer(INSSBuffer *iface) @@ -246,8 +249,13 @@ static HRESULT WINAPI buffer_GetBuffer(INSSBuffer *iface, BYTE **data)
static HRESULT WINAPI buffer_GetBufferAndLength(INSSBuffer *iface, BYTE **data, DWORD *size) { - FIXME("iface %p, data %p, size %p, stub!\n", iface, data, size); - return E_NOTIMPL; + struct buffer *buffer = impl_from_INSSBuffer(iface); + + TRACE("buffer %p, data %p, size %p.\n", buffer, data, size); + + *size = buffer->size; + *data = buffer->data; + return S_OK; }
static const INSSBufferVtbl buffer_vtbl = @@ -1579,7 +1587,7 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, { case WG_PARSER_EVENT_BUFFER: /* FIXME: Should these be pooled? */ - if (!(object = calloc(1, sizeof(*object)))) + if (!(object = calloc(1, offsetof(struct buffer, data[event.u.buffer.size])))) { wg_parser_stream_release_buffer(wg_stream); return E_OUTOFMEMORY; @@ -1587,6 +1595,14 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream,
object->INSSBuffer_iface.lpVtbl = &buffer_vtbl; object->refcount = 1; + object->size = event.u.buffer.size; + + if (!wg_parser_stream_copy_buffer(wg_stream, object->data, 0, object->size)) + { + /* The GStreamer pin has been flushed. */ + free(object); + break; + }
wg_parser_stream_release_buffer(wg_stream);
diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index dabeb054530..419dea2f68d 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -509,7 +509,7 @@ static void test_sync_reader_streaming(void) if (hr == S_OK) { hr = INSSBuffer_GetBufferAndLength(sample, &data, &size); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr); ref = INSSBuffer_Release(sample); ok(!ref, "Got outstanding refcount %d.\n", ref);
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=101063
Your paranoid android.
=== debiant2 (32 bit Chinese:China report) ===
wmvcore: wmvcore.c:792: Test failed: Stream 0: Format 0: Got hr 0xc00d0041. wmvcore.c:809: Test failed: Stream 0: Format 0: Media types didn't match.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/wm_syncreader.c | 29 +++++++++++++++++++++++++++-- dlls/wmvcore/tests/wmvcore.c | 6 +++--- 2 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c index a2cc747e9bf..063be2a94ab 100644 --- a/dlls/winegstreamer/wm_syncreader.c +++ b/dlls/winegstreamer/wm_syncreader.c @@ -25,6 +25,8 @@ struct sync_reader struct wm_reader reader;
IWMSyncReader2 IWMSyncReader2_iface; + + WORD last_read_stream; };
static struct sync_reader *impl_from_IWMSyncReader2(IWMSyncReader2 *iface) @@ -83,6 +85,7 @@ static HRESULT WINAPI WMSyncReader_GetNextSample(IWMSyncReader2 *iface, struct sync_reader *reader = impl_from_IWMSyncReader2(iface); struct wm_stream *stream; HRESULT hr; + WORD i;
TRACE("reader %p, stream_number %u, sample %p, pts %p, duration %p," " flags %p, output_number %p, ret_stream_number %p.\n", @@ -92,8 +95,30 @@ static HRESULT WINAPI WMSyncReader_GetNextSample(IWMSyncReader2 *iface,
if (!stream_number) { - FIXME("Reading from all streams is not implemented yet.\n"); - hr = E_NOTIMPL; + if (!output_number && !ret_stream_number) + { + LeaveCriticalSection(&reader->reader.cs); + return E_INVALIDARG; + } + + for (i = 0; i < reader->reader.stream_count; ++i) + { + WORD index = (i + reader->last_read_stream + 1) % reader->reader.stream_count; + + hr = wm_reader_get_stream_sample(&reader->reader.streams[index], sample, pts, duration, flags); + if (hr == S_OK) + { + if (output_number) + *output_number = index; + if (ret_stream_number) + *ret_stream_number = index + 1; + } + if (hr != NS_E_NO_MORE_SAMPLES) + { + reader->last_read_stream = index; + break; + } + } } else { diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 419dea2f68d..48d585e73c0 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -550,7 +550,7 @@ static void test_sync_reader_streaming(void) INSSBuffer_Release(sample);
hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, NULL, NULL); - todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr); + ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, &output_number, NULL); todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); @@ -567,7 +567,7 @@ static void test_sync_reader_streaming(void) stream_number = pts = duration = flags = output_number = 0xdeadbeef; hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, &output_number, &stream_number); - todo_wine ok(hr == S_OK || hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + ok(hr == S_OK || hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
if (hr == S_OK) { @@ -589,7 +589,7 @@ static void test_sync_reader_streaming(void)
hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, NULL, &stream_number); - todo_wine ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr); + ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample, &pts, &duration, &flags, NULL, NULL);
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/wm_reader.c | 15 +++++++++++++++ dlls/winegstreamer/wm_syncreader.c | 9 ++++++--- dlls/wmvcore/tests/wmvcore.c | 17 +++++++---------- 4 files changed, 29 insertions(+), 13 deletions(-)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index a9c361366b3..d330716b8f9 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -166,6 +166,7 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, INSSBuffer **sample, QWORD *pts, QWORD *duration, DWORD *flags); void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops); HRESULT wm_reader_open_stream(struct wm_reader *reader, IStream *stream); +void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration); HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, IWMOutputMediaProps *props);
diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index e708ed4bfa6..24fd11f652d 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1637,6 +1637,21 @@ HRESULT wm_reader_get_stream_sample(struct wm_stream *stream, } }
+void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration) +{ + WORD i; + + EnterCriticalSection(&reader->cs); + + wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, start, start + duration, + AM_SEEKING_AbsolutePositioning, duration ? AM_SEEKING_AbsolutePositioning : AM_SEEKING_NoPositioning); + + for (i = 0; i < reader->stream_count; ++i) + reader->streams[i].eos = false; + + LeaveCriticalSection(&reader->cs); +} + void wm_reader_init(struct wm_reader *reader, const struct wm_reader_ops *ops) { reader->IWMHeaderInfo3_iface.lpVtbl = &header_info_vtbl; diff --git a/dlls/winegstreamer/wm_syncreader.c b/dlls/winegstreamer/wm_syncreader.c index 063be2a94ab..1f5827cf244 100644 --- a/dlls/winegstreamer/wm_syncreader.c +++ b/dlls/winegstreamer/wm_syncreader.c @@ -259,9 +259,12 @@ static HRESULT WINAPI WMSyncReader_SetOutputSetting(IWMSyncReader2 *iface, DWORD
static HRESULT WINAPI WMSyncReader_SetRange(IWMSyncReader2 *iface, QWORD start, LONGLONG duration) { - struct sync_reader *This = impl_from_IWMSyncReader2(iface); - FIXME("(%p)->(%s %s): stub!\n", This, wine_dbgstr_longlong(start), wine_dbgstr_longlong(duration)); - return E_NOTIMPL; + struct sync_reader *reader = impl_from_IWMSyncReader2(iface); + + TRACE("reader %p, start %I64u, duration %I64d.\n", reader, start, duration); + + wm_reader_seek(&reader->reader, start, duration); + return S_OK; }
static HRESULT WINAPI WMSyncReader_SetRangeByFrame(IWMSyncReader2 *iface, WORD stream_num, QWORD frame_num, diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c index 48d585e73c0..6e196234208 100644 --- a/dlls/wmvcore/tests/wmvcore.c +++ b/dlls/wmvcore/tests/wmvcore.c @@ -542,25 +542,22 @@ static void test_sync_reader_streaming(void) ok(hr == NS_E_NO_MORE_SAMPLES, "Got hr %#x.\n", hr);
hr = IWMSyncReader_SetRange(reader, 0, 0); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); + ok(hr == S_OK, "Got hr %#x.\n", hr);
hr = IWMSyncReader_GetNextSample(reader, stream_numbers[0], &sample, &pts, &duration, &flags, NULL, NULL); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - if (hr == S_OK) - INSSBuffer_Release(sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + INSSBuffer_Release(sample);
hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, NULL, NULL); ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, &output_number, NULL); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - if (hr == S_OK) - INSSBuffer_Release(sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + INSSBuffer_Release(sample);
hr = IWMSyncReader_GetNextSample(reader, 0, &sample, &pts, &duration, &flags, NULL, &stream_number); - todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr); - if (hr == S_OK) - INSSBuffer_Release(sample); + ok(hr == S_OK, "Got hr %#x.\n", hr); + INSSBuffer_Release(sample);
for (;;) {
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/winegstreamer/gst_private.h | 2 ++ dlls/winegstreamer/wm_reader.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+)
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index d330716b8f9..109ce6ab28f 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -136,6 +136,8 @@ struct wm_reader LONG refcount; CRITICAL_SECTION cs;
+ QWORD start_time; + IStream *source_stream; HANDLE read_thread; bool read_thread_shutdown; diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c index 24fd11f652d..82f74318062 100644 --- a/dlls/winegstreamer/wm_reader.c +++ b/dlls/winegstreamer/wm_reader.c @@ -1543,6 +1543,22 @@ HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, stream->format = format; wg_parser_stream_enable(stream->wg_stream, &format);
+ /* Re-decode any buffers that might have been generated with the old format. + * + * FIXME: Seeking in-place will cause some buffers to be dropped. + * Unfortunately, we can't really store the last received PTS and seek there + * either: since seeks are inexact and we aren't guaranteed to receive + * samples in order, some buffers might be duplicated or dropped anyway. + * In order to really seamlessly allow for format changes, we need + * cooperation from each individual GStreamer stream, to be able to tell + * upstream exactly which buffers they need resent... + * + * In all likelihood this function is being called not mid-stream but rather + * while setting the stream up, before consuming any events. Accordingly + * let's just seek back to the beginning. */ + wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, reader->start_time, 0, + AM_SEEKING_AbsolutePositioning, AM_SEEKING_NoPositioning); + LeaveCriticalSection(&reader->cs); return S_OK; } @@ -1643,6 +1659,8 @@ void wm_reader_seek(struct wm_reader *reader, QWORD start, LONGLONG duration)
EnterCriticalSection(&reader->cs);
+ reader->start_time = start; + wg_parser_stream_seek(reader->streams[0].wg_stream, 1.0, start, start + duration, AM_SEEKING_AbsolutePositioning, duration ? AM_SEEKING_AbsolutePositioning : AM_SEEKING_NoPositioning);