From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/writer.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index c708664d2fc..765b50155b9 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -83,6 +83,7 @@ struct sink_writer HRESULT status; MF_SINK_WRITER_STATISTICS stats;
+ IMFAttributes *attributes; IMFSinkWriterCallback *callback;
CRITICAL_SECTION cs; @@ -225,6 +226,8 @@ static ULONG WINAPI sink_writer_Release(IMFSinkWriter *iface) IMFPresentationClock_Release(writer->clock); if (writer->sink) IMFMediaSink_Release(writer->sink); + if (writer->attributes) + IMFAttributes_Release(writer->attributes); if (writer->callback) IMFSinkWriterCallback_Release(writer->callback); for (i = 0; i < writer->streams.count; ++i) @@ -978,6 +981,7 @@ HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attribut
if (attributes) { + IMFAttributes_AddRef((object->attributes = attributes)); IMFAttributes_GetUnknown(attributes, &MF_SINK_WRITER_ASYNC_CALLBACK, &IID_IMFSinkWriterCallback, (void **)&object->callback); }
From: Ziqing Hui zhui@codeweavers.com
Our tests show that there will be 2 transforms created for encoding. So we use a array here rather than a single encoder transform. --- dlls/mfreadwrite/writer.c | 40 +++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 765b50155b9..67af6dc816f 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -46,6 +46,12 @@ struct marker_context void *user_context; };
+struct transform +{ + IMFTransform *transform; + GUID category; +}; + struct pending_item { struct list entry; @@ -58,9 +64,9 @@ struct pending_item struct stream { IMFStreamSink *stream_sink; - IMFTransform *encoder; + struct transform transforms[2]; MF_SINK_WRITER_STATISTICS stats; - struct list queue; + struct list queue; /* struct pending_item */ };
struct sink_writer @@ -166,6 +172,14 @@ static HRESULT create_marker_context(unsigned int marker_type, void *user_contex
return S_OK; } +static void stream_release_transforms(struct stream *stream) +{ + if (stream->transforms[0].transform) + IMFTransform_Release(stream->transforms[0].transform); + if (stream->transforms[1].transform) + IMFTransform_Release(stream->transforms[1].transform); + memset(stream->transforms, 0, sizeof(stream->transforms)); +}
static void sink_writer_release_pending_item(struct pending_item *item) { @@ -236,8 +250,7 @@ static ULONG WINAPI sink_writer_Release(IMFSinkWriter *iface)
if (stream->stream_sink) IMFStreamSink_Release(stream->stream_sink); - if (stream->encoder) - IMFTransform_Release(stream->encoder); + stream_release_transforms(stream); sink_writer_drop_pending_items(stream); } DeleteCriticalSection(&writer->cs); @@ -360,8 +373,10 @@ static HRESULT WINAPI sink_writer_BeginWriting(IMFSinkWriter *iface) WARN("Failed to subscribe to events for steam %u, hr %#lx.\n", i, hr); }
- if (stream->encoder) - IMFTransform_ProcessMessage(stream->encoder, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); + if (stream->transforms[0].transform) + IMFTransform_ProcessMessage(stream->transforms[0].transform, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); + if (stream->transforms[1].transform) + IMFTransform_ProcessMessage(stream->transforms[1].transform, MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0); }
if (SUCCEEDED(hr)) @@ -469,8 +484,10 @@ static HRESULT sink_writer_flush(struct sink_writer *writer, unsigned int index)
IMFStreamSink_Flush(stream->stream_sink);
- if (stream->encoder) - IMFTransform_ProcessMessage(stream->encoder, MFT_MESSAGE_COMMAND_FLUSH, 0); + if (stream->transforms[0].transform) + IMFTransform_ProcessMessage(stream->transforms[0].transform, MFT_MESSAGE_COMMAND_FLUSH, 0); + if (stream->transforms[1].transform) + IMFTransform_ProcessMessage(stream->transforms[1].transform, MFT_MESSAGE_COMMAND_FLUSH, 0);
return sink_writer_place_marker(writer, stream, MFSTREAMSINK_MARKER_ENDOFSEGMENT, 0, NULL); } @@ -741,8 +758,11 @@ static HRESULT WINAPI sink_writer_GetServiceForStream(IMFSinkWriter *iface, DWOR 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 (stream->transforms[1].transform) + hr = sink_writer_get_service(stream->transforms[1].transform, service, riid, object); + else if (stream->transforms[0].transform) + hr = sink_writer_get_service(stream->transforms[0].transform, service, riid, object); + if (FAILED(hr)) hr = sink_writer_get_service(stream->stream_sink, service, riid, object); }
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/tests/mfplat.c | 13 ++-- dlls/mfreadwrite/writer.c | 114 +++++++++++++++++++++----------- 2 files changed, 82 insertions(+), 45 deletions(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 7ed757073ff..bc6d8a2ca8f 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1698,7 +1698,6 @@ static void test_sink_writer_get_object(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMFSinkWriter_QueryInterface(writer, &IID_IMFSinkWriterEx, (void **)&writer_ex); - todo_wine ok(hr == S_OK, "QueryInterface returned %#lx.\n", hr);
hr = MFCreateMediaType(&stream_type); @@ -1715,13 +1714,10 @@ static void test_sink_writer_get_object(void) ok(hr == MF_E_UNSUPPORTED_SERVICE, "GetServiceForStream returned %#lx.\n", hr); ok(!transform, "Unexpected transform %p.\n", transform);
- if (writer_ex) - { transform = (void *)0xdeadbeef; hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 0, &guid, &transform); ok(hr == MF_E_INVALIDINDEX, "GetTransformForStream returned %#lx.\n", hr); ok(!transform, "Unexpected transform %p.\n", transform); - }
hr = MFCreateMediaType(&input_type); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -1738,23 +1734,26 @@ static void test_sink_writer_get_object(void) if (hr == S_OK) IMFTransform_Release(transform);
- if (writer_ex) - { hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 0, &guid, &transform); + todo_wine ok(hr == S_OK, "GetTransformForStream returned %#lx.\n", hr); + todo_wine ok(IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_PROCESSOR), "Unexpected guid %s.\n", debugstr_guid(&guid)); + if (hr == S_OK) IMFTransform_Release(transform);
hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 1, &guid, &transform); + todo_wine ok(hr == S_OK, "GetTransformForStream returned %#lx.\n", hr); + todo_wine ok(IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_ENCODER), "Unexpected guid %s.\n", debugstr_guid(&guid)); + if (hr == S_OK) IMFTransform_Release(transform);
transform = (void *)0xdeadbeef; hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 2, &guid, &transform); ok(hr == MF_E_INVALIDINDEX, "GetTransformForStream returned %#lx.\n", hr); ok(!transform, "Unexpected transform %p.\n", transform); - }
/* Get media sink before BeginWriting. */ sink = (void *)0xdeadbeef; diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 67af6dc816f..a845058ed32 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -71,7 +71,7 @@ struct stream
struct sink_writer { - IMFSinkWriter IMFSinkWriter_iface; + IMFSinkWriterEx IMFSinkWriterEx_iface; IMFAsyncCallback events_callback; LONG refcount;
@@ -95,9 +95,9 @@ struct sink_writer CRITICAL_SECTION cs; };
-static struct sink_writer *impl_from_IMFSinkWriter(IMFSinkWriter *iface) +static struct sink_writer *impl_from_IMFSinkWriterEx(IMFSinkWriterEx *iface) { - return CONTAINING_RECORD(iface, struct sink_writer, IMFSinkWriter_iface); + return CONTAINING_RECORD(iface, struct sink_writer, IMFSinkWriterEx_iface); }
static struct sink_writer *impl_from_events_callback_IMFAsyncCallback(IMFAsyncCallback *iface) @@ -189,15 +189,16 @@ static void sink_writer_release_pending_item(struct pending_item *item) free(item); }
-static HRESULT WINAPI sink_writer_QueryInterface(IMFSinkWriter *iface, REFIID riid, void **out) +static HRESULT WINAPI sink_writer_QueryInterface(IMFSinkWriterEx *iface, REFIID riid, void **out) { TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
- if (IsEqualIID(riid, &IID_IMFSinkWriter) || - IsEqualIID(riid, &IID_IUnknown)) + if (IsEqualIID(riid, &IID_IMFSinkWriterEx) + || IsEqualIID(riid, &IID_IMFSinkWriter) + || IsEqualIID(riid, &IID_IUnknown)) { *out = iface; - IMFSinkWriter_AddRef(iface); + IMFSinkWriterEx_AddRef(iface); return S_OK; }
@@ -206,9 +207,9 @@ static HRESULT WINAPI sink_writer_QueryInterface(IMFSinkWriter *iface, REFIID ri return E_NOINTERFACE; }
-static ULONG WINAPI sink_writer_AddRef(IMFSinkWriter *iface) +static ULONG WINAPI sink_writer_AddRef(IMFSinkWriterEx *iface) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); ULONG refcount = InterlockedIncrement(&writer->refcount);
TRACE("%p, %lu.\n", iface, refcount); @@ -226,9 +227,9 @@ static void sink_writer_drop_pending_items(struct stream *stream) } }
-static ULONG WINAPI sink_writer_Release(IMFSinkWriter *iface) +static ULONG WINAPI sink_writer_Release(IMFSinkWriterEx *iface) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); ULONG refcount = InterlockedDecrement(&writer->refcount); unsigned int i;
@@ -288,9 +289,9 @@ static HRESULT sink_writer_add_stream(struct sink_writer *writer, IMFStreamSink return hr; }
-static HRESULT WINAPI sink_writer_AddStream(IMFSinkWriter *iface, IMFMediaType *media_type, DWORD *index) +static HRESULT WINAPI sink_writer_AddStream(IMFSinkWriterEx *iface, IMFMediaType *media_type, DWORD *index) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); HRESULT hr = MF_E_INVALIDREQUEST; IMFStreamSink *stream_sink; DWORD id; @@ -320,7 +321,7 @@ static HRESULT WINAPI sink_writer_AddStream(IMFSinkWriter *iface, IMFMediaType * return hr; }
-static HRESULT WINAPI sink_writer_SetInputMediaType(IMFSinkWriter *iface, DWORD index, IMFMediaType *type, +static HRESULT WINAPI sink_writer_SetInputMediaType(IMFSinkWriterEx *iface, DWORD index, IMFMediaType *type, IMFAttributes *parameters) { FIXME("%p, %lu, %p, %p.\n", iface, index, type, parameters); @@ -347,9 +348,9 @@ static HRESULT sink_writer_set_presentation_clock(struct sink_writer *writer) return hr; }
-static HRESULT WINAPI sink_writer_BeginWriting(IMFSinkWriter *iface) +static HRESULT WINAPI sink_writer_BeginWriting(IMFSinkWriterEx *iface) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); HRESULT hr = S_OK; unsigned int i;
@@ -573,9 +574,9 @@ static HRESULT sink_writer_write_sample(struct sink_writer *writer, struct strea return hr; }
-static HRESULT WINAPI sink_writer_WriteSample(IMFSinkWriter *iface, DWORD index, IMFSample *sample) +static HRESULT WINAPI sink_writer_WriteSample(IMFSinkWriterEx *iface, DWORD index, IMFSample *sample) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); struct stream *stream; LONGLONG timestamp; DWORD length; @@ -612,9 +613,9 @@ static HRESULT WINAPI sink_writer_WriteSample(IMFSinkWriter *iface, DWORD index, return hr; }
-static HRESULT WINAPI sink_writer_SendStreamTick(IMFSinkWriter *iface, DWORD index, LONGLONG timestamp) +static HRESULT WINAPI sink_writer_SendStreamTick(IMFSinkWriterEx *iface, DWORD index, LONGLONG timestamp) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); HRESULT hr;
TRACE("%p, %lu, %s.\n", iface, index, wine_dbgstr_longlong(timestamp)); @@ -631,9 +632,9 @@ static HRESULT WINAPI sink_writer_SendStreamTick(IMFSinkWriter *iface, DWORD ind return hr; }
-static HRESULT WINAPI sink_writer_PlaceMarker(IMFSinkWriter *iface, DWORD index, void *user_context) +static HRESULT WINAPI sink_writer_PlaceMarker(IMFSinkWriterEx *iface, DWORD index, void *user_context) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); struct stream *stream; HRESULT hr;
@@ -655,9 +656,9 @@ static HRESULT WINAPI sink_writer_PlaceMarker(IMFSinkWriter *iface, DWORD index, return hr; }
-static HRESULT WINAPI sink_writer_NotifyEndOfSegment(IMFSinkWriter *iface, DWORD index) +static HRESULT WINAPI sink_writer_NotifyEndOfSegment(IMFSinkWriterEx *iface, DWORD index) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); HRESULT hr = S_OK; unsigned int i;
@@ -686,9 +687,9 @@ static HRESULT WINAPI sink_writer_NotifyEndOfSegment(IMFSinkWriter *iface, DWORD return hr; }
-static HRESULT WINAPI sink_writer_Flush(IMFSinkWriter *iface, DWORD index) +static HRESULT WINAPI sink_writer_Flush(IMFSinkWriterEx *iface, DWORD index) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); HRESULT hr = S_OK; unsigned int i;
@@ -717,7 +718,7 @@ static HRESULT WINAPI sink_writer_Flush(IMFSinkWriter *iface, DWORD index) return hr; }
-static HRESULT WINAPI sink_writer_Finalize(IMFSinkWriter *iface) +static HRESULT WINAPI sink_writer_Finalize(IMFSinkWriterEx *iface) { FIXME("%p.\n", iface);
@@ -743,10 +744,10 @@ static HRESULT sink_writer_get_service(void *object, REFGUID service, REFIID rii return hr; }
-static HRESULT WINAPI sink_writer_GetServiceForStream(IMFSinkWriter *iface, DWORD index, REFGUID service, +static HRESULT WINAPI sink_writer_GetServiceForStream(IMFSinkWriterEx *iface, DWORD index, REFGUID service, REFIID riid, void **object) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); HRESULT hr = E_UNEXPECTED; struct stream *stream;
@@ -774,9 +775,9 @@ static HRESULT WINAPI sink_writer_GetServiceForStream(IMFSinkWriter *iface, DWOR return hr; }
-static HRESULT WINAPI sink_writer_GetStatistics(IMFSinkWriter *iface, DWORD index, MF_SINK_WRITER_STATISTICS *stats) +static HRESULT WINAPI sink_writer_GetStatistics(IMFSinkWriterEx *iface, DWORD index, MF_SINK_WRITER_STATISTICS *stats) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); struct stream *stream; HRESULT hr = S_OK;
@@ -804,7 +805,43 @@ static HRESULT WINAPI sink_writer_GetStatistics(IMFSinkWriter *iface, DWORD inde return hr; }
-static const IMFSinkWriterVtbl sink_writer_vtbl = +static HRESULT WINAPI sink_writer_GetTransformForStream(IMFSinkWriterEx *iface, + DWORD stream_index, DWORD transform_index, GUID *category, IMFTransform **transform) +{ + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); + struct transform *entry; + struct stream *stream; + + TRACE("%p, %#lx, %#lx, %p, %p.\n", iface, stream_index, transform_index, category, transform); + + if (!transform) + return E_POINTER; + *transform = NULL; + + EnterCriticalSection(&writer->cs); + + if (!(stream = sink_writer_get_stream(writer, stream_index))) + { + LeaveCriticalSection(&writer->cs); + return MF_E_INVALIDSTREAMNUMBER; + } + + if (transform_index > 1 || !stream->transforms[transform_index].transform) + { + LeaveCriticalSection(&writer->cs); + return MF_E_INVALIDINDEX; + } + + entry = &stream->transforms[transform_index]; + IMFTransform_AddRef((*transform = entry->transform)); + if (category) + *category = entry->category; + + LeaveCriticalSection(&writer->cs); + return S_OK; +} + +static const IMFSinkWriterExVtbl sink_writer_vtbl = { sink_writer_QueryInterface, sink_writer_AddRef, @@ -820,6 +857,7 @@ static const IMFSinkWriterVtbl sink_writer_vtbl = sink_writer_Finalize, sink_writer_GetServiceForStream, sink_writer_GetStatistics, + sink_writer_GetTransformForStream, };
static HRESULT WINAPI sink_writer_callback_QueryInterface(IMFAsyncCallback *iface, @@ -841,13 +879,13 @@ static HRESULT WINAPI sink_writer_callback_QueryInterface(IMFAsyncCallback *ifac 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); + return IMFSinkWriterEx_AddRef(&writer->IMFSinkWriterEx_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); + return IMFSinkWriterEx_Release(&writer->IMFSinkWriterEx_iface); }
static HRESULT WINAPI sink_writer_callback_GetParameters(IMFAsyncCallback *iface, @@ -991,7 +1029,7 @@ HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attribut if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY;
- object->IMFSinkWriter_iface.lpVtbl = &sink_writer_vtbl; + object->IMFSinkWriterEx_iface.lpVtbl = &sink_writer_vtbl; object->events_callback.lpVtbl = &sink_writer_events_callback_vtbl; object->refcount = 1; object->sink = sink; @@ -1008,12 +1046,12 @@ HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attribut
if (FAILED(hr = sink_writer_initialize_existing_streams(object, sink))) { - IMFSinkWriter_Release(&object->IMFSinkWriter_iface); + IMFSinkWriterEx_Release(&object->IMFSinkWriterEx_iface); return hr; }
- hr = IMFSinkWriter_QueryInterface(&object->IMFSinkWriter_iface, riid, out); - IMFSinkWriter_Release(&object->IMFSinkWriter_iface); + hr = IMFSinkWriterEx_QueryInterface(&object->IMFSinkWriterEx_iface, riid, out); + IMFSinkWriterEx_Release(&object->IMFSinkWriterEx_iface); return hr; }
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/tests/mfplat.c | 3 -- dlls/mfreadwrite/writer.c | 75 +++++++++++++++++++++++++++++---- 2 files changed, 67 insertions(+), 11 deletions(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index bc6d8a2ca8f..81bfc3eda76 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1840,15 +1840,12 @@ static void test_sink_writer_add_stream(void) init_media_type(input_type, video_input_type_desc, -1);
hr = IMFSinkWriter_SetInputMediaType(writer, 0xdeadbeef, NULL, NULL); - todo_wine ok(hr == E_INVALIDARG, "SetInputMediaType returned %#lx.\n", hr);
hr = IMFSinkWriter_SetInputMediaType(writer, 0, NULL, NULL); - todo_wine ok(hr == E_INVALIDARG, "SetInputMediaType returned %#lx.\n", hr);
hr = IMFSinkWriter_SetInputMediaType(writer, 0xdeadbeef, input_type, NULL); - todo_wine ok(hr == MF_E_INVALIDSTREAMNUMBER, "SetInputMediaType returned %#lx.\n", hr);
hr = IMFSinkWriter_SetInputMediaType(writer, 0, input_type, NULL); diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index a845058ed32..d420f5971fb 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -181,6 +181,32 @@ static void stream_release_transforms(struct stream *stream) memset(stream->transforms, 0, sizeof(stream->transforms)); }
+static HRESULT stream_get_type(struct stream *stream, IMFMediaType **out_type) +{ + IMFMediaTypeHandler *type_handler; + HRESULT hr; + + if (FAILED(hr = IMFStreamSink_GetMediaTypeHandler(stream->stream_sink, &type_handler))) + return hr; + hr = IMFMediaTypeHandler_GetCurrentMediaType(type_handler, out_type); + + IMFMediaTypeHandler_Release(type_handler); + return hr; +} + +static HRESULT stream_create_transforms(struct stream *stream, + IMFMediaType *input_type, IMFMediaType *output_type, BOOL use_encoder) +{ + return E_NOTIMPL; +} + +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 void sink_writer_release_pending_item(struct pending_item *item) { list_remove(&item->entry); @@ -324,9 +350,48 @@ static HRESULT WINAPI sink_writer_AddStream(IMFSinkWriterEx *iface, IMFMediaType static HRESULT WINAPI sink_writer_SetInputMediaType(IMFSinkWriterEx *iface, DWORD index, IMFMediaType *type, IMFAttributes *parameters) { - FIXME("%p, %lu, %p, %p.\n", iface, index, type, parameters); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); + IMFMediaType *stream_type = NULL; + struct stream *stream; + DWORD flags; + HRESULT hr;
- return E_NOTIMPL; + TRACE("%p, %lu, %p, %p.\n", iface, index, type, parameters); + + if (!type) + return E_INVALIDARG; + + EnterCriticalSection(&writer->cs); + + if (!(stream = sink_writer_get_stream(writer, index))) + { + hr = MF_E_INVALIDSTREAMNUMBER; + goto done; + } + + if (FAILED(hr = stream_get_type(stream, &stream_type)) + || FAILED(hr = IMFMediaType_IsEqual(type, stream_type, &flags))) + goto done; + + if (!(flags & MF_MEDIATYPE_EQUAL_MAJOR_TYPES)) + { + hr = MF_E_INVALIDMEDIATYPE; + goto done; + } + + /* Types are not compatible, create transforms. */ + if (!(flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)) + { + /* Try only using converter first, then try again with encoder. */ + if (FAILED(hr = stream_create_transforms(stream, type, stream_type, FALSE))) + hr = stream_create_transforms(stream, type, stream_type, TRUE); + } + +done: + if (stream_type) + IMFMediaType_Release(stream_type); + LeaveCriticalSection(&writer->cs); + return hr; }
static HRESULT sink_writer_set_presentation_clock(struct sink_writer *writer) @@ -391,12 +456,6 @@ static HRESULT WINAPI sink_writer_BeginWriting(IMFSinkWriterEx *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 sink_writer_get_buffer_length(IMFSample *sample, LONGLONG *timestamp, DWORD *length) { IMFMediaBuffer *buffer;
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/writer.c | 67 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index d420f5971fb..5e7a67d944f 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -172,6 +172,12 @@ static HRESULT create_marker_context(unsigned int marker_type, void *user_contex
return S_OK; } + +static HRESULT create_transform_from_activate(IMFActivate *activate, struct transform *out_transform) +{ + return E_NOTIMPL; +} + static void stream_release_transforms(struct stream *stream) { if (stream->transforms[0].transform) @@ -194,10 +200,69 @@ static HRESULT stream_get_type(struct stream *stream, IMFMediaType **out_type) return hr; }
+static HRESULT transform_set_types(struct transform *transform, IMFMediaType *input_type, IMFMediaType *output_type) +{ + return E_NOTIMPL; +} + +static HRESULT stream_enumerate_transforms(struct stream *stream, IMFMediaType *input_type, IMFMediaType *output_type, + BOOL use_encoder, IMFActivate ***out_activates, UINT32 *out_count) +{ + return E_NOTIMPL; +} + static HRESULT stream_create_transforms(struct stream *stream, IMFMediaType *input_type, IMFMediaType *output_type, BOOL use_encoder) { - return E_NOTIMPL; + IMFMediaType *encoder_input_type; + struct transform transform = {}; + IMFActivate **activates; + UINT32 count = 0, i; + HRESULT hr; + + /* Enumerate available transforms. */ + if (FAILED(hr = stream_enumerate_transforms(stream, input_type, output_type, use_encoder, &activates, &count))) + return hr; + for (i = 0; i < count; i++) + { + /* Create transform. */ + if (FAILED(hr = create_transform_from_activate(activates[i], &transform))) + continue; + + /* Set types on transform. */ + if (SUCCEEDED(hr = transform_set_types(&transform, input_type, output_type))) + { + TRACE("Created %s transform %p.", use_encoder ? "encoder" : "converter", transform.transform); + stream->transforms[0] = transform; + break; + } + + /* Failed to use a single encoder, try using an encoder and a converter. */ + if (use_encoder) + { + if (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform.transform, 0, 0, &encoder_input_type))) + { + /* Create converter. */ + if (SUCCEEDED(hr = stream_create_transforms(stream, input_type, encoder_input_type, FALSE))) + { + /* We have converter on transforms[0], set transforms[1] to encoder. */ + TRACE("Created encoder transform %p.", transform.transform); + stream->transforms[1] = transform; + IMFMediaType_Release(encoder_input_type); + break; + } + IMFMediaType_Release(encoder_input_type); + } + } + + IMFTransform_Release(transform.transform); + } + + for (i = 0; i < count; ++i) + IMFActivate_Release(activates[i]); + CoTaskMemFree(activates); + + return hr; }
static struct stream *sink_writer_get_stream(const struct sink_writer *writer, DWORD index)
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/writer.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 5e7a67d944f..0e279dfb3fd 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -175,7 +175,15 @@ static HRESULT create_marker_context(unsigned int marker_type, void *user_contex
static HRESULT create_transform_from_activate(IMFActivate *activate, struct transform *out_transform) { - return E_NOTIMPL; + struct transform transform; + HRESULT hr; + + if (FAILED(hr = IMFActivate_GetGUID(activate, &MF_TRANSFORM_CATEGORY_Attribute, &transform.category))) + return hr; + if (SUCCEEDED(hr = IMFActivate_ActivateObject(activate, &IID_IMFTransform, (void **)&transform.transform))) + *out_transform = transform; + + return hr; }
static void stream_release_transforms(struct stream *stream)
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/writer.c | 50 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 0e279dfb3fd..b494d2edd0c 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -66,6 +66,7 @@ struct stream IMFStreamSink *stream_sink; struct transform transforms[2]; MF_SINK_WRITER_STATISTICS stats; + struct sink_writer *writer; struct list queue; /* struct pending_item */ };
@@ -216,7 +217,53 @@ static HRESULT transform_set_types(struct transform *transform, IMFMediaType *in static HRESULT stream_enumerate_transforms(struct stream *stream, IMFMediaType *input_type, IMFMediaType *output_type, BOOL use_encoder, IMFActivate ***out_activates, UINT32 *out_count) { - return E_NOTIMPL; + UINT32 flags = MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_LOCALMFT | MFT_ENUM_FLAG_SORTANDFILTER; + BOOL disable_converter = FALSE, use_hardware_transforms = FALSE; + MFT_REGISTER_TYPE_INFO input_type_info, output_type_info; + struct sink_writer *writer = stream->writer; + GUID category; + HRESULT hr; + + /* Check writer attributes. */ + if (writer->attributes) + { + IMFAttributes_GetUINT32(writer->attributes, + &MF_READWRITE_DISABLE_CONVERTERS, (UINT32 *)&disable_converter); + IMFAttributes_GetUINT32(writer->attributes, + &MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, (UINT32 *)&use_hardware_transforms); + if (use_hardware_transforms) + flags |= MFT_ENUM_FLAG_HARDWARE; + } + + /* Neither encoder nor converter is allowed, return failure. */ + if (!use_encoder && disable_converter) + return E_FAIL; + + /* Get type infos. */ + if (FAILED(hr = IMFMediaType_GetMajorType(input_type, &input_type_info.guidMajorType)) + || FAILED(hr = IMFMediaType_GetGUID(input_type, &MF_MT_SUBTYPE, &input_type_info.guidSubtype))) + return hr; + if (FAILED(hr = IMFMediaType_GetMajorType(output_type, &output_type_info.guidMajorType)) + || FAILED(hr = IMFMediaType_GetGUID(output_type, &MF_MT_SUBTYPE, &output_type_info.guidSubtype))) + return hr; + + /* Set category according to major type. */ + if (IsEqualGUID(&output_type_info.guidMajorType, &MFMediaType_Video)) + category = use_encoder ? MFT_CATEGORY_VIDEO_ENCODER : MFT_CATEGORY_VIDEO_PROCESSOR; + else if (IsEqualGUID(&output_type_info.guidMajorType, &MFMediaType_Audio)) + category = use_encoder ? MFT_CATEGORY_AUDIO_ENCODER : MFT_CATEGORY_AUDIO_EFFECT; + else + return MF_E_TOPO_CODEC_NOT_FOUND; + + /* Enumerate available transforms. */ + *out_count = 0; + if (FAILED(hr = MFTEnumEx(category, flags, + (disable_converter ? &input_type_info : NULL), &output_type_info, out_activates, out_count))) + return hr; + if (!*out_count) + return MF_E_TOPO_CODEC_NOT_FOUND; + + return hr; }
static HRESULT stream_create_transforms(struct stream *stream, @@ -381,6 +428,7 @@ static HRESULT sink_writer_add_stream(struct sink_writer *writer, IMFStreamSink stream->stream_sink = stream_sink; IMFStreamSink_AddRef(stream_sink); stream->stats.cb = sizeof(stream->stats); + stream->writer = writer; list_init(&stream->queue);
writer->streams.next_id = max(writer->streams.next_id, id);
From: Ziqing Hui zhui@codeweavers.com
We will use this in writer.c, so make it non-static. For writer, the source type is from downstream, so rename this. --- dlls/mfreadwrite/mf_private.h | 1 + dlls/mfreadwrite/reader.c | 58 +++++++++++++++++------------------ 2 files changed, 30 insertions(+), 29 deletions(-)
diff --git a/dlls/mfreadwrite/mf_private.h b/dlls/mfreadwrite/mf_private.h index d8b44712b4a..92e0e20f67d 100644 --- a/dlls/mfreadwrite/mf_private.h +++ b/dlls/mfreadwrite/mf_private.h @@ -22,6 +22,7 @@ extern HRESULT create_sink_writer_from_url(const WCHAR *url, IMFByteStream *stre IMFAttributes *attributes, REFIID riid, void **out); extern HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attributes, REFIID riid, void **out); +extern HRESULT update_media_type(IMFMediaType *dst_type, IMFMediaType *src_type);
static inline BOOL mf_array_reserve(void **elements, size_t *capacity, size_t count, size_t size) { diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 4d223f1de6e..690569f4138 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -714,39 +714,39 @@ static void media_type_try_copy_attr(IMFMediaType *dst, IMFMediaType *src, const PropVariantClear(&value); }
-/* update a media type with additional attributes reported by upstream element */ -/* also present in mf/topology_loader.c pipeline */ -static HRESULT update_media_type_from_upstream(IMFMediaType *media_type, IMFMediaType *upstream_type) +/* Update a media type with additional attributes reported by another media type, */ +/* also present as update_media_type_from_upstream in mf/topology_loader.c pipeline. */ +HRESULT update_media_type(IMFMediaType *dst_type, IMFMediaType *src_type) { HRESULT hr = S_OK;
/* propagate common video attributes */ - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_SIZE, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FRAME_RATE, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_DEFAULT_STRIDE, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_ROTATION, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_FIXED_SIZE_SAMPLES, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_PIXEL_ASPECT_RATIO, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &hr); - - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_CHROMA_SITING, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_INTERLACE_MODE, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_TRANSFER_FUNCTION, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_PRIMARIES, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_YUV_MATRIX, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_LIGHTING, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_VIDEO_NOMINAL_RANGE, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_FRAME_SIZE, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_FRAME_RATE, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_DEFAULT_STRIDE, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_VIDEO_ROTATION, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_FIXED_SIZE_SAMPLES, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_PIXEL_ASPECT_RATIO, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, &hr); + + media_type_try_copy_attr(dst_type, src_type, &MF_MT_VIDEO_CHROMA_SITING, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_INTERLACE_MODE, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_TRANSFER_FUNCTION, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_VIDEO_PRIMARIES, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_YUV_MATRIX, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_VIDEO_LIGHTING, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_VIDEO_NOMINAL_RANGE, &hr);
/* propagate common audio attributes */ - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_NUM_CHANNELS, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_CHANNEL_MASK, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &hr); - media_type_try_copy_attr(media_type, upstream_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_AUDIO_NUM_CHANNELS, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_AUDIO_CHANNEL_MASK, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_AUDIO_SAMPLES_PER_BLOCK, &hr); + media_type_try_copy_attr(dst_type, src_type, &MF_MT_AUDIO_VALID_BITS_PER_SAMPLE, &hr);
return hr; } @@ -2120,7 +2120,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL if (SUCCEEDED(hr = IMFTransform_SetInputType(transform, 0, input_type, 0)) && SUCCEEDED(hr = IMFTransform_GetInputCurrentType(transform, 0, &media_type))) { - if (SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type)) + if (SUCCEEDED(hr = update_media_type(output_type, media_type)) && FAILED(hr = IMFTransform_SetOutputType(transform, 0, output_type, 0)) && FAILED(hr = set_matching_transform_output_type(transform, output_type)) && allow_processor && SUCCEEDED(hr = IMFTransform_GetOutputAvailableType(transform, 0, 0, &media_type))) @@ -2128,7 +2128,7 @@ static HRESULT source_reader_create_transform(struct source_reader *reader, BOOL struct transform_entry *converter;
if (SUCCEEDED(hr = IMFTransform_SetOutputType(transform, 0, media_type, 0)) - && SUCCEEDED(hr = update_media_type_from_upstream(output_type, media_type)) + && SUCCEEDED(hr = update_media_type(output_type, media_type)) && SUCCEEDED(hr = source_reader_create_transform(reader, FALSE, FALSE, media_type, output_type, &converter))) list_add_tail(&entry->entry, &converter->entry);
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/tests/mfplat.c | 8 -------- dlls/mfreadwrite/writer.c | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 81bfc3eda76..afcc1b86970 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1723,29 +1723,23 @@ static void test_sink_writer_get_object(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); init_media_type(input_type, video_input_type_desc, -1); hr = IMFSinkWriter_SetInputMediaType(writer, 0, input_type, NULL); - todo_wine ok(hr == S_OK, "SetInputMediaType returned %#lx.\n", hr); IMFMediaType_Release(input_type);
/* Get transform after SetInputMediaType. */ hr = IMFSinkWriter_GetServiceForStream(writer, 0, &GUID_NULL, &IID_IMFTransform, (void **)&transform); - todo_wine ok(hr == S_OK, "GetServiceForStream returned %#lx.\n", hr); if (hr == S_OK) IMFTransform_Release(transform);
hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 0, &guid, &transform); - todo_wine ok(hr == S_OK, "GetTransformForStream returned %#lx.\n", hr); - todo_wine ok(IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_PROCESSOR), "Unexpected guid %s.\n", debugstr_guid(&guid)); if (hr == S_OK) IMFTransform_Release(transform);
hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 1, &guid, &transform); - todo_wine ok(hr == S_OK, "GetTransformForStream returned %#lx.\n", hr); - todo_wine ok(IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_ENCODER), "Unexpected guid %s.\n", debugstr_guid(&guid)); if (hr == S_OK) IMFTransform_Release(transform); @@ -1849,7 +1843,6 @@ static void test_sink_writer_add_stream(void) ok(hr == MF_E_INVALIDSTREAMNUMBER, "SetInputMediaType returned %#lx.\n", hr);
hr = IMFSinkWriter_SetInputMediaType(writer, 0, input_type, NULL); - todo_wine ok(hr == S_OK, "SetInputMediaType returned %#lx.\n", hr);
IMFMediaType_Release(input_type); @@ -1909,7 +1902,6 @@ static void test_sink_writer_sample_process(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); init_media_type(input_type, video_input_type_desc, -1); hr = IMFSinkWriter_SetInputMediaType(writer, 0, input_type, NULL); - todo_wine ok(hr == S_OK, "SetInputMediaType returned %#lx.\n", hr); IMFMediaType_Release(input_type);
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index b494d2edd0c..22595a62c7e 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -211,7 +211,20 @@ static HRESULT stream_get_type(struct stream *stream, IMFMediaType **out_type)
static HRESULT transform_set_types(struct transform *transform, IMFMediaType *input_type, IMFMediaType *output_type) { - return E_NOTIMPL; + IMFMediaType *output_current_type = NULL; + HRESULT hr; + + /* Set output type on transform. */ + if (FAILED(hr = IMFTransform_SetOutputType(transform->transform, 0, output_type, 0)) + || FAILED(hr = IMFTransform_GetOutputCurrentType(transform->transform, 0, &output_current_type))) + return hr; + + /* Set input type on transform. */ + if (SUCCEEDED(hr = update_media_type(input_type, output_current_type))) + hr = IMFTransform_SetInputType(transform->transform, 0, input_type, 0); + + IMFMediaType_Release(output_current_type); + return hr; }
static HRESULT stream_enumerate_transforms(struct stream *stream, IMFMediaType *input_type, IMFMediaType *output_type,