Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v2: mfreadwrite/writer: Create output stream if it wasn't provided. mfreadwrite/writer: Create archive sink automatically when writer is created from url/bytestream. mf: Add archive sink creation exported functions.
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mf/main.c | 85 +++++++++++++++++++++++++++++++++++++ dlls/mf/mf.spec | 9 ++-- include/Makefile.in | 1 + include/mfidl.idl | 11 +++++ include/wine/mfinternal.idl | 54 +++++++++++++++++++++++ libs/mfuuid/mfuuid.c | 1 + 6 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 include/wine/mfinternal.idl
diff --git a/dlls/mf/main.c b/dlls/mf/main.c index 6b1d9293c8a..12c9f11c6b0 100644 --- a/dlls/mf/main.c +++ b/dlls/mf/main.c @@ -30,6 +30,7 @@
#include "wine/debug.h" #include "wine/list.h" +#include "wine/mfinternal.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
@@ -1383,6 +1384,9 @@ static const IMFMediaTypeHandlerVtbl simple_type_handler_vtbl = simple_type_handler_GetMajorType, };
+/******************************************************************************* + * MFCreateSimpleTypeHandler (mf.@) + */ HRESULT WINAPI MFCreateSimpleTypeHandler(IMFMediaTypeHandler **handler) { struct simple_type_handler *object; @@ -1401,6 +1405,9 @@ HRESULT WINAPI MFCreateSimpleTypeHandler(IMFMediaTypeHandler **handler) return S_OK; }
+/******************************************************************************* + * MFRequireProtectedEnvironment (mf.@) + */ HRESULT WINAPI MFRequireProtectedEnvironment(IMFPresentationDescriptor *pd) { BOOL selected, protected = FALSE; @@ -1419,3 +1426,81 @@ HRESULT WINAPI MFRequireProtectedEnvironment(IMFPresentationDescriptor *pd)
return protected ? S_OK : S_FALSE; } + +static HRESULT create_media_sink(const CLSID *clsid, IMFByteStream *stream, IMFMediaType *video_type, + IMFMediaType *audio_type, IMFMediaSink **sink) +{ + IMFSinkClassFactory *factory; + HRESULT hr; + + if (FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFSinkClassFactory, (void **)&factory))) + return hr; + + hr = IMFSinkClassFactory_CreateMediaSink(factory, stream, video_type, audio_type, sink); + IMFSinkClassFactory_Release(factory); + + return hr; +} + +/******************************************************************************* + * MFCreate3GPMediaSink (mf.@) + */ +HRESULT WINAPI MFCreate3GPMediaSink(IMFByteStream *stream, IMFMediaType *video_type, + IMFMediaType *audio_type, IMFMediaSink **sink) +{ + TRACE("%p, %p, %p, %p.\n", stream, video_type, audio_type, sink); + + return create_media_sink(&CLSID_MF3GPSinkClassFactory, stream, video_type, audio_type, sink); +} + +/******************************************************************************* + * MFCreateAC3MediaSink (mf.@) + */ +HRESULT WINAPI MFCreateAC3MediaSink(IMFByteStream *stream, IMFMediaType *audio_type, IMFMediaSink **sink) +{ + TRACE("%p, %p, %p.\n", stream, audio_type, sink); + + return create_media_sink(&CLSID_MFAC3SinkClassFactory, stream, NULL, audio_type, sink); +} + +/******************************************************************************* + * MFCreateADTSMediaSink (mf.@) + */ +HRESULT WINAPI MFCreateADTSMediaSink(IMFByteStream *stream, IMFMediaType *audio_type, IMFMediaSink **sink) +{ + TRACE("%p, %p, %p.\n", stream, audio_type, sink); + + return create_media_sink(&CLSID_MFADTSSinkClassFactory, stream, NULL, audio_type, sink); +} + +/******************************************************************************* + * MFCreateMP3MediaSink (mf.@) + */ +HRESULT WINAPI MFCreateMP3MediaSink(IMFByteStream *stream, IMFMediaSink **sink) +{ + TRACE("%p, %p.\n", stream, sink); + + return create_media_sink(&CLSID_MFMP3SinkClassFactory, stream, NULL, NULL, sink); +} + +/******************************************************************************* + * MFCreateMPEG4MediaSink (mf.@) + */ +HRESULT WINAPI MFCreateMPEG4MediaSink(IMFByteStream *stream, IMFMediaType *video_type, + IMFMediaType *audio_type, IMFMediaSink **sink) +{ + TRACE("%p, %p, %p, %p.\n", stream, video_type, audio_type, sink); + + return create_media_sink(&CLSID_MFMPEG4SinkClassFactory, stream, video_type, audio_type, sink); +} + +/******************************************************************************* + * MFCreateFMPEG4MediaSink (mf.@) + */ +HRESULT WINAPI MFCreateFMPEG4MediaSink(IMFByteStream *stream, IMFMediaType *video_type, + IMFMediaType *audio_type, IMFMediaSink **sink) +{ + TRACE("%p, %p, %p, %p.\n", stream, video_type, audio_type, sink); + + return create_media_sink(&CLSID_MFFMPEG4SinkClassFactory, stream, video_type, audio_type, sink); +} diff --git a/dlls/mf/mf.spec b/dlls/mf/mf.spec index 8f340243fc2..e207ca23a8e 100644 --- a/dlls/mf/mf.spec +++ b/dlls/mf/mf.spec @@ -7,7 +7,9 @@ @ stdcall -private DllRegisterServer() @ stdcall -private DllUnregisterServer() @ stub ExtractPropVariant -@ stub MFCreate3GPMediaSink +@ stdcall MFCreate3GPMediaSink(ptr ptr ptr ptr) +@ stdcall MFCreateAC3MediaSink(ptr ptr ptr) +@ stdcall MFCreateADTSMediaSink(ptr ptr ptr) @ stub MFCreateASFByteStreamPlugin @ stub MFCreateASFContentInfo @ stub MFCreateASFIndexer @@ -33,11 +35,12 @@ @ stub MFCreateDrmNetNDSchemePlugin @ stub MFCreateFileBlockMap @ stub MFCreateFileSchemePlugin +@ stdcall MFCreateFMPEG4MediaSink(ptr ptr ptr ptr) @ stub MFCreateHttpSchemePlugin @ stub MFCreateLPCMByteStreamPlugin @ stub MFCreateMP3ByteStreamPlugin -@ stub MFCreateMP3MediaSink -@ stub MFCreateMPEG4MediaSink +@ stdcall MFCreateMP3MediaSink(ptr ptr) +@ stdcall MFCreateMPEG4MediaSink(ptr ptr ptr ptr) @ stub MFCreateMediaProcessor @ stdcall MFCreateMediaSession(ptr ptr) @ stub MFCreateNSCByteStreamPlugin diff --git a/include/Makefile.in b/include/Makefile.in index 1a4f0cd9e6c..70134a7bcb7 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -833,6 +833,7 @@ SOURCES = \ wine/irpcss.idl \ wine/itss.idl \ wine/list.h \ + wine/mfinternal.idl \ wine/mmsystem16.h \ wine/mscvpdb.h \ wine/mssign.h \ diff --git a/include/mfidl.idl b/include/mfidl.idl index 14e2dd7ce4d..72e96d1c598 100644 --- a/include/mfidl.idl +++ b/include/mfidl.idl @@ -686,11 +686,22 @@ interface IMFSeekInfo : IUnknown }
cpp_quote("HRESULT WINAPI CreatePropertyStore(IPropertyStore **store);") +cpp_quote("HRESULT WINAPI MFCreate3GPMediaSink(IMFByteStream *stream, IMFMediaType *video_type,") +cpp_quote(" IMFMediaType *audio_type, IMFMediaSink **sink);") +cpp_quote("HRESULT WINAPI MFCreateAC3MediaSink(IMFByteStream *stream, IMFMediaType *audio_type,") +cpp_quote(" IMFMediaSink **sink);") +cpp_quote("HRESULT WINAPI MFCreateADTSMediaSink(IMFByteStream *stream, IMFMediaType *audio_type,") +cpp_quote(" IMFMediaSink **sink);") cpp_quote("HRESULT WINAPI MFCreateAudioRenderer(IMFAttributes *config, IMFMediaSink **sink);") cpp_quote("HRESULT WINAPI MFCreateAudioRendererActivate(IMFActivate **activate);") +cpp_quote("HRESULT WINAPI MFCreateFMPEG4MediaSink(IMFByteStream *stream, IMFMediaType *video_type,") +cpp_quote(" IMFMediaType *audio_type, IMFMediaSink **sink);") cpp_quote("HRESULT WINAPI MFCreateMediaSession(IMFAttributes *config, IMFMediaSession **session);") cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStream(IStream *stream, IMFByteStream **bytestream);" ) cpp_quote("HRESULT WINAPI MFCreateMFByteStreamOnStreamEx(IUnknown *stream, IMFByteStream **bytestream);") +cpp_quote("HRESULT WINAPI MFCreateMP3MediaSink(IMFByteStream *stream, IMFMediaSink **sink);") +cpp_quote("HRESULT WINAPI MFCreateMPEG4MediaSink(IMFByteStream *stream, IMFMediaType *video_type,") +cpp_quote(" IMFMediaType *audio_type, IMFMediaSink **sink);") cpp_quote("HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock);") cpp_quote("HRESULT WINAPI MFCreatePresentationDescriptor(DWORD count, IMFStreamDescriptor **descriptors,") cpp_quote(" IMFPresentationDescriptor **presentation_desc);") diff --git a/include/wine/mfinternal.idl b/include/wine/mfinternal.idl new file mode 100644 index 00000000000..9dbb5fcb47e --- /dev/null +++ b/include/wine/mfinternal.idl @@ -0,0 +1,54 @@ +/* + * Copyright 2022 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep header install +#endif + +import "unknwn.idl"; + +interface IMFByteStream; +interface IMFMediaSink; +interface IMFMediaType; + +/* Internal interface used to instantiate registered sinks. It should be compatible, + except for used method names. */ + +[ + uuid(37aa1c3b-620f-477e-bef9-ac4aa85be95d), + object, + local +] +interface IMFSinkClassFactory : IUnknown +{ + HRESULT CreateMediaSink( + [in] IMFByteStream *stream, + [in] IMFMediaType *video_type, + [in] IMFMediaType *audio_type, + [out] IMFMediaSink **sink + ); +} + +cpp_quote("DEFINE_GUID(CLSID_MF3GPSinkClassFactory, 0xe54cdfaf, 0x2381, 0x4cad, 0xab, 0x99, 0xf3, 0x85, 0x17, 0x12, 0x7d, 0x5c);") +cpp_quote("DEFINE_GUID(CLSID_MFAC3SinkClassFactory, 0x255a6fda, 0x6f93, 0x4e8a, 0x96, 0x11, 0xde, 0xd1, 0x16, 0x9e, 0xef, 0xb4);") +cpp_quote("DEFINE_GUID(CLSID_MFADTSSinkClassFactory, 0xd7ca55ab, 0x5022, 0x4db3, 0xa5, 0x99, 0xab, 0xaf, 0xa3, 0x58, 0xe6, 0xf3);") +cpp_quote("DEFINE_GUID(CLSID_MFAVISinkClassFactory, 0xaf4b1274, 0xb78a, 0x4979, 0xae, 0xf5, 0x20, 0xe7, 0x8f, 0xee, 0x10, 0x2e);") +cpp_quote("DEFINE_GUID(CLSID_MFFMPEG4SinkClassFactory, 0x60f9f51e, 0x4613, 0x4b35, 0xae, 0x88, 0x33, 0x25, 0x42, 0xb5, 0x67, 0xb8);") +cpp_quote("DEFINE_GUID(CLSID_MFMP3SinkClassFactory, 0x11275a82, 0x5e5a, 0x47fd, 0xa0, 0x1c, 0x36, 0x83, 0xc1, 0x2f, 0xb1, 0x96);") +cpp_quote("DEFINE_GUID(CLSID_MFMPEG4SinkClassFactory, 0xa22c4fc7, 0x6e91, 0x4e1d, 0x89, 0xe9, 0x53, 0xb2, 0x66, 0x7b, 0x72, 0xba);") +cpp_quote("DEFINE_GUID(CLSID_MFWAVESinkClassFactory, 0x36f99745, 0x23c9, 0x4c9c, 0x8d, 0xd5, 0xcc, 0x31, 0xce, 0x96, 0x43, 0x90);") diff --git a/libs/mfuuid/mfuuid.c b/libs/mfuuid/mfuuid.c index ce50eedb0a0..d7fdcf18a20 100644 --- a/libs/mfuuid/mfuuid.c +++ b/libs/mfuuid/mfuuid.c @@ -32,6 +32,7 @@ #include "mfidl.h" #include "mfreadwrite.h" #include "mfmediaengine.h" +#include "wine/mfinternal.h"
DEFINE_GUID(MF_SCRUBBING_SERVICE, 0xdd0ac3d8,0x40e3,0x4128,0xac,0x48,0xc0,0xad,0xd0,0x67,0xb7,0x14); DEFINE_GUID(CLSID_FileSchemePlugin, 0x477ec299,0x1421,0x4bdd,0x97,0x1f,0x7c,0xcb,0x93,0x3f,0x21,0xad);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/Makefile.in | 2 +- dlls/mfreadwrite/mf_private.h | 4 +- dlls/mfreadwrite/reader.c | 6 +- dlls/mfreadwrite/writer.c | 127 ++++++++++++++++++++++++++++------ 4 files changed, 115 insertions(+), 24 deletions(-)
diff --git a/dlls/mfreadwrite/Makefile.in b/dlls/mfreadwrite/Makefile.in index 440d5ba96cd..552ba6d2638 100644 --- a/dlls/mfreadwrite/Makefile.in +++ b/dlls/mfreadwrite/Makefile.in @@ -1,6 +1,6 @@ MODULE = mfreadwrite.dll IMPORTLIB = mfreadwrite -IMPORTS = mfuuid uuid mfplat ole32 +IMPORTS = mfuuid uuid mfplat ole32 kernelbase
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/mfreadwrite/mf_private.h b/dlls/mfreadwrite/mf_private.h index 4e23ab7b3e0..7d8172a383a 100644 --- a/dlls/mfreadwrite/mf_private.h +++ b/dlls/mfreadwrite/mf_private.h @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-extern HRESULT create_sink_writer_from_stream(IMFByteStream *stream, IMFAttributes *attributes, - REFIID riid, void **out) DECLSPEC_HIDDEN; +extern HRESULT create_sink_writer_from_url(const WCHAR *url, IMFByteStream *stream, + IMFAttributes *attributes, REFIID riid, void **out) DECLSPEC_HIDDEN; extern HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attributes, REFIID riid, void **out) DECLSPEC_HIDDEN; diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c index 76348458fac..aac59deba76 100644 --- a/dlls/mfreadwrite/reader.c +++ b/dlls/mfreadwrite/reader.c @@ -2594,6 +2594,10 @@ static HRESULT WINAPI readwrite_factory_CreateInstanceFromURL(IMFReadWriteClassF { return create_source_reader_from_url(url, attributes, &IID_IMFSourceReader, out); } + else if (IsEqualGUID(clsid, &CLSID_MFSinkWriter)) + { + return create_sink_writer_from_url(url, NULL, attributes, riid, out); + }
FIXME("Unsupported %s.\n", debugstr_guid(clsid));
@@ -2621,7 +2625,7 @@ static HRESULT WINAPI readwrite_factory_CreateInstanceFromObject(IMFReadWriteCla hr = IUnknown_QueryInterface(unk, &IID_IMFMediaSink, (void **)&sink);
if (stream) - hr = create_sink_writer_from_stream(stream, attributes, riid, out); + hr = create_sink_writer_from_url(NULL, stream, attributes, riid, out); else if (sink) hr = create_sink_writer_from_sink(sink, attributes, riid, out);
diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index 1f33c0791ec..a3f77c4415b 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -22,6 +22,8 @@ #include "mfapi.h" #include "mfidl.h" #include "mfreadwrite.h" +#include "pathcch.h" +#include "wine/mfinternal.h" #include "mf_private.h"
#include "wine/debug.h" @@ -196,24 +198,6 @@ HRESULT create_sink_writer_from_sink(IMFMediaSink *sink, IMFAttributes *attribut return hr; }
-HRESULT create_sink_writer_from_stream(IMFByteStream *stream, IMFAttributes *attributes, - REFIID riid, void **out) -{ - struct sink_writer *object; - HRESULT hr; - - object = malloc(sizeof(*object)); - if (!object) - return E_OUTOFMEMORY; - - object->IMFSinkWriter_iface.lpVtbl = &sink_writer_vtbl; - object->refcount = 1; - - hr = IMFSinkWriter_QueryInterface(&object->IMFSinkWriter_iface, riid, out); - IMFSinkWriter_Release(&object->IMFSinkWriter_iface); - return hr; -} - /*********************************************************************** * MFCreateSinkWriterFromMediaSink (mfreadwrite.@) */ @@ -224,13 +208,116 @@ HRESULT WINAPI MFCreateSinkWriterFromMediaSink(IMFMediaSink *sink, IMFAttributes return create_sink_writer_from_sink(sink, attributes, &IID_IMFSinkWriter, (void **)writer); }
+static HRESULT sink_writer_get_sink_factory_class(const WCHAR *url, IMFAttributes *attributes, CLSID *clsid) +{ + static const struct extension_map + { + const WCHAR *ext; + const GUID *guid; + } ext_map[] = + { + { L".mp4", &MFTranscodeContainerType_MPEG4 }, + { L".mp3", &MFTranscodeContainerType_MP3 }, + { L".wav", &MFTranscodeContainerType_WAVE }, + { L".avi", &MFTranscodeContainerType_AVI }, + }; + static const struct + { + const GUID *container; + const CLSID *clsid; + } class_map[] = + { + { &MFTranscodeContainerType_MPEG4, &CLSID_MFMPEG4SinkClassFactory }, + { &MFTranscodeContainerType_MP3, &CLSID_MFMP3SinkClassFactory }, + { &MFTranscodeContainerType_WAVE, &CLSID_MFWAVESinkClassFactory }, + { &MFTranscodeContainerType_AVI, &CLSID_MFAVISinkClassFactory }, + }; + const WCHAR *extension; + GUID container; + unsigned int i; + + if (url) + { + if (!attributes || FAILED(IMFAttributes_GetGUID(attributes, &MF_TRANSCODE_CONTAINERTYPE, &container))) + { + const struct extension_map *map = NULL; + + if (FAILED(PathCchFindExtension(url, PATHCCH_MAX_CCH, &extension))) return E_INVALIDARG; + if (!extension || !*extension) return E_INVALIDARG; + + for (i = 0; i < ARRAY_SIZE(ext_map); ++i) + { + map = &ext_map[i]; + + if (!wcsicmp(map->ext, extension)) + break; + } + + if (!map) + { + WARN("Couldn't find container type for extension %s.\n", debugstr_w(extension)); + return E_INVALIDARG; + } + + container = *map->guid; + } + } + else + { + if (!attributes) return E_INVALIDARG; + if (FAILED(IMFAttributes_GetGUID(attributes, &MF_TRANSCODE_CONTAINERTYPE, &container))) return E_INVALIDARG; + } + + for (i = 0; i < ARRAY_SIZE(class_map); ++i) + { + if (IsEqualGUID(&container, &class_map[i].container)) + { + *clsid = *class_map[i].clsid; + return S_OK; + } + } + + WARN("Couldn't find factory class for container %s.\n", debugstr_guid(&container)); + return E_INVALIDARG; +} + +HRESULT create_sink_writer_from_url(const WCHAR *url, IMFByteStream *bytestream, IMFAttributes *attributes, + REFIID riid, void **out) +{ + IMFSinkClassFactory *factory; + IMFMediaSink *sink; + CLSID clsid; + HRESULT hr; + + if (FAILED(hr = sink_writer_get_sink_factory_class(url, attributes, &clsid))) return hr; + + if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFSinkClassFactory, (void **)&factory))) + { + WARN("Failed to create a sink factory, hr %#lx.\n", hr); + return hr; + } + + hr = IMFSinkClassFactory_CreateMediaSink(factory, bytestream, NULL, NULL, &sink); + IMFSinkClassFactory_Release(factory); + if (FAILED(hr)) + { + WARN("Failed to create a sink, hr %#lx.\n", hr); + return hr; + } + + hr = create_sink_writer_from_sink(sink, attributes, riid, out); + IMFMediaSink_Release(sink); + + return hr; +} + /*********************************************************************** * MFCreateSinkWriterFromURL (mfreadwrite.@) */ HRESULT WINAPI MFCreateSinkWriterFromURL(const WCHAR *url, IMFByteStream *bytestream, IMFAttributes *attributes, IMFSinkWriter **writer) { - FIXME("%s, %p, %p, %p.\n", debugstr_w(url), bytestream, attributes, writer); + TRACE("%s, %p, %p, %p.\n", debugstr_w(url), bytestream, attributes, writer);
- return E_NOTIMPL; + return create_sink_writer_from_url(url, bytestream, attributes, &IID_IMFSinkWriter, (void **)writer); }
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfreadwrite/tests/mfplat.c | 13 +++++++++++++ dlls/mfreadwrite/writer.c | 13 +++++++++++++ 2 files changed, 26 insertions(+)
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c index c36e1a7e04d..95f615767d5 100644 --- a/dlls/mfreadwrite/tests/mfplat.c +++ b/dlls/mfreadwrite/tests/mfplat.c @@ -1291,6 +1291,18 @@ done: DestroyWindow(window); }
+static void test_sink_writer(void) +{ + IMFSinkWriter *writer; + HRESULT hr; + + hr = MFCreateSinkWriterFromURL(NULL, NULL, NULL, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = MFCreateSinkWriterFromURL(NULL, NULL, NULL, &writer); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); +} + START_TEST(mfplat) { HRESULT hr; @@ -1304,6 +1316,7 @@ START_TEST(mfplat) test_source_reader(); test_source_reader_from_media_source(); test_reader_d3d9(); + test_sink_writer();
hr = MFShutdown(); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); diff --git a/dlls/mfreadwrite/writer.c b/dlls/mfreadwrite/writer.c index a3f77c4415b..f4bd08b8cda 100644 --- a/dlls/mfreadwrite/writer.c +++ b/dlls/mfreadwrite/writer.c @@ -289,6 +289,9 @@ HRESULT create_sink_writer_from_url(const WCHAR *url, IMFByteStream *bytestream, CLSID clsid; HRESULT hr;
+ if (!url && !bytestream) + return E_INVALIDARG; + if (FAILED(hr = sink_writer_get_sink_factory_class(url, attributes, &clsid))) return hr;
if (FAILED(hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IMFSinkClassFactory, (void **)&factory))) @@ -297,8 +300,18 @@ HRESULT create_sink_writer_from_url(const WCHAR *url, IMFByteStream *bytestream, return hr; }
+ if (bytestream) + IMFByteStream_AddRef(bytestream); + else if (FAILED(hr = MFCreateFile(MF_ACCESSMODE_WRITE, MF_OPENMODE_DELETE_IF_EXIST, 0, url, &bytestream))) + { + WARN("Failed to create output file stream, hr %#lx.\n", hr); + IMFSinkClassFactory_Release(factory); + return hr; + } + hr = IMFSinkClassFactory_CreateMediaSink(factory, bytestream, NULL, NULL, &sink); IMFSinkClassFactory_Release(factory); + IMFByteStream_Release(bytestream); if (FAILED(hr)) { WARN("Failed to create a sink, hr %#lx.\n", hr);