From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/tests/mfplat.c | 10 ++++++++++ dlls/mfreadwrite/writer.c | 13 +++++++++++++ 2 files changed, 23 insertions(+)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 95f615767d5..14e92cceab2 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1299,8 +1299,18 @@ static void test_sink_writer(void) hr = MFCreateSinkWriterFromURL(NULL, NULL, NULL, NULL); ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+ writer = (void *)0xdeadbeef; hr = MFCreateSinkWriterFromURL(NULL, NULL, NULL, &writer); ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(!writer, "Unexpected pointer %p.\n", writer); + + hr = MFCreateSinkWriterFromMediaSink(NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + writer = (void *)0xdeadbeef; + hr = MFCreateSinkWriterFromMediaSink(NULL, NULL, &writer); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(!writer, "Unexpected pointer %p.\n", writer); }
START_TEST(mfplat) diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index f4bd08b8cda..9e92e6f8f9e 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -186,6 +186,11 @@ HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attribut struct sink_writer *object; HRESULT hr;
+ *out = NULL; + + if (!sink) + return E_INVALIDARG; + object = malloc(sizeof(*object)); if (!object) return E_OUTOFMEMORY; @@ -205,6 +210,9 @@ HRESULT WINAPI MFCreateSinkWriterFromMediaSink(IMFMediaSink *sink, IMFAttributes { TRACE("%p, %p, %p.\n", sink, attributes, writer);
+ if (!writer) + return E_INVALIDARG; + return create_sink_writer_from_sink(sink, attributes, &IID_IMFSinkWriter, (void **)writer); }
@@ -289,6 +297,8 @@ HRESULT create_sink_writer_from_url(const WCHAR *url, IMFByteStream *bytestream, CLSID clsid; HRESULT hr;
+ *out = NULL; + if (!url && !bytestream) return E_INVALIDARG;
@@ -332,5 +342,8 @@ HRESULT WINAPI MFCreateSinkWriterFromURL(const WCHAR *url, IMFByteStream *bytest { TRACE("%s, %p, %p, %p.\n", debugstr_w(url), bytestream, attributes, writer);
+ if (!writer) + return E_INVALIDARG; + return create_sink_writer_from_url(url, bytestream, attributes, &IID_IMFSinkWriter, (void **)writer); }
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/mf_private.h | 29 +++++++++ dlls/mfreadwrite/reader.c | 1 - dlls/mfreadwrite/writer.c | 119 ++++++++++++++++++++++++++++++++-- 3 files changed, 143 insertions(+), 6 deletions(-)
diff --git a/dlls/mfreadwrite/mf_private.h b/dlls/mfreadwrite/mf_private.h index 7d8172a383a..e2372e7e856 100644 --- a/dlls/mfreadwrite/mf_private.h +++ b/dlls/mfreadwrite/mf_private.h @@ -16,7 +16,36 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include "mferror.h" + extern HRESULT create_sink_writer_from_url(const WCHAR *url, IMFByteStream *stream, IMFAttributes *attributes, REFIID riid, void **out) DECLSPEC_HIDDEN; extern HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attributes, REFIID riid, void **out) DECLSPEC_HIDDEN; + +static inline BOOL mf_array_reserve(void **elements, size_t *capacity, size_t count, size_t size) +{ + size_t new_capacity, max_capacity; + void *new_elements; + + if (count <= *capacity) + return TRUE; + + max_capacity = ~(SIZE_T)0 / size; + if (count > max_capacity) + return FALSE; + + new_capacity = max(4, *capacity); + while (new_capacity < count && new_capacity <= max_capacity / 2) + new_capacity *= 2; + if (new_capacity < count) + new_capacity = max_capacity; + + if (!(new_elements = realloc(*elements, new_capacity * size))) + return FALSE; + + *elements = new_elements; + *capacity = new_capacity; + + return TRUE; +} diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index aac59deba76..f29d48b6a9e 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -30,7 +30,6 @@ #undef INITGUID #include <guiddef.h> #include "mfapi.h" -#include "mferror.h" #include "mfidl.h" #include "mfreadwrite.h" #include "d3d9.h" diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 9e92e6f8f9e..c393d4d6e38 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -30,10 +30,33 @@
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
+enum writer_state +{ + SINK_WRITER_STATE_INITIAL = 0, +}; + +struct stream +{ + IMFStreamSink *stream_sink; +}; + struct sink_writer { IMFSinkWriter IMFSinkWriter_iface; LONG refcount; + + struct + { + struct stream *items; + size_t count; + size_t capacity; + DWORD next_id; + } streams; + + IMFMediaSink *sink; + enum writer_state state; + + CRITICAL_SECTION cs; };
static struct sink_writer *impl_from_IMFSinkWriter(IMFSinkWriter *iface) @@ -72,22 +95,80 @@ static ULONG WINAPI sink_writer_Release(IMFSinkWriter *iface) { struct sink_writer *writer = impl_from_IMFSinkWriter(iface); ULONG refcount = InterlockedDecrement(&writer->refcount); + unsigned int i;
TRACE("%p, %lu.\n", iface, refcount);
if (!refcount) { + if (writer->sink) + IMFMediaSink_Release(writer->sink); + for (i = 0; i < writer->streams.count; ++i) + { + struct stream *stream = &writer->streams.items[i]; + + if (stream->stream_sink) + IMFStreamSink_Release(stream->stream_sink); + } + DeleteCriticalSection(&writer->cs); free(writer); }
return refcount; }
-static HRESULT WINAPI sink_writer_AddStream(IMFSinkWriter *iface, IMFMediaType *type, DWORD *index) +static HRESULT sink_writer_add_stream(struct sink_writer *writer, IMFStreamSink *stream_sink, DWORD *index) { - FIXME("%p, %p, %p.\n", iface, type, index); + DWORD id = 0; + HRESULT hr;
- return E_NOTIMPL; + if (!mf_array_reserve((void **)&writer->streams.items, &writer->streams.capacity, writer->streams.count + 1, + sizeof(*writer->streams.items))) + { + return E_OUTOFMEMORY; + } + + if (FAILED(hr = IMFStreamSink_GetIdentifier(stream_sink, &id))) return hr; + + *index = writer->streams.count++; + + writer->streams.items[*index].stream_sink = stream_sink; + IMFStreamSink_AddRef(stream_sink); + writer->streams.next_id = max(writer->streams.next_id, id); + + return hr; +} + +static HRESULT WINAPI sink_writer_AddStream(IMFSinkWriter *iface, IMFMediaType *media_type, DWORD *index) +{ + struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + HRESULT hr = MF_E_INVALIDREQUEST; + IMFStreamSink *stream_sink; + DWORD id; + + TRACE("%p, %p, %p.\n", iface, media_type, index); + + if (!media_type) + return E_INVALIDARG; + + if (!index) + return E_POINTER; + + EnterCriticalSection(&writer->cs); + + if (writer->state == SINK_WRITER_STATE_INITIAL) + { + id = writer->streams.next_id + 1; + if (SUCCEEDED(hr = IMFMediaSink_AddStreamSink(writer->sink, id, media_type, &stream_sink))) + { + if (FAILED(hr = sink_writer_add_stream(writer, stream_sink, index))) + IMFMediaSink_RemoveStreamSink(writer->sink, id); + } + } + + LeaveCriticalSection(&writer->cs); + + return hr; }
static HRESULT WINAPI sink_writer_SetInputMediaType(IMFSinkWriter *iface, DWORD index, IMFMediaType *type, @@ -180,6 +261,26 @@ static const IMFSinkWriterVtbl sink_writer_vtbl = sink_writer_GetStatistics, };
+static HRESULT sink_writer_initialize_existing_streams(struct sink_writer *writer, IMFMediaSink *sink) +{ + IMFStreamSink *stream_sink; + DWORD count = 0, i, index; + HRESULT hr; + + if (FAILED(hr = IMFMediaSink_GetStreamSinkCount(sink, &count))) return hr; + if (!count) return S_OK; + + for (i = 0; i < count; ++i) + { + if (FAILED(hr = IMFMediaSink_GetStreamSinkByIndex(sink, i, &stream_sink))) break; + hr = sink_writer_add_stream(writer, stream_sink, &index); + IMFStreamSink_Release(stream_sink); + if (FAILED(hr)) break; + } + + return hr; +} + HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attributes, REFIID riid, void **out) { @@ -191,12 +292,20 @@ HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attribut if (!sink) return E_INVALIDARG;
- object = malloc(sizeof(*object)); - if (!object) + if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
object->IMFSinkWriter_iface.lpVtbl = &sink_writer_vtbl; object->refcount = 1; + object->sink = sink; + IMFMediaSink_AddRef(sink); + InitializeCriticalSection(&object->cs); + + if (FAILED(hr = sink_writer_initialize_existing_streams(object, sink))) + { + IMFSinkWriter_Release(&object->IMFSinkWriter_iface); + return hr; + }
hr = IMFSinkWriter_QueryInterface(&object->IMFSinkWriter_iface, riid, out); IMFSinkWriter_Release(&object->IMFSinkWriter_iface);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/Makefile.in | 1 + dlls/mfreadwrite/writer.c | 132 ++++++++++++++++++++++++++++++++++- 2 files changed, 131 insertions(+), 2 deletions(-)
diff --git a/dlls/mfreadwrite/Makefile.in b/dlls/mfreadwrite/Makefile.in index 552ba6d2638..35e3ff75398 100644 --- a/dlls/mfreadwrite/Makefile.in +++ b/dlls/mfreadwrite/Makefile.in @@ -1,6 +1,7 @@ MODULE = mfreadwrite.dll IMPORTLIB = mfreadwrite IMPORTS = mfuuid uuid mfplat ole32 kernelbase +DELAYIMPORTS = mf
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index c393d4d6e38..a61fa998f9e 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -33,6 +33,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat); enum writer_state { SINK_WRITER_STATE_INITIAL = 0, + SINK_WRITER_STATE_WRITING, };
struct stream @@ -43,6 +44,7 @@ struct stream struct sink_writer { IMFSinkWriter IMFSinkWriter_iface; + IMFAsyncCallback events_callback; LONG refcount;
struct @@ -53,6 +55,7 @@ struct sink_writer DWORD next_id; } streams;
+ IMFPresentationClock *clock; IMFMediaSink *sink; enum writer_state state;
@@ -64,6 +67,11 @@ static struct sink_writer *impl_from_IMFSinkWriter(IMFSinkWriter *iface) return CONTAINING_RECORD(iface, struct sink_writer, IMFSinkWriter_iface); }
+static struct sink_writer *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct sink_writer, events_callback); +} + static HRESULT WINAPI sink_writer_QueryInterface(IMFSinkWriter *iface, REFIID riid, void **out) { TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); @@ -101,6 +109,8 @@ static ULONG WINAPI sink_writer_Release(IMFSinkWriter *iface)
if (!refcount) { + if (writer->clock) + IMFPresentationClock_Release(writer->clock); if (writer->sink) IMFMediaSink_Release(writer->sink); for (i = 0; i < writer->streams.count; ++i) @@ -179,11 +189,60 @@ static HRESULT WINAPI sink_writer_SetInputMediaType(IMFSinkWriter *iface, DWORD return E_NOTIMPL; }
+static HRESULT sink_writer_set_presentation_clock(struct sink_writer *writer) +{ + IMFPresentationTimeSource *time_source = NULL; + HRESULT hr; + + if (FAILED(hr = MFCreatePresentationClock(&writer->clock))) return hr; + + if (FAILED(IMFMediaSink_QueryInterface(writer->sink, &IID_IMFPresentationTimeSource, (void **)&time_source))) + hr = MFCreateSystemTimeSource(&time_source); + + if (SUCCEEDED(hr = IMFPresentationClock_SetTimeSource(writer->clock, time_source))) + hr = IMFMediaSink_SetPresentationClock(writer->sink, writer->clock); + + if (time_source) + IMFPresentationTimeSource_Release(time_source); + + return hr; +} + static HRESULT WINAPI sink_writer_BeginWriting(IMFSinkWriter *iface) { - FIXME("%p.\n", iface); + struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + HRESULT hr = S_OK; + unsigned int i;
- return E_NOTIMPL; + TRACE("%p.\n", iface); + + EnterCriticalSection(&writer->cs); + + if (!writer->streams.count) + hr = MF_E_INVALIDREQUEST; + else if (writer->state != SINK_WRITER_STATE_INITIAL) + hr = MF_E_INVALIDREQUEST; + else if (SUCCEEDED(hr = sink_writer_set_presentation_clock(writer))) + { + for (i = 0; i < writer->streams.count; ++i) + { + struct stream *stream = &writer->streams.items[i]; + + if (FAILED(hr = IMFStreamSink_BeginGetEvent(stream->stream_sink, &writer->events_callback, + (IUnknown *)stream->stream_sink))) + { + WARN("Failed to subscribe to events for steam %u, hr %#lx.\n", i, hr); + } + + /* FIXME: notify the encoder */ + } + + writer->state = SINK_WRITER_STATE_WRITING; + } + + LeaveCriticalSection(&writer->cs); + + return hr; }
static HRESULT WINAPI sink_writer_WriteSample(IMFSinkWriter *iface, DWORD index, IMFSample *sample) @@ -261,6 +320,74 @@ static const IMFSinkWriterVtbl sink_writer_vtbl = sink_writer_GetStatistics, };
+static HRESULT WINAPI sink_writer_callback_QueryInterface(IMFAsyncCallback *iface, + REFIID riid, void **out) +{ + if (IsEqualIID(riid, &IID_IMFAsyncCallback) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = iface; + IMFAsyncCallback_AddRef(iface); + return S_OK; + } + + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI sink_writer_events_callback_AddRef(IMFAsyncCallback *iface) +{ + struct sink_writer *writer = impl_from_events_callback_IMFAsyncCallback(iface); + return IMFSinkWriter_AddRef(&writer->IMFSinkWriter_iface); +} + +static ULONG WINAPI sink_writer_events_callback_Release(IMFAsyncCallback *iface) +{ + struct sink_writer *writer = impl_from_events_callback_IMFAsyncCallback(iface); + return IMFSinkWriter_Release(&writer->IMFSinkWriter_iface); +} + +static HRESULT WINAPI sink_writer_callback_GetParameters(IMFAsyncCallback *iface, + DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI sink_writer_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + IMFStreamSink *stream_sink; + MediaEventType event_type; + IMFMediaEvent *event; + HRESULT hr; + + TRACE("%p, %p.\n", iface, result); + + stream_sink = (IMFStreamSink *)IMFAsyncResult_GetStateNoAddRef(result); + + if (FAILED(hr = IMFStreamSink_EndGetEvent(stream_sink, result, &event))) + return hr; + + IMFMediaEvent_GetType(event, &event_type); + + TRACE("Got event %lu.\n", event_type); + + IMFMediaEvent_Release(event); + + IMFStreamSink_BeginGetEvent(stream_sink, iface, (IUnknown *)stream_sink); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl sink_writer_events_callback_vtbl = +{ + sink_writer_callback_QueryInterface, + sink_writer_events_callback_AddRef, + sink_writer_events_callback_Release, + sink_writer_callback_GetParameters, + sink_writer_events_callback_Invoke, +}; + static HRESULT sink_writer_initialize_existing_streams(struct sink_writer *writer, IMFMediaSink *sink) { IMFStreamSink *stream_sink; @@ -296,6 +423,7 @@ HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attribut return E_OUTOFMEMORY;
object->IMFSinkWriter_iface.lpVtbl = &sink_writer_vtbl; + object->events_callback.lpVtbl = &sink_writer_events_callback_vtbl; object->refcount = 1; object->sink = sink; IMFMediaSink_AddRef(sink);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/writer.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index a61fa998f9e..b0414b0bc7f 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -237,6 +237,9 @@ static HRESULT WINAPI sink_writer_BeginWriting(IMFSinkWriter *iface) /* FIXME: notify the encoder */ }
+ if (SUCCEEDED(hr)) + hr = IMFPresentationClock_Start(writer->clock, 0); + writer->state = SINK_WRITER_STATE_WRITING; }
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/writer.c | 52 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index b0414b0bc7f..b4af637b614 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -39,6 +39,7 @@ enum writer_state struct stream { IMFStreamSink *stream_sink; + IMFTransform *encoder; };
struct sink_writer @@ -119,6 +120,8 @@ static ULONG WINAPI sink_writer_Release(IMFSinkWriter *iface)
if (stream->stream_sink) IMFStreamSink_Release(stream->stream_sink); + if (stream->encoder) + IMFTransform_Release(stream->encoder); } DeleteCriticalSection(&writer->cs); free(writer); @@ -248,6 +251,12 @@ static HRESULT WINAPI sink_writer_BeginWriting(IMFSinkWriter *iface) return hr; }
+static struct stream * sink_writer_get_stream(const struct sink_writer *writer, DWORD index) +{ + if (index >= writer->streams.count) return NULL; + return &writer->streams.items[index]; +} + static HRESULT WINAPI sink_writer_WriteSample(IMFSinkWriter *iface, DWORD index, IMFSample *sample) { FIXME("%p, %lu, %p.\n", iface, index, sample); @@ -290,12 +299,51 @@ static HRESULT WINAPI sink_writer_Finalize(IMFSinkWriter *iface) return E_NOTIMPL; }
+static HRESULT sink_writer_get_service(void *object, REFGUID service, REFIID riid, void **ret) +{ + IUnknown *iface = object; + IMFGetService *gs; + HRESULT hr; + + if (!iface) return MF_E_UNSUPPORTED_SERVICE; + + if (IsEqualGUID(service, &GUID_NULL)) + return IUnknown_QueryInterface(iface, riid, ret); + + if (FAILED(hr = IUnknown_QueryInterface(iface, &IID_IMFGetService, (void **)&gs))) + return hr; + + hr = IMFGetService_GetService(gs, service, riid, ret); + IMFGetService_Release(gs); + return hr; +} + static HRESULT WINAPI sink_writer_GetServiceForStream(IMFSinkWriter *iface, DWORD index, REFGUID service, REFIID riid, void **object) { - FIXME("%p, %lu, %s, %s, %p.\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object); + struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + HRESULT hr = E_UNEXPECTED; + struct stream *stream;
- return E_NOTIMPL; + TRACE("%p, %lu, %s, %s, %p.\n", iface, index, debugstr_guid(service), debugstr_guid(riid), object); + + EnterCriticalSection(&writer->cs); + + if (index == MF_SINK_WRITER_MEDIASINK) + hr = sink_writer_get_service(writer->sink, service, riid, object); + else if ((stream = sink_writer_get_stream(writer, index))) + { + if (stream->encoder) + hr = sink_writer_get_service(stream->encoder, service, riid, object); + if (FAILED(hr)) + hr = sink_writer_get_service(stream->stream_sink, service, riid, object); + } + else + hr = MF_E_INVALIDSTREAMNUMBER; + + LeaveCriticalSection(&writer->cs); + + return hr; }
static HRESULT WINAPI sink_writer_GetStatistics(IMFSinkWriter *iface, DWORD index, MF_SINK_WRITER_STATISTICS *stats)
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/writer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index b4af637b614..039e8fc7477 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -237,7 +237,8 @@ static HRESULT WINAPI sink_writer_BeginWriting(IMFSinkWriter *iface) WARN("Failed to subscribe to events for steam %u, hr %#lx.\n", i, hr); }
- /* FIXME: notify the encoder */ + if (stream->encoder) + IMFTransform_ProcessMessage(stream->encoder, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); }
if (SUCCEEDED(hr))
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/writer.c | 88 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 5 deletions(-)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 039e8fc7477..ccd4a92f4c4 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -40,6 +40,7 @@ struct stream { IMFStreamSink *stream_sink; IMFTransform *encoder; + MF_SINK_WRITER_STATISTICS stats; };
struct sink_writer @@ -59,6 +60,7 @@ struct sink_writer IMFPresentationClock *clock; IMFMediaSink *sink; enum writer_state state; + MF_SINK_WRITER_STATISTICS stats;
CRITICAL_SECTION cs; }; @@ -132,6 +134,7 @@ static ULONG WINAPI sink_writer_Release(IMFSinkWriter *iface)
static HRESULT sink_writer_add_stream(struct sink_writer *writer, IMFStreamSink *stream_sink, DWORD *index) { + struct stream *stream; DWORD id = 0; HRESULT hr;
@@ -144,9 +147,12 @@ static HRESULT sink_writer_add_stream(struct sink_writer *writer, IMFStreamSink if (FAILED(hr = IMFStreamSink_GetIdentifier(stream_sink, &id))) return hr;
*index = writer->streams.count++; + stream = &writer->streams.items[*index];
- writer->streams.items[*index].stream_sink = stream_sink; + stream->stream_sink = stream_sink; IMFStreamSink_AddRef(stream_sink); + memset(&stream->stats, 0, sizeof(stream->stats)); + stream->stats.cb = sizeof(stream->stats); writer->streams.next_id = max(writer->streams.next_id, id);
return hr; @@ -258,11 +264,61 @@ static struct stream * sink_writer_get_stream(const struct sink_writer *writer, return &writer->streams.items[index]; }
+static HRESULT sink_writer_get_buffer_length(IMFSample *sample, LONGLONG *timestamp, DWORD *length) +{ + IMFMediaBuffer *buffer; + HRESULT hr; + + *timestamp = 0; + *length = 0; + + if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer))) return hr; + hr = IMFMediaBuffer_GetCurrentLength(buffer, length); + IMFMediaBuffer_Release(buffer); + if (FAILED(hr)) return hr; + if (!*length) return E_INVALIDARG; + IMFSample_GetSampleTime(sample, timestamp); + + return hr; +} + static HRESULT WINAPI sink_writer_WriteSample(IMFSinkWriter *iface, DWORD index, IMFSample *sample) { - FIXME("%p, %lu, %p.\n", iface, index, sample); + struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct stream *stream; + LONGLONG timestamp; + DWORD length; + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p, %lu, %p.\n", iface, index, sample); + + if (!sample) + return E_INVALIDARG; + + EnterCriticalSection(&writer->cs); + + if (writer->state != SINK_WRITER_STATE_WRITING) + hr = MF_E_INVALIDREQUEST; + else if (!(stream = sink_writer_get_stream(writer, index))) + { + hr = MF_E_INVALIDSTREAMNUMBER; + } + else if (SUCCEEDED(hr = sink_writer_get_buffer_length(sample, ×tamp, &length))) + { + /* FIXME: queue sample */ + + stream->stats.llLastTimestampReceived = timestamp; + stream->stats.qwNumSamplesReceived++; + stream->stats.dwByteCountQueued += length; + + writer->stats.llLastTimestampReceived = timestamp; + writer->stats.qwNumSamplesReceived++; + writer->stats.dwByteCountQueued += length; + } + + EnterCriticalSection(&writer->cs); + + return hr; }
static HRESULT WINAPI sink_writer_SendStreamTick(IMFSinkWriter *iface, DWORD index, LONGLONG timestamp) @@ -349,9 +405,30 @@ static HRESULT WINAPI sink_writer_GetServiceForStream(IMFSinkWriter *iface, DWOR
static HRESULT WINAPI sink_writer_GetStatistics(IMFSinkWriter *iface, DWORD index, MF_SINK_WRITER_STATISTICS *stats) { - FIXME("%p, %lu, %p.\n", iface, index, stats); + struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct stream *stream; + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %lu, %p.\n", iface, index, stats); + + if (!stats) + return E_POINTER; + + if (stats->cb != sizeof(*stats)) + return E_INVALIDARG; + + EnterCriticalSection(&writer->cs); + + if (index == MF_SINK_WRITER_ALL_STREAMS) + *stats = writer->stats; + else if ((stream = sink_writer_get_stream(writer, index))) + *stats = stream->stats; + else + hr = MF_E_INVALIDSTREAMNUMBER; + + LeaveCriticalSection(&writer->cs); + + return hr; }
static const IMFSinkWriterVtbl sink_writer_vtbl = @@ -479,6 +556,7 @@ HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attribut object->refcount = 1; object->sink = sink; IMFMediaSink_AddRef(sink); + object->stats.cb = sizeof(object->stats); InitializeCriticalSection(&object->cs);
if (FAILED(hr = sink_writer_initialize_existing_streams(object, sink)))
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/writer.c | 50 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index ccd4a92f4c4..ed05b0d3191 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -60,6 +60,7 @@ struct sink_writer IMFPresentationClock *clock; IMFMediaSink *sink; enum writer_state state; + HRESULT status; MF_SINK_WRITER_STATISTICS stats;
CRITICAL_SECTION cs; @@ -419,7 +420,9 @@ static HRESULT WINAPI sink_writer_GetStatistics(IMFSinkWriter *iface, DWORD inde
EnterCriticalSection(&writer->cs);
- if (index == MF_SINK_WRITER_ALL_STREAMS) + if (FAILED(writer->status)) + hr = writer->status; + else if (index == MF_SINK_WRITER_ALL_STREAMS) *stats = writer->stats; else if ((stream = sink_writer_get_stream(writer, index))) *stats = stream->stats; @@ -483,12 +486,28 @@ static HRESULT WINAPI sink_writer_callback_GetParameters(IMFAsyncCallback *iface return E_NOTIMPL; }
+static struct stream *sink_writer_get_stream_for_stream_sink(struct sink_writer *writer, IMFStreamSink *stream_sink) +{ + size_t i; + + for (i = 0; i < writer->streams.count; ++i) + { + if (writer->streams.items[i].stream_sink == stream_sink) + return &writer->streams.items[i]; + } + + return NULL; +} + static HRESULT WINAPI sink_writer_events_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) { + struct sink_writer *writer = impl_from_events_callback_IMFAsyncCallback(iface); IMFStreamSink *stream_sink; MediaEventType event_type; + struct stream *stream; IMFMediaEvent *event; - HRESULT hr; + LONGLONG timestamp; + HRESULT status, hr;
TRACE("%p, %p.\n", iface, result);
@@ -498,9 +517,36 @@ static HRESULT WINAPI sink_writer_events_callback_Invoke(IMFAsyncCallback *iface return hr;
IMFMediaEvent_GetType(event, &event_type); + IMFMediaEvent_GetStatus(event, &status);
TRACE("Got event %lu.\n", event_type);
+ EnterCriticalSection(&writer->cs); + + if (writer->status == S_OK && FAILED(status)) + writer->status = status; + + if (writer->status == S_OK && (stream = sink_writer_get_stream_for_stream_sink(writer, stream_sink))) + { + switch (event_type) + { + case MEStreamSinkRequestSample: + + timestamp = MFGetSystemTime(); + + writer->stats.llLastSinkSampleRequest = timestamp; + writer->stats.dwNumOutstandingSinkSampleRequests++; + stream->stats.llLastSinkSampleRequest = timestamp; + stream->stats.dwNumOutstandingSinkSampleRequests++; + + break; + default: + ; + } + } + + LeaveCriticalSection(&writer->cs); + IMFMediaEvent_Release(event);
IMFStreamSink_BeginGetEvent(stream_sink, iface, (IUnknown *)stream_sink);