Based on top of tests MR !7125.
-- v2: mfreadwrite: Implement IMFSinkWriterEx. mfreadwrite: Implement create_transform. mfreadwrite: Implement sink_writer_SetInputMediaType. mfreadwrite: Rename update_media_type_from_upstream and make it non-static. mfreadwrite: Use a transform array for writer. mfreadwrite/tests: Test sample processing for mp4 sink writer. mfreadwrite/tests: Test getting transforms from mp4 sink writer. mfreadwrite/tests: Test AddStream and SetInputMediaType for mp4 sink writer. mfreadwrite/tests: Remove trivial if.
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/tests/mfplat.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index b6981479a1b..21758cc5aae 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1612,23 +1612,19 @@ static void test_sink_writer_mp4(void)
hr = MFCreateSinkWriterFromURL(NULL, stream, attr, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - IMFSinkWriter_Release(writer); + IMFSinkWriter_Release(writer);
hr = MFCreateSinkWriterFromURL(tmp_file, NULL, NULL, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - IMFSinkWriter_Release(writer); + IMFSinkWriter_Release(writer);
hr = MFCreateSinkWriterFromURL(tmp_file, NULL, attr, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - IMFSinkWriter_Release(writer); + IMFSinkWriter_Release(writer);
hr = MFCreateSinkWriterFromURL(tmp_file, stream, NULL, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - IMFSinkWriter_Release(writer); + IMFSinkWriter_Release(writer);
hr = MFCreateSinkWriterFromURL(tmp_file, stream, attr, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/tests/mfplat.c | 78 ++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 21758cc5aae..70c058eb29f 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1582,11 +1582,31 @@ static void test_sink_writer_create(void)
static void test_sink_writer_mp4(void) { + static const struct attribute_desc video_stream_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_H264), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), + ATTR_UINT32(MF_MT_AVG_BITRATE, 193540), + ATTR_UINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive), + {0}, + }; + static const struct attribute_desc video_input_type_desc[] = + { + ATTR_GUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), + ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), + ATTR_RATIO(MF_MT_FRAME_SIZE, 96, 96), + ATTR_RATIO(MF_MT_FRAME_RATE, 30000, 1001), + {0}, + }; + IMFMediaType *stream_type, *input_type; WCHAR tmp_file[MAX_PATH]; IMFSinkWriter *writer; IMFByteStream *stream; IMFAttributes *attr; IMFMediaSink *sink; + DWORD index; HRESULT hr;
GetTempPathW(ARRAY_SIZE(tmp_file), tmp_file); @@ -1598,6 +1618,10 @@ static void test_sink_writer_mp4(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = MFCreateTempFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, &stream); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMediaType(&stream_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = MFCreateMediaType(&input_type); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/* Test MFCreateSinkWriterFromURL. */ writer = (void *)0xdeadbeef; @@ -1629,7 +1653,43 @@ static void test_sink_writer_mp4(void) hr = MFCreateSinkWriterFromURL(tmp_file, stream, attr, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- /* Test GetServiceForStream. */ + /* BeginWriting fails before calling AddStream. */ + hr = IMFSinkWriter_BeginWriting(writer); + ok(hr == MF_E_INVALIDREQUEST, "BeginWriting returned %#lx.\n", hr); + + /* Test AddStream. */ + init_media_type(stream_type, video_stream_type_desc, -1); + + hr = IMFSinkWriter_AddStream(writer, NULL, NULL); + ok(hr == E_INVALIDARG, "AddStream returned %#lx.\n", hr); + hr = IMFSinkWriter_AddStream(writer, stream_type, NULL); + ok(hr == E_POINTER, "AddStream returned %#lx.\n", hr); + + index = 0xdeadbeef; + hr = IMFSinkWriter_AddStream(writer, NULL, &index); + ok(hr == E_INVALIDARG, "AddStream returned %#lx.\n", hr); + ok(index == 0xdeadbeef, "Unexpected index %lu.\n", index); + + hr = IMFSinkWriter_AddStream(writer, stream_type, &index); + ok(hr == S_OK, "AddStream returned %#lx.\n", hr); + ok(index == 0, "Unexpected index %lu.\n", index); + + /* Test SetInputMediaType. */ + 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); + todo_wine + ok(hr == S_OK, "SetInputMediaType returned %#lx.\n", hr); + + /* Test GetServiceForStream before calling BeginWriting. */ sink = (void *)0xdeadbeef; hr = IMFSinkWriter_GetServiceForStream(writer, MF_SINK_WRITER_MEDIASINK, &GUID_NULL, &IID_IMFMediaSink, (void **)&sink); @@ -1638,8 +1698,24 @@ static void test_sink_writer_mp4(void) todo_wine ok(!sink, "Unexpected pointer %p.\n", sink);
+ /* Test BeginWriting. */ + hr = IMFSinkWriter_BeginWriting(writer); + todo_wine + ok(hr == S_OK, "BeginWriting returned %#lx.\n", hr); + hr = IMFSinkWriter_BeginWriting(writer); + todo_wine + ok(hr == MF_E_INVALIDREQUEST, "BeginWriting returned %#lx.\n", hr); + + /* Test GetServiceForStream after calling BeginWriting. */ + hr = IMFSinkWriter_GetServiceForStream(writer, MF_SINK_WRITER_MEDIASINK, + &GUID_NULL, &IID_IMFMediaSink, (void **)&sink); + ok(hr == S_OK, "GetServiceForStream returned %#lx.\n", hr); + IMFMediaSink_Release(sink); + DeleteFileW(tmp_file); IMFSinkWriter_Release(writer); + IMFMediaType_Release(input_type); + IMFMediaType_Release(stream_type); IMFByteStream_Release(stream); IMFAttributes_Release(attr); }
From: Ziqing Hui zhui@codeweavers.com
The tests indicate that mp4 writer has 2 transforms: a processor and a encoder. --- dlls/mfreadwrite/tests/mfplat.c | 49 +++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 70c058eb29f..6e49976aa4c 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1601,13 +1601,16 @@ static void test_sink_writer_mp4(void) {0}, }; IMFMediaType *stream_type, *input_type; + IMFSinkWriterEx *writer_ex = NULL; WCHAR tmp_file[MAX_PATH]; + IMFTransform *transform; IMFSinkWriter *writer; IMFByteStream *stream; IMFAttributes *attr; IMFMediaSink *sink; DWORD index; HRESULT hr; + GUID guid;
GetTempPathW(ARRAY_SIZE(tmp_file), tmp_file); wcscat(tmp_file, L"tmp.mp4"); @@ -1653,6 +1656,10 @@ static void test_sink_writer_mp4(void) hr = MFCreateSinkWriterFromURL(tmp_file, stream, attr, &writer); 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); + /* BeginWriting fails before calling AddStream. */ hr = IMFSinkWriter_BeginWriting(writer); ok(hr == MF_E_INVALIDREQUEST, "BeginWriting returned %#lx.\n", hr); @@ -1674,6 +1681,19 @@ static void test_sink_writer_mp4(void) ok(hr == S_OK, "AddStream returned %#lx.\n", hr); ok(index == 0, "Unexpected index %lu.\n", index);
+ /* Get transform before SetInputMediaType. */ + transform = (void *)0xdeadbeef; + hr = IMFSinkWriter_GetServiceForStream(writer, 0, &GUID_NULL, &IID_IMFTransform, (void **)&transform); + todo_wine + ok(hr == MF_E_UNSUPPORTED_SERVICE, "GetServiceForStream returned %#lx.\n", hr); + ok(!transform, "Unexpected pointer %p.\n", transform); + + if (writer_ex) + { + hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 0, &guid, &transform); + ok(hr == MF_E_INVALIDINDEX, "GetTransformForStream returned %#lx.\n", hr); + } + /* Test SetInputMediaType. */ init_media_type(input_type, video_input_type_desc, -1); hr = IMFSinkWriter_SetInputMediaType(writer, 0xdeadbeef, NULL, NULL); @@ -1689,7 +1709,30 @@ static void test_sink_writer_mp4(void) todo_wine ok(hr == S_OK, "SetInputMediaType returned %#lx.\n", hr);
- /* Test GetServiceForStream before calling BeginWriting. */ + /* 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); + + if (writer_ex) + { + hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 0, &guid, &transform); + ok(hr == S_OK, "GetTransformForStream returned %#lx.\n", hr); + ok(IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_PROCESSOR), "Unexpected guid %s.\n", debugstr_guid(&guid)); + IMFTransform_Release(transform); + + hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 1, &guid, &transform); + ok(hr == S_OK, "GetTransformForStream returned %#lx.\n", hr); + ok(IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_ENCODER), "Unexpected guid %s.\n", debugstr_guid(&guid)); + IMFTransform_Release(transform); + + hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 2, &guid, &transform); + ok(hr == MF_E_INVALIDINDEX, "GetTransformForStream returned %#lx.\n", hr); + } + + /* Get media sink before BeginWriting. */ sink = (void *)0xdeadbeef; hr = IMFSinkWriter_GetServiceForStream(writer, MF_SINK_WRITER_MEDIASINK, &GUID_NULL, &IID_IMFMediaSink, (void **)&sink); @@ -1706,12 +1749,14 @@ static void test_sink_writer_mp4(void) todo_wine ok(hr == MF_E_INVALIDREQUEST, "BeginWriting returned %#lx.\n", hr);
- /* Test GetServiceForStream after calling BeginWriting. */ + /* Get media sink after BeginWriting. */ hr = IMFSinkWriter_GetServiceForStream(writer, MF_SINK_WRITER_MEDIASINK, &GUID_NULL, &IID_IMFMediaSink, (void **)&sink); ok(hr == S_OK, "GetServiceForStream returned %#lx.\n", hr); IMFMediaSink_Release(sink);
+ if (writer_ex) + IMFSinkWriterEx_Release(writer_ex); DeleteFileW(tmp_file); IMFSinkWriter_Release(writer); IMFMediaType_Release(input_type);
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/tests/mfplat.c | 72 ++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 5 deletions(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 6e49976aa4c..ad5506e8dd5 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -162,6 +162,37 @@ static void init_attributes_(const char *file, int line, IMFAttributes *attribut } }
+static IMFSample *create_sample(const BYTE *data, DWORD size) +{ + IMFMediaBuffer *media_buffer; + IMFSample *sample; + BYTE *buffer; + DWORD length; + HRESULT hr; + ULONG ret; + + hr = MFCreateSample(&sample); + ok(hr == S_OK, "MFCreateSample returned %#lx\n", hr); + hr = MFCreateMemoryBuffer(size, &media_buffer); + ok(hr == S_OK, "MFCreateMemoryBuffer returned %#lx\n", hr); + + hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &length); + ok(hr == S_OK, "Lock returned %#lx\n", hr); + ok(length == 0, "Unexpected length %lu\n", length); + memcpy(buffer, data, size); + hr = IMFMediaBuffer_Unlock(media_buffer); + ok(hr == S_OK, "Unlock returned %#lx\n", hr); + + hr = IMFMediaBuffer_SetCurrentLength(media_buffer, size); + ok(hr == S_OK, "SetCurrentLength returned %#lx\n", hr); + hr = IMFSample_AddBuffer(sample, media_buffer); + ok(hr == S_OK, "AddBuffer returned %#lx\n", hr); + ret = IMFMediaBuffer_Release(media_buffer); + ok(ret == 1, "Release returned %lu\n", ret); + + return sample; +} + static ULONG get_refcount(void *iface) { IUnknown *unknown = iface; @@ -1602,13 +1633,15 @@ static void test_sink_writer_mp4(void) }; IMFMediaType *stream_type, *input_type; IMFSinkWriterEx *writer_ex = NULL; + DWORD rgb32_data[96 * 96]; WCHAR tmp_file[MAX_PATH]; IMFTransform *transform; IMFSinkWriter *writer; IMFByteStream *stream; + DWORD index, i, size; IMFAttributes *attr; IMFMediaSink *sink; - DWORD index; + HANDLE file; HRESULT hr; GUID guid;
@@ -1641,10 +1674,6 @@ static void test_sink_writer_mp4(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFSinkWriter_Release(writer);
- hr = MFCreateSinkWriterFromURL(tmp_file, NULL, NULL, &writer); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - IMFSinkWriter_Release(writer); - hr = MFCreateSinkWriterFromURL(tmp_file, NULL, attr, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); IMFSinkWriter_Release(writer); @@ -1655,6 +1684,10 @@ static void test_sink_writer_mp4(void)
hr = MFCreateSinkWriterFromURL(tmp_file, stream, attr, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IMFSinkWriter_Release(writer); + + hr = MFCreateSinkWriterFromURL(tmp_file, NULL, NULL, &writer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IMFSinkWriter_QueryInterface(writer, &IID_IMFSinkWriterEx, (void **)&writer_ex); todo_wine @@ -1755,6 +1788,35 @@ static void test_sink_writer_mp4(void) ok(hr == S_OK, "GetServiceForStream returned %#lx.\n", hr); IMFMediaSink_Release(sink);
+ /* WriteSample. */ + for (i = 0; i < ARRAY_SIZE(rgb32_data); ++i) + rgb32_data[i] = 0x0000ff00; + for (i = 0; i < 30; ++i) + { + IMFSample *sample = create_sample((const BYTE *)rgb32_data, sizeof(rgb32_data)); + hr = IMFSample_SetSampleTime(sample, 333333 * i); + ok(hr == S_OK, "SetSampleTime returned %#lx.\n", hr); + hr = IMFSample_SetSampleDuration(sample, 333333); + ok(hr == S_OK, "SetSampleDuration returned %#lx.\n", hr); + hr = IMFSinkWriter_WriteSample(writer, 0, sample); + todo_wine + ok(hr == S_OK, "WriteSample returned %#lx.\n", hr); + IMFSample_Release(sample); + } + + /* Finalize. */ + hr = IMFSinkWriter_Finalize(writer); + todo_wine + ok(hr == S_OK, "Finalize returned %#lx.\n", hr); + + /* Check the output file. */ + file = CreateFileW(tmp_file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + todo_wine + ok(file != INVALID_HANDLE_VALUE, "CreateFileW failed.\n"); + size = GetFileSize(file, NULL); + todo_wine + ok(size != INVALID_FILE_SIZE && size > 0x400, "Unexpected file size %#lx.\n", size); + if (writer_ex) IMFSinkWriterEx_Release(writer_ex); DeleteFileW(tmp_file);
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 | 42 +++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 11 deletions(-)
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index c708664d2fc..5a03766b347 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,15 @@ 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) { list_remove(&item->entry); @@ -233,8 +248,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); @@ -308,7 +322,6 @@ static HRESULT WINAPI sink_writer_SetInputMediaType(IMFSinkWriter *iface, DWORD IMFAttributes *parameters) { FIXME("%p, %lu, %p, %p.\n", iface, index, type, parameters); - return E_NOTIMPL; }
@@ -357,8 +370,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)) @@ -466,8 +481,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); } @@ -738,8 +755,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
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
We'll implement create_transform later. --- dlls/mfreadwrite/tests/mfplat.c | 3 -- dlls/mfreadwrite/writer.c | 61 ++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 11 deletions(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index ad5506e8dd5..fcc3ce70702 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1730,13 +1730,10 @@ static void test_sink_writer_mp4(void) /* Test SetInputMediaType. */ 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); todo_wine diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 5a03766b347..e0031c3ec28 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -181,6 +181,19 @@ static void stream_release_transforms(struct stream *stream) memset(stream->transforms, 0, sizeof(stream->transforms)); }
+static HRESULT create_transform(IMFMediaType *input_type, IMFMediaType *output_type, BOOL use_encoder, + struct transform *out) +{ + 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); @@ -321,8 +334,46 @@ static HRESULT WINAPI sink_writer_AddStream(IMFSinkWriter *iface, IMFMediaType * static HRESULT WINAPI sink_writer_SetInputMediaType(IMFSinkWriter *iface, DWORD index, IMFMediaType *type, IMFAttributes *parameters) { - FIXME("%p, %lu, %p, %p.\n", iface, index, type, parameters); - return E_NOTIMPL; + struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + IMFMediaTypeHandler *type_handler = NULL; + struct transform transforms[2] = {}; + IMFMediaType *stream_type = NULL; + struct stream *stream; + HRESULT hr; + + 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))) + { + LeaveCriticalSection(&writer->cs); + return MF_E_INVALIDSTREAMNUMBER; + } + + /* Get stream type from stream sink. */ + if (SUCCEEDED(hr = IMFStreamSink_GetMediaTypeHandler(stream->stream_sink, &type_handler)) + && SUCCEEDED((hr = IMFMediaTypeHandler_GetCurrentMediaType(type_handler, &stream_type)))) + { + /* Create transforms for encoding. + * Try converter first, then try again with encoder. */ + if (SUCCEEDED(hr = create_transform(type, stream_type, FALSE, transforms)) + || SUCCEEDED(hr = create_transform(type, stream_type, TRUE, transforms))) + { + stream_release_transforms(stream); + stream->transforms[0] = transforms[0]; + stream->transforms[1] = transforms[1]; + } + + IMFMediaType_Release(stream_type); + IMFMediaTypeHandler_Release(type_handler); + } + + LeaveCriticalSection(&writer->cs); + return hr; }
static HRESULT sink_writer_set_presentation_clock(struct sink_writer *writer) @@ -387,12 +438,6 @@ 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 sink_writer_get_buffer_length(IMFSample *sample, LONGLONG *timestamp, DWORD *length) { IMFMediaBuffer *buffer;
From: Ziqing Hui zhui@codeweavers.com
--- dlls/mfreadwrite/tests/mfplat.c | 2 - dlls/mfreadwrite/writer.c | 124 +++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 3 deletions(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index fcc3ce70702..3174a08e3d4 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1736,12 +1736,10 @@ static void test_sink_writer_mp4(void) hr = IMFSinkWriter_SetInputMediaType(writer, 0xdeadbeef, input_type, NULL); 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);
/* 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); diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index e0031c3ec28..2ec7d5d99e3 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -181,10 +181,132 @@ static void stream_release_transforms(struct stream *stream) memset(stream->transforms, 0, sizeof(stream->transforms)); }
+static HRESULT enum_transforms(IMFMediaType *input_type, IMFMediaType *output_type, BOOL use_encoder, + IMFActivate ***activates, UINT32 *count) +{ + MFT_REGISTER_TYPE_INFO input_type_info, output_type_info; + GUID category; + HRESULT hr; + + /* Get type infos. */ + if (input_type) + { + 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. */ + *count = 0; + if (FAILED(hr = MFTEnumEx(category, 0, (input_type ? NULL : &input_type_info), &output_type_info, + activates, count))) + return hr; + if (!*count) + return MF_E_TOPO_CODEC_NOT_FOUND; + + return hr; +} + +static HRESULT create_transform_from_activate(IMFActivate *activate, + IMFMediaType *input_type, IMFMediaType *output_type, struct transform *out) +{ + IMFMediaType *output_current_type = NULL; + struct transform transform; + HRESULT hr; + + /* Get transform category. */ + if (FAILED(hr = IMFActivate_GetGUID(activate, &MF_TRANSFORM_CATEGORY_Attribute, &transform.category))) + return hr; + + /* Create transform. */ + if (FAILED(hr = IMFActivate_ActivateObject(activate, &IID_IMFTransform, (void **)&transform.transform))) + return 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))) + { + IMFTransform_Release(transform.transform); + return hr; + } + + /* Set input type on transform. */ + if (input_type) + { + if (FAILED(hr = update_media_type(input_type, output_current_type)) + || FAILED(hr = IMFTransform_SetInputType(transform.transform, 0, input_type, 0))) + { + IMFMediaType_Release(output_current_type); + IMFTransform_Release(transform.transform); + return hr; + } + } + + IMFMediaType_Release(output_current_type); + + *out = transform; + TRACE("Created transform %p.\n", out->transform); + + return S_OK; +} + static HRESULT create_transform(IMFMediaType *input_type, IMFMediaType *output_type, BOOL use_encoder, struct transform *out) { - return E_NOTIMPL; + struct transform transform = {}, converter = {}; + IMFMediaType *encoder_input_type; + IMFActivate **activates; + UINT32 count = 0, i; + HRESULT hr; + + if (FAILED(hr = enum_transforms(input_type, output_type, use_encoder, &activates, &count))) + return hr; + + for (i = 0; i < count; i++) + { + if (SUCCEEDED(hr = create_transform_from_activate(activates[i], input_type, output_type, &transform))) + { + TRACE("Create %s transform %p.", use_encoder ? "encoder" : "converter", transform.transform); + *out = transform; + break; + } + + /* Failed to use a single encoder, try using an encoder and a converter. */ + if (use_encoder && SUCCEEDED(hr = create_transform_from_activate(activates[i], NULL, output_type, &transform))) + { + if (SUCCEEDED(hr = IMFTransform_GetInputAvailableType(transform.transform, 0, 0, &encoder_input_type))) + { + hr = create_transform(input_type, encoder_input_type, FALSE, &converter); + IMFMediaType_Release(encoder_input_type); + if (SUCCEEDED(hr)) + { + TRACE("Created converter transform %p, encoder transform %p.", + converter.transform, transform.transform); + out[0] = converter; + out[1] = transform; + break; + } + } + 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/tests/mfplat.c | 34 ++++------ dlls/mfreadwrite/writer.c | 116 +++++++++++++++++++++----------- 2 files changed, 90 insertions(+), 60 deletions(-)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index 3174a08e3d4..e97b30705a3 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1690,7 +1690,6 @@ static void test_sink_writer_mp4(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);
/* BeginWriting fails before calling AddStream. */ @@ -1721,11 +1720,8 @@ static void test_sink_writer_mp4(void) ok(hr == MF_E_UNSUPPORTED_SERVICE, "GetServiceForStream returned %#lx.\n", hr); ok(!transform, "Unexpected pointer %p.\n", transform);
- if (writer_ex) - { - hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 0, &guid, &transform); - ok(hr == MF_E_INVALIDINDEX, "GetTransformForStream returned %#lx.\n", hr); - } + hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 0, &guid, &transform); + ok(hr == MF_E_INVALIDINDEX, "GetTransformForStream returned %#lx.\n", hr);
/* Test SetInputMediaType. */ init_media_type(input_type, video_input_type_desc, -1); @@ -1741,24 +1737,20 @@ static void test_sink_writer_mp4(void) /* Get transform after SetInputMediaType. */ hr = IMFSinkWriter_GetServiceForStream(writer, 0, &GUID_NULL, &IID_IMFTransform, (void **)&transform); ok(hr == S_OK, "GetServiceForStream returned %#lx.\n", hr); - if (hr == S_OK) - IMFTransform_Release(transform); + IMFTransform_Release(transform);
- if (writer_ex) - { - hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 0, &guid, &transform); - ok(hr == S_OK, "GetTransformForStream returned %#lx.\n", hr); - ok(IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_PROCESSOR), "Unexpected guid %s.\n", debugstr_guid(&guid)); - IMFTransform_Release(transform); + hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 0, &guid, &transform); + ok(hr == S_OK, "GetTransformForStream returned %#lx.\n", hr); + ok(IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_PROCESSOR), "Unexpected guid %s.\n", debugstr_guid(&guid)); + IMFTransform_Release(transform);
- hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 1, &guid, &transform); - ok(hr == S_OK, "GetTransformForStream returned %#lx.\n", hr); - ok(IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_ENCODER), "Unexpected guid %s.\n", debugstr_guid(&guid)); - IMFTransform_Release(transform); + hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 1, &guid, &transform); + ok(hr == S_OK, "GetTransformForStream returned %#lx.\n", hr); + ok(IsEqualGUID(&guid, &MFT_CATEGORY_VIDEO_ENCODER), "Unexpected guid %s.\n", debugstr_guid(&guid)); + IMFTransform_Release(transform);
- hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 2, &guid, &transform); - ok(hr == MF_E_INVALIDINDEX, "GetTransformForStream returned %#lx.\n", hr); - } + hr = IMFSinkWriterEx_GetTransformForStream(writer_ex, 0, 2, &guid, &transform); + ok(hr == MF_E_INVALIDINDEX, "GetTransformForStream returned %#lx.\n", hr);
/* Get media sink before BeginWriting. */ sink = (void *)0xdeadbeef; diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 2ec7d5d99e3..c05fe4a9cbc 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;
@@ -94,9 +94,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) @@ -324,15 +324,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; }
@@ -341,9 +342,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); @@ -361,9 +362,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;
@@ -421,9 +422,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; @@ -453,10 +454,10 @@ 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) { - struct sink_writer *writer = impl_from_IMFSinkWriter(iface); + struct sink_writer *writer = impl_from_IMFSinkWriterEx(iface); IMFMediaTypeHandler *type_handler = NULL; struct transform transforms[2] = {}; IMFMediaType *stream_type = NULL; @@ -517,9 +518,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;
@@ -737,9 +738,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; @@ -776,9 +777,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)); @@ -795,9 +796,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;
@@ -819,9 +820,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;
@@ -850,9 +851,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;
@@ -881,7 +882,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);
@@ -907,10 +908,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;
@@ -938,9 +939,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;
@@ -968,7 +969,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; + + 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, @@ -984,6 +1021,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, @@ -1005,13 +1043,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, @@ -1155,7 +1193,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; @@ -1171,12 +1209,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; }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=150990
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
mfreadwrite: mfplat.c:1693: Test failed: QueryInterface returned 0x80004002. 0600:mfplat: unhandled exception c0000005 at 010765FC
=== w7u_adm (32 bit report) ===
mfreadwrite: mfplat.c:1693: Test failed: QueryInterface returned 0x80004002. 0878:mfplat: unhandled exception c0000005 at 000C65FC
=== w7u_el (32 bit report) ===
mfreadwrite: mfplat.c:1693: Test failed: QueryInterface returned 0x80004002. 0a98:mfplat: unhandled exception c0000005 at 009065FC
=== w7pro64 (64 bit report) ===
mfreadwrite: mfplat.c:1693: Test failed: QueryInterface returned 0x80004002. 08a4:mfplat: unhandled exception c0000005 at 0000000000C26246
It's is ready now.
This MR only contains transforms creatation, but doesn't use it. This MR is too big, so I'm planning to implement the transforms sample processing later in a future MR.