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;
Nikolay Sivov (@nsivov) commented about dlls/mfreadwrite/writer.c:
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 */
};
If it's always encoder, with optional converter, it's more readable to just call it that. Like "struct transform encoder, converter;" This way you don't need to remember which one is which.
Nikolay Sivov (@nsivov) commented about dlls/mfreadwrite/writer.c:
- 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;
+}
This should be a fixme I guess.
Nikolay Sivov (@nsivov) commented about dlls/mfreadwrite/writer.c:
|| 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);
- }
Do we need to try? We know that on mismatching subtypes we need an encoder. Are there any other cases?
On Fri Mar 21 10:15:56 2025 +0000, Nikolay Sivov wrote:
Do we need to try? We know that on mismatching subtypes we need an encoder. Are there any other cases?
Basically, I do this because we are already doing this in reader, see [reader.c](https://gitlab.winehq.org/wine/wine/-/blob/master/dlls/mfreadwrite/reader.c?...).
But like you said, the only situation we need an encoder is that the input type is uncompressed and stream type is compressed, it should be ok to check that. Do you think we should check the type rather than try creating it? Maybe with something like this:
``` uncompressed_types = {...};
bool is_type_compressed(GUID *subtype) { for (i : uncompressed_types) if is equal guid, return false; return true; }
sink_writer_SetInputMediaType { use_encoder = !input_compressed && stream_compressed; ... if (!(flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)) hr = stream_create_transforms(stream, type, stream_type, use_encoder); } ``` I don't find any api that can check if a subtype is compressed or not.
On Sat Mar 22 04:38:27 2025 +0000, Ziqing Hui wrote:
Basically, I do this because we are already doing this in reader, see [reader.c](https://gitlab.winehq.org/wine/wine/-/blob/master/dlls/mfreadwrite/reader.c?...). But like you said, the only situation we need an encoder is that the input type is uncompressed and stream type is compressed, it should be ok to check that. Do you think we should check the type rather than try creating it? Maybe with something like this:
uncompressed_types = {...}; bool is_type_compressed(GUID *subtype) { for (i : uncompressed_types) if is equal guid, return false; return true; } sink_writer_SetInputMediaType { use_encoder = !input_compressed && stream_compressed; ... if (!(flags & MF_MEDIATYPE_EQUAL_FORMAT_DATA)) hr = stream_create_transforms(stream, type, stream_type, use_encoder); }
I don't find any api that can check if a subtype is compressed or not.
When I was implementing the code that check whether a type is compressed or not, I changed my mind. In our situation here, the best way to check if a subtype is compressed is to use MFEnumEx to enumrate encoder for it, so try calling `stream_create_transforms()` is the correct way I think, because it will enum encoder for it first. Having a type list, and checking the list to decide if a type is compressed is urly.