Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
Notes: Supersedes: 193344-193350
dlls/wmphoto/Makefile.in | 1 + dlls/wmphoto/main.c | 97 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 3 deletions(-)
diff --git a/dlls/wmphoto/Makefile.in b/dlls/wmphoto/Makefile.in index 24e1f49496a..83462bd4c2f 100644 --- a/dlls/wmphoto/Makefile.in +++ b/dlls/wmphoto/Makefile.in @@ -1,4 +1,5 @@ MODULE = wmphoto.dll +IMPORTS = windowscodecs uuid kernelbase
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/wmphoto/main.c b/dlls/wmphoto/main.c index d3a926e7704..efb408e94cb 100644 --- a/dlls/wmphoto/main.c +++ b/dlls/wmphoto/main.c @@ -1,5 +1,6 @@ /* * Copyright 2017 Vincent Povirk for CodeWeavers + * Copyright 2020 Rémi Bernon for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,16 +18,96 @@ */
#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <setjmp.h> + +#define COBJMACROS
#include "windef.h" #include "winbase.h" #include "objbase.h" #include "rpcproxy.h" +#include "wincodecsdk.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+static HRESULT wmp_decoder_create(IUnknown *outer, IUnknown **out) +{ + FIXME("outer %p, out %p, stub!\n", outer, out); + return E_NOTIMPL; +} + +struct class_factory +{ + IClassFactory IClassFactory_iface; + HRESULT (*create_instance)(IUnknown *outer, IUnknown **out); +}; + +static inline struct class_factory *impl_from_IClassFactory(IClassFactory *iface) +{ + return CONTAINING_RECORD(iface, struct class_factory, IClassFactory_iface); +} + +static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IClassFactory)) + { + *out = iface; + IClassFactory_AddRef(iface); + return S_OK; + } + + *out = NULL; + FIXME("%s not implemented.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI class_factory_AddRef(IClassFactory *iface) { return 2; } + +static ULONG WINAPI class_factory_Release(IClassFactory *iface) { return 1; } + +static HRESULT WINAPI class_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **out) +{ + struct class_factory *factory = impl_from_IClassFactory(iface); + IUnknown *unk; + HRESULT hr; + + TRACE("iface %p, outer %p, iid %s, out %p.\n", iface, outer, debugstr_guid(iid), out); + + if (outer && !IsEqualGUID(iid, &IID_IUnknown)) return E_NOINTERFACE; + + *out = NULL; + if (SUCCEEDED(hr = factory->create_instance(outer, &unk))) + { + hr = IUnknown_QueryInterface(unk, iid, out); + IUnknown_Release(unk); + } + + return hr; +} + +static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL lock) +{ + FIXME("iface %p, lock %d, stub!\n", iface, lock); + return S_OK; +} + +static const IClassFactoryVtbl class_factory_vtbl = +{ + class_factory_QueryInterface, + class_factory_AddRef, + class_factory_Release, + class_factory_CreateInstance, + class_factory_LockServer, +}; + +static struct class_factory wmp_decoder_cf = {{&class_factory_vtbl}, wmp_decoder_create}; + static HINSTANCE WMPHOTO_hInstance;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) @@ -49,10 +130,20 @@ HRESULT WINAPI DllCanUnloadNow(void) return S_FALSE; }
-HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppv) +HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID *out) { - FIXME("wmphoto: stub\n"); - return E_NOTIMPL; + struct class_factory *factory; + + TRACE("clsid %s, iid %s, out %p.\n", debugstr_guid(clsid), debugstr_guid(iid), out); + + if (IsEqualGUID(clsid, &CLSID_WICWmpDecoder)) factory = &wmp_decoder_cf; + else + { + FIXME("%s not implemented.\n", debugstr_guid(clsid)); + return CLASS_E_CLASSNOTAVAILABLE; + } + + return IClassFactory_QueryInterface(&factory->IClassFactory_iface, iid, out); }
HRESULT WINAPI DllRegisterServer(void)
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windowscodecs/tests/wmpformat.c | 15 ++- dlls/wmphoto/Makefile.in | 1 + dlls/wmphoto/main.c | 186 ++++++++++++++++++++++++++- 3 files changed, 196 insertions(+), 6 deletions(-)
diff --git a/dlls/windowscodecs/tests/wmpformat.c b/dlls/windowscodecs/tests/wmpformat.c index 2e2809701f6..12bc1275919 100644 --- a/dlls/windowscodecs/tests/wmpformat.c +++ b/dlls/windowscodecs/tests/wmpformat.c @@ -89,7 +89,7 @@ static void test_decode(void) &IID_IWICBitmapDecoder, (void **)&decoder); if (FAILED(hr)) { - todo_wine win_skip("WmpDecoder isn't available, skipping test\n"); + win_skip("WmpDecoder isn't available, skipping test\n"); return; }
@@ -119,8 +119,8 @@ static void test_decode(void) "unexpected container format\n");
hr = IWICBitmapDecoder_GetFrameCount(decoder, &count); - ok(SUCCEEDED(hr), "GetFrameCount failed, hr=%x\n", hr); - ok(count == 1, "unexpected count %u\n", count); + todo_wine ok(SUCCEEDED(hr), "GetFrameCount failed, hr=%x\n", hr); + todo_wine ok(count == 1, "unexpected count %u\n", count);
hr = IWICBitmapDecoder_GetFrame(decoder, 0, NULL); ok(hr == E_INVALIDARG, "GetFrame(NULL) returned hr=%x\n", hr); @@ -128,7 +128,13 @@ static void test_decode(void) for (j = 2; j > 0; --j) { hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode); - ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr); + todo_wine ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr); + + if (FAILED(hr)) + { + skip("No frame returned, skipping tests\n"); + goto done; + }
hr = IWICBitmapFrameDecode_GetSize(framedecode, &width, &height); ok(SUCCEEDED(hr), "GetSize failed, hr=%x\n", hr); @@ -165,6 +171,7 @@ static void test_decode(void) IWICBitmapFrameDecode_Release(framedecode); }
+done: IStream_Release(wmpstream); GlobalFree(hwmpdata);
diff --git a/dlls/wmphoto/Makefile.in b/dlls/wmphoto/Makefile.in index 83462bd4c2f..21dfce04fa6 100644 --- a/dlls/wmphoto/Makefile.in +++ b/dlls/wmphoto/Makefile.in @@ -1,5 +1,6 @@ MODULE = wmphoto.dll IMPORTS = windowscodecs uuid kernelbase +PARENTSRC = ../windowscodecs
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/wmphoto/main.c b/dlls/wmphoto/main.c index efb408e94cb..5715d1676ae 100644 --- a/dlls/wmphoto/main.c +++ b/dlls/wmphoto/main.c @@ -34,12 +34,194 @@
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
-static HRESULT wmp_decoder_create(IUnknown *outer, IUnknown **out) +struct wmp_decoder { - FIXME("outer %p, out %p, stub!\n", outer, out); + IWICBitmapDecoder IWICBitmapDecoder_iface; + LONG ref; + IStream *stream; + CRITICAL_SECTION lock; +}; + +static inline struct wmp_decoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) +{ + return CONTAINING_RECORD(iface, struct wmp_decoder, IWICBitmapDecoder_iface); +} + +static HRESULT WINAPI wmp_decoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, void **out) +{ + struct wmp_decoder *This = impl_from_IWICBitmapDecoder(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (!out) return E_INVALIDARG; + + *out = NULL; + if (!IsEqualIID(&IID_IUnknown, iid) && !IsEqualIID(&IID_IWICBitmapDecoder, iid)) + return E_NOINTERFACE; + + *out = &This->IWICBitmapDecoder_iface; + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI wmp_decoder_AddRef(IWICBitmapDecoder *iface) +{ + struct wmp_decoder *This = impl_from_IWICBitmapDecoder(iface); + ULONG ref = InterlockedIncrement(&This->ref); + TRACE("iface %p -> ref %u.\n", iface, ref); + return ref; +} + +static ULONG WINAPI wmp_decoder_Release(IWICBitmapDecoder *iface) +{ + struct wmp_decoder *This = impl_from_IWICBitmapDecoder(iface); + ULONG ref = InterlockedDecrement(&This->ref); + TRACE("iface %p -> ref %u.\n", iface, ref); + + if (ref == 0) + { + This->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->lock); + if (This->stream) IStream_Release(This->stream); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +static HRESULT WINAPI wmp_decoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, DWORD *capability) +{ + FIXME("iface %p, stream %p, capability %p, stub!\n", iface, stream, capability); + return E_NOTIMPL; +} + +static HRESULT WINAPI wmp_decoder_Initialize(IWICBitmapDecoder *iface, IStream *stream, WICDecodeOptions options) +{ + struct wmp_decoder *This = impl_from_IWICBitmapDecoder(iface); + LARGE_INTEGER seek; + HRESULT hr; + + TRACE("iface %p, stream %p, options %u.\n", iface, stream, options); + + EnterCriticalSection(&This->lock); + + if (This->stream) hr = WINCODEC_ERR_WRONGSTATE; + else + { + seek.QuadPart = 0; + if (FAILED(hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL))) goto done; + + IStream_AddRef(stream); + This->stream = stream; + hr = S_OK; + } + +done: + LeaveCriticalSection(&This->lock); + return hr; +} + +static HRESULT WINAPI wmp_decoder_GetContainerFormat(IWICBitmapDecoder *iface, GUID *format) +{ + memcpy(format, &GUID_ContainerFormatWmp, sizeof(GUID)); + return S_OK; +} + +static HRESULT WINAPI wmp_decoder_GetDecoderInfo(IWICBitmapDecoder *iface, IWICBitmapDecoderInfo **info) +{ + FIXME("iface %p, info %p, stub!\n", iface, info); + return E_NOTIMPL; +} + +static HRESULT WINAPI wmp_decoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette) +{ + TRACE("iface %p, palette %p.\n", iface, palette); + return WINCODEC_ERR_PALETTEUNAVAILABLE; +} + +static HRESULT WINAPI wmp_decoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, IWICMetadataQueryReader **reader) +{ + FIXME("iface %p, reader %p, stub!\n", iface, reader); + if (!reader) return E_INVALIDARG; + *reader = NULL; return E_NOTIMPL; }
+static HRESULT WINAPI wmp_decoder_GetPreview(IWICBitmapDecoder *iface, IWICBitmapSource **source) +{ + FIXME("iface %p, source %p, stub!\n", iface, source); + return E_NOTIMPL; +} + +static HRESULT WINAPI wmp_decoder_GetColorContexts(IWICBitmapDecoder *iface, UINT maxcount, + IWICColorContext **contexts, UINT *count) +{ + FIXME("iface %p, maxcount %u, contexts %p, count %p, stub!\n", iface, maxcount, contexts, count); + return E_NOTIMPL; +} + +static HRESULT WINAPI wmp_decoder_GetThumbnail(IWICBitmapDecoder *iface, IWICBitmapSource **thumbnail) +{ + FIXME("iface %p, thumbnail %p, stub!\n", iface, thumbnail); + return E_NOTIMPL; +} + +static HRESULT WINAPI wmp_decoder_GetFrameCount(IWICBitmapDecoder *iface, UINT *count) +{ + TRACE("iface %p, count %p.\n", iface, count); + if (!count) return E_INVALIDARG; + *count = 0; + return E_NOTIMPL; +} + +static HRESULT WINAPI wmp_decoder_GetFrame(IWICBitmapDecoder *iface, UINT index, IWICBitmapFrameDecode **frame) +{ + TRACE("iface %p, index %u, frame %p.\n", iface, index, frame); + if (!frame) return E_INVALIDARG; + *frame = NULL; + return E_NOTIMPL; +} + +static const IWICBitmapDecoderVtbl wmp_decoder_vtbl = +{ + /* IUnknown methods */ + wmp_decoder_QueryInterface, + wmp_decoder_AddRef, + wmp_decoder_Release, + /* IWICBitmapDecoder methods */ + wmp_decoder_QueryCapability, + wmp_decoder_Initialize, + wmp_decoder_GetContainerFormat, + wmp_decoder_GetDecoderInfo, + wmp_decoder_CopyPalette, + wmp_decoder_GetMetadataQueryReader, + wmp_decoder_GetPreview, + wmp_decoder_GetColorContexts, + wmp_decoder_GetThumbnail, + wmp_decoder_GetFrameCount, + wmp_decoder_GetFrame +}; + +static HRESULT CDECL wmp_decoder_create(IUnknown *outer, IUnknown **out) +{ + struct wmp_decoder *This; + + TRACE("outer %p, out %p.\n", outer, out); + + *out = NULL; + This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wmp_decoder)); + if (!This) return E_OUTOFMEMORY; + + This->IWICBitmapDecoder_iface.lpVtbl = &wmp_decoder_vtbl; + This->ref = 1; + This->stream = NULL; + InitializeCriticalSection(&This->lock); + This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wmp_decoder.lock"); + + *out = (IUnknown *)&This->IWICBitmapDecoder_iface; + return S_OK; +} + struct class_factory { IClassFactory IClassFactory_iface;
This library is the JPEG-XR / Windows Media Photo / HD Photo reference implementation from Microsoft, released under BSD 2-Clause license:
https://archive.codeplex.com/?p=jxrlib
It is available for most Linux distributions already, and is also an optional dependency for imagemagick, freeimage or calibre:
* https://packages.debian.org/source/sid/jxrlib
* https://rpmfind.net/linux/rpm2html/search.php?query=jxrlib
* https://packages.ubuntu.com/source/xenial/jxrlib
* https://www.archlinux.org/packages/community/x86_64/jxrlib/
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- configure.ac | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/configure.ac b/configure.ac index 1072f16f09e..33a3278e0d4 100644 --- a/configure.ac +++ b/configure.ac @@ -58,6 +58,7 @@ AC_ARG_WITH(gstreamer, AS_HELP_STRING([--without-gstreamer],[do not use GStreame AC_ARG_WITH(hal, AS_HELP_STRING([--without-hal],[do not use HAL (dynamic device support)])) AC_ARG_WITH(inotify, AS_HELP_STRING([--without-inotify],[do not use inotify (filesystem change notifications)])) AC_ARG_WITH(jpeg, AS_HELP_STRING([--without-jpeg],[do not use JPEG])) +AC_ARG_WITH(jxrlib, AS_HELP_STRING([--without-jxrlib],[do not use JPEG-XR])) AC_ARG_WITH(krb5, AS_HELP_STRING([--without-krb5],[do not use krb5 (Kerberos)])) AC_ARG_WITH(ldap, AS_HELP_STRING([--without-ldap],[do not use LDAP]), [if test "x$withval" = "xno"; then ac_cv_header_ldap_h=no; ac_cv_header_lber_h=no; fi]) @@ -1850,6 +1851,21 @@ fi WINE_WARNING_WITH(jpeg,[test "x$ac_cv_lib_soname_jpeg" = "x"], [libjpeg ${notice_platform}development files not found, JPEG won't be supported.])
+dnl **** Check for libjxrglue **** +if test "x$with_jxrlib" != "xno" +then + WINE_PACKAGE_FLAGS(JXRLIB,[jxrlib],,[${JXRLIB_CFLAGS:--I/usr/include/jxrlib}],, + [AC_CHECK_HEADERS([JXRGlue.h],,,[#define FAR]) + if test "$ac_cv_header_JXRGlue_h" = "yes" + then + WINE_CHECK_SONAME(jxrglue,PKImageDecode_Create_WMP,,[JXRLIB_CFLAGS=""],[$JXRLIB_LIBS]) + else + JXRLIB_CFLAGS="" + fi]) +fi +WINE_WARNING_WITH(jxrlib,[test "x$ac_cv_lib_soname_jxrglue" = "x"], + [jxrlib ${notice_platform}development files not found, JPEG-XR won't be supported.]) + dnl **** Check for libpng **** if test "x$with_png" != "xno" then
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
FYI, jxrlib isn't avaiable for i686 in ubuntu.
According to: https://launchpad.net/ubuntu/focal/i386/libjxr0
"Publishing history
Removal requested on 2019-12-06. Deleted on 2019-12-06 by Steve Langasek
i386 deprecated as host arch Published on 2019-10-18"
Attempting to install it anyway generates confirmation from apt: "sudo apt install libjxr0.i686 Reading package lists... Done Building dependency tree Reading state information... Done E: Unable to locate package libjxr0.i686"
The dev package and x64 runtime libs are present, so anyone attempting to build wine on ubuntu would need to either build and install a 32-bit copy of the runtime libs, or disable support for this patch set when building wine.
It is available for most Linux distributions already, and is also an optional dependency for imagemagick, freeimage or calibre:
On 9/29/20 7:26 PM, Patrick Hibbs wrote:
FYI, jxrlib isn't avaiable for i686 in ubuntu.
According to: https://launchpad.net/ubuntu/focal/i386/libjxr0
"Publishing history
Removal requested on 2019-12-06. Deleted on 2019-12-06 by Steve Langasek i386 deprecated as host arch Published on 2019-10-18"
Attempting to install it anyway generates confirmation from apt: "sudo apt install libjxr0.i686 Reading package lists... Done Building dependency tree Reading state information... Done E: Unable to locate package libjxr0.i686"
The dev package and x64 runtime libs are present, so anyone attempting to build wine on ubuntu would need to either build and install a 32-bit copy of the runtime libs, or disable support for this patch set when building wine.
It is available for most Linux distributions already, and is also an optional dependency for imagemagick, freeimage or calibre:
Thanks for the information. The use case here is for Flight Simulator, which is a 64bit process so it won't be impacted. And I don't know any other application that needs it.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/wmphoto/Makefile.in | 5 ++- dlls/wmphoto/jxrlib.c | 68 ++++++++++++++++++++++++++++++++++ dlls/wmphoto/main.c | 17 +++++++-- dlls/wmphoto/wmphoto_private.h | 31 ++++++++++++++++ 4 files changed, 116 insertions(+), 5 deletions(-) create mode 100644 dlls/wmphoto/jxrlib.c create mode 100644 dlls/wmphoto/wmphoto_private.h
diff --git a/dlls/wmphoto/Makefile.in b/dlls/wmphoto/Makefile.in index 21dfce04fa6..37c879aed49 100644 --- a/dlls/wmphoto/Makefile.in +++ b/dlls/wmphoto/Makefile.in @@ -3,7 +3,10 @@ IMPORTS = windowscodecs uuid kernelbase PARENTSRC = ../windowscodecs
EXTRADLLFLAGS = -mno-cygwin +EXTRAINCL = $(JXRLIB_CFLAGS)
-C_SRCS = main.c +C_SRCS = \ + jxrlib.c \ + main.c
IDL_SRCS = wmphoto.idl diff --git a/dlls/wmphoto/jxrlib.c b/dlls/wmphoto/jxrlib.c new file mode 100644 index 00000000000..3fc78bee9de --- /dev/null +++ b/dlls/wmphoto/jxrlib.c @@ -0,0 +1,68 @@ +/* + * Copyright 2020 Rémi Bernon 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 unix +#endif + +#include "config.h" +#include "wine/port.h" + +#include <assert.h> +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winternl.h" + +#include "wine/debug.h" + +#include "wmphoto_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + +#ifdef SONAME_LIBJXRGLUE +static void *libjxrglue; +#endif + +static const struct jxrlib_funcs jxrlib_funcs = +{ +}; + +NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out) +{ + TRACE("module %p, reason %d, ptr_in %p, ptr_out %p\n", module, reason, ptr_in, ptr_out); + + if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS; + +#ifdef SONAME_LIBJXRGLUE + if (!(libjxrglue = dlopen(SONAME_LIBJXRGLUE, RTLD_NOW))) + { + WARN("failed to load %s\n", SONAME_LIBJXRGLUE); + return STATUS_DLL_NOT_FOUND; + } +#endif + + *(const struct jxrlib_funcs **)ptr_out = &jxrlib_funcs; + return STATUS_SUCCESS; +} diff --git a/dlls/wmphoto/main.c b/dlls/wmphoto/main.c index 5715d1676ae..83b5627f1af 100644 --- a/dlls/wmphoto/main.c +++ b/dlls/wmphoto/main.c @@ -26,14 +26,19 @@
#include "windef.h" #include "winbase.h" +#include "winternl.h" #include "objbase.h" #include "rpcproxy.h" #include "wincodecsdk.h"
#include "wine/debug.h"
+#include "wmphoto_private.h" + WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+static const struct jxrlib_funcs *jxrlib_funcs; + struct wmp_decoder { IWICBitmapDecoder IWICBitmapDecoder_iface; @@ -292,13 +297,17 @@ static struct class_factory wmp_decoder_cf = {{&class_factory_vtbl}, wmp_decoder
static HINSTANCE WMPHOTO_hInstance;
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { - switch (fdwReason) + TRACE("instance %p, reason %d, reserved %p\n", instance, reason, reserved); + + if (FAILED(__wine_init_unix_lib(instance, reason, NULL, &jxrlib_funcs))) return FALSE; + + switch (reason) { case DLL_PROCESS_ATTACH: - WMPHOTO_hInstance = hinstDLL; - DisableThreadLibraryCalls(hinstDLL); + WMPHOTO_hInstance = instance; + DisableThreadLibraryCalls(instance); break; case DLL_WINE_PREATTACH: return FALSE; /* prefer native version */ diff --git a/dlls/wmphoto/wmphoto_private.h b/dlls/wmphoto/wmphoto_private.h new file mode 100644 index 00000000000..dce7f018039 --- /dev/null +++ b/dlls/wmphoto/wmphoto_private.h @@ -0,0 +1,31 @@ +/* + * Copyright 2020 Rémi Bernon 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 + */ + +#ifndef WMPHOTO_PRIVATE_H +#define WMPHOTO_PRIVATE_H + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" + +struct jxrlib_funcs +{ +}; + +#endif /* WMPHOTO_PRIVATE_H */
Only a single frame is supported for now, but it should not be too hard to extend it to support multiple frames if there's any need for it.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v6: Use stream proxy object on the PE side for jxrlib callbacks instead of calling IStream vtable directly.
dlls/d3dx10_43/tests/d3dx10.c | 3 +- dlls/windowscodecs/Makefile.in | 1 + dlls/windowscodecs/copy_pixels.c | 90 +++++++ dlls/windowscodecs/main.c | 65 ----- dlls/windowscodecs/tests/wmpformat.c | 6 +- dlls/wmphoto/Makefile.in | 1 + dlls/wmphoto/jxrlib.c | 171 +++++++++++++ dlls/wmphoto/main.c | 369 ++++++++++++++++++++++++++- dlls/wmphoto/wmphoto_private.h | 28 ++ 9 files changed, 657 insertions(+), 77 deletions(-) create mode 100644 dlls/windowscodecs/copy_pixels.c
diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index 640e83fcd0f..fb5eb79e4e4 100644 --- a/dlls/d3dx10_43/tests/d3dx10.c +++ b/dlls/d3dx10_43/tests/d3dx10.c @@ -1376,8 +1376,7 @@ static void test_get_image_info(void) for (i = 0; i < ARRAY_SIZE(test_image); ++i) { hr = D3DX10GetImageInfoFromMemory(test_image[i].data, test_image[i].size, NULL, &image_info, NULL); - todo_wine_if(test_image[i].expected.ImageFileFormat == D3DX10_IFF_WMP) - ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr); + ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr); if (hr != S_OK) continue; check_image_info(&image_info, i, __LINE__); diff --git a/dlls/windowscodecs/Makefile.in b/dlls/windowscodecs/Makefile.in index fac90344fa3..56fa821939f 100644 --- a/dlls/windowscodecs/Makefile.in +++ b/dlls/windowscodecs/Makefile.in @@ -13,6 +13,7 @@ C_SRCS = \ colorcontext.c \ colortransform.c \ converter.c \ + copy_pixels.c \ ddsformat.c \ fliprotate.c \ gifformat.c \ diff --git a/dlls/windowscodecs/copy_pixels.c b/dlls/windowscodecs/copy_pixels.c new file mode 100644 index 00000000000..da905557b3f --- /dev/null +++ b/dlls/windowscodecs/copy_pixels.c @@ -0,0 +1,90 @@ +/* + * Copyright 2009 Vincent Povirk 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 + */ + +#include <stdarg.h> + +#include "wincodecsdk.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + +HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer, + UINT srcwidth, UINT srcheight, INT srcstride, + const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer) +{ + UINT bytesperrow; + UINT row_offset; /* number of bits into the source rows where the data starts */ + WICRect rect; + + if (!rc) + { + rect.X = 0; + rect.Y = 0; + rect.Width = srcwidth; + rect.Height = srcheight; + rc = ▭ + } + else + { + if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight) + return E_INVALIDARG; + } + + bytesperrow = ((bpp * rc->Width)+7)/8; + + if (dststride < bytesperrow) + return E_INVALIDARG; + + if ((dststride * (rc->Height-1)) + bytesperrow > dstbuffersize) + return E_INVALIDARG; + + /* if the whole bitmap is copied and the buffer format matches then it's a matter of a single memcpy */ + if (rc->X == 0 && rc->Y == 0 && rc->Width == srcwidth && rc->Height == srcheight && + srcstride == dststride && srcstride == bytesperrow) + { + memcpy(dstbuffer, srcbuffer, srcstride * srcheight); + return S_OK; + } + + row_offset = rc->X * bpp; + + if (row_offset % 8 == 0) + { + /* everything lines up on a byte boundary */ + INT row; + const BYTE *src; + BYTE *dst; + + src = srcbuffer + (row_offset / 8) + srcstride * rc->Y; + dst = dstbuffer; + for (row=0; row < rc->Height; row++) + { + memcpy(dst, src, bytesperrow); + src += srcstride; + dst += dststride; + } + return S_OK; + } + else + { + /* we have to do a weird bitwise copy. eww. */ + FIXME("cannot reliably copy bitmap data if bpp < 8\n"); + return E_FAIL; + } +} diff --git a/dlls/windowscodecs/main.c b/dlls/windowscodecs/main.c index 7e03112a63c..ca708d26fd4 100644 --- a/dlls/windowscodecs/main.c +++ b/dlls/windowscodecs/main.c @@ -55,71 +55,6 @@ HRESULT WINAPI DllCanUnloadNow(void) return S_FALSE; }
-HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer, - UINT srcwidth, UINT srcheight, INT srcstride, - const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer) -{ - UINT bytesperrow; - UINT row_offset; /* number of bits into the source rows where the data starts */ - WICRect rect; - - if (!rc) - { - rect.X = 0; - rect.Y = 0; - rect.Width = srcwidth; - rect.Height = srcheight; - rc = ▭ - } - else - { - if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight) - return E_INVALIDARG; - } - - bytesperrow = ((bpp * rc->Width)+7)/8; - - if (dststride < bytesperrow) - return E_INVALIDARG; - - if ((dststride * (rc->Height-1)) + bytesperrow > dstbuffersize) - return E_INVALIDARG; - - /* if the whole bitmap is copied and the buffer format matches then it's a matter of a single memcpy */ - if (rc->X == 0 && rc->Y == 0 && rc->Width == srcwidth && rc->Height == srcheight && - srcstride == dststride && srcstride == bytesperrow) - { - memcpy(dstbuffer, srcbuffer, srcstride * srcheight); - return S_OK; - } - - row_offset = rc->X * bpp; - - if (row_offset % 8 == 0) - { - /* everything lines up on a byte boundary */ - INT row; - const BYTE *src; - BYTE *dst; - - src = srcbuffer + (row_offset / 8) + srcstride * rc->Y; - dst = dstbuffer; - for (row=0; row < rc->Height; row++) - { - memcpy(dst, src, bytesperrow); - src += srcstride; - dst += dststride; - } - return S_OK; - } - else - { - /* we have to do a weird bitwise copy. eww. */ - FIXME("cannot reliably copy bitmap data if bpp < 8\n"); - return E_FAIL; - } -} - HRESULT configure_write_source(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, const WICRect *prc, const WICPixelFormatGUID *format, diff --git a/dlls/windowscodecs/tests/wmpformat.c b/dlls/windowscodecs/tests/wmpformat.c index 12bc1275919..e808e6fee53 100644 --- a/dlls/windowscodecs/tests/wmpformat.c +++ b/dlls/windowscodecs/tests/wmpformat.c @@ -119,8 +119,8 @@ static void test_decode(void) "unexpected container format\n");
hr = IWICBitmapDecoder_GetFrameCount(decoder, &count); - todo_wine ok(SUCCEEDED(hr), "GetFrameCount failed, hr=%x\n", hr); - todo_wine ok(count == 1, "unexpected count %u\n", count); + ok(SUCCEEDED(hr), "GetFrameCount failed, hr=%x\n", hr); + ok(count == 1, "unexpected count %u\n", count);
hr = IWICBitmapDecoder_GetFrame(decoder, 0, NULL); ok(hr == E_INVALIDARG, "GetFrame(NULL) returned hr=%x\n", hr); @@ -128,7 +128,7 @@ static void test_decode(void) for (j = 2; j > 0; --j) { hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode); - todo_wine ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr); + ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr);
if (FAILED(hr)) { diff --git a/dlls/wmphoto/Makefile.in b/dlls/wmphoto/Makefile.in index 37c879aed49..a9dce70a4de 100644 --- a/dlls/wmphoto/Makefile.in +++ b/dlls/wmphoto/Makefile.in @@ -6,6 +6,7 @@ EXTRADLLFLAGS = -mno-cygwin EXTRAINCL = $(JXRLIB_CFLAGS)
C_SRCS = \ + copy_pixels.c \ jxrlib.c \ main.c
diff --git a/dlls/wmphoto/jxrlib.c b/dlls/wmphoto/jxrlib.c index 3fc78bee9de..1e7ec5e92bc 100644 --- a/dlls/wmphoto/jxrlib.c +++ b/dlls/wmphoto/jxrlib.c @@ -28,12 +28,21 @@ #include <string.h> #include <stdlib.h>
+#define COBJMACROS + #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winerror.h" #include "winternl.h" +#include "objidl.h" + +#ifdef SONAME_LIBJXRGLUE +#define ERR JXR_ERR +#include <JXRGlue.h> +#undef ERR +#endif
#include "wine/debug.h"
@@ -43,10 +52,166 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
#ifdef SONAME_LIBJXRGLUE static void *libjxrglue; +static typeof(PKImageDecode_Create_WMP) *pPKImageDecode_Create_WMP; + +struct decoder_proxy +{ + struct jxrlib_decoder decoder_iface; + struct WMPStream WMPStream_iface; + struct jxrlib_stream *stream; + PKImageDecode *decoder; +}; + +static inline struct decoder_proxy *impl_from_jxrlib_decoder(struct jxrlib_decoder *iface) +{ + return CONTAINING_RECORD(iface, struct decoder_proxy, decoder_iface); +} + +static inline struct decoder_proxy *impl_from_WMPStream(struct WMPStream *iface) +{ + return CONTAINING_RECORD(iface, struct decoder_proxy, WMPStream_iface); +} + +static JXR_ERR wmp_stream_Close(struct WMPStream **piface) +{ + TRACE("iface %p.\n", piface); + return WMP_errSuccess; +} + +static Bool wmp_stream_EOS(struct WMPStream *iface) +{ + FIXME("iface %p, stub!\n", iface); + return FALSE; +} + +static JXR_ERR wmp_stream_Read(struct WMPStream *iface, void *buf, size_t len) +{ + struct decoder_proxy *This = impl_from_WMPStream(iface); + return This->stream->Read(This->stream, buf, len); +} + +static JXR_ERR wmp_stream_Write(struct WMPStream *iface, const void *buf, size_t len) +{ + struct decoder_proxy *This = impl_from_WMPStream(iface); + return This->stream->Write(This->stream, buf, len); +} + +static JXR_ERR wmp_stream_SetPos(struct WMPStream *iface, size_t pos) +{ + struct decoder_proxy *This = impl_from_WMPStream(iface); + return This->stream->SetPos(This->stream, pos); +} + +static JXR_ERR wmp_stream_GetPos(struct WMPStream *iface, size_t *pos) +{ + struct decoder_proxy *This = impl_from_WMPStream(iface); + return This->stream->GetPos(This->stream, pos); +} + +static JXR_ERR CDECL decoder_Initialize(struct jxrlib_decoder *iface, struct jxrlib_stream *stream) +{ + struct decoder_proxy *This = impl_from_jxrlib_decoder(iface); + if (This->stream) return WMP_errFail; + This->stream = stream; + return This->decoder->Initialize(This->decoder, &This->WMPStream_iface); +} + +static JXR_ERR CDECL decoder_GetPixelFormat(struct jxrlib_decoder *iface, GUID *guid) +{ + struct decoder_proxy *This = impl_from_jxrlib_decoder(iface); + return This->decoder->GetPixelFormat(This->decoder, guid); +} + +static JXR_ERR CDECL decoder_GetSize(struct jxrlib_decoder *iface, INT32 *width, INT32 *height) +{ + struct decoder_proxy *This = impl_from_jxrlib_decoder(iface); + return This->decoder->GetSize(This->decoder, width, height); +} + +static JXR_ERR CDECL decoder_GetResolution(struct jxrlib_decoder *iface, FLOAT *resx, FLOAT *resy) +{ + struct decoder_proxy *This = impl_from_jxrlib_decoder(iface); + return This->decoder->GetResolution(This->decoder, resx, resy); +} + +static JXR_ERR CDECL decoder_Copy(struct jxrlib_decoder *iface, const WICRect *rect, UINT8 *buffer, UINT32 stride) +{ + struct decoder_proxy *This = impl_from_jxrlib_decoder(iface); + PKRect pkrect; + if (!rect) return WMP_errFail; + pkrect.X = rect->X; + pkrect.Y = rect->Y; + pkrect.Width = rect->Width; + pkrect.Height = rect->Height; + return This->decoder->Copy(This->decoder, &pkrect, buffer, stride); +} + +static JXR_ERR CDECL decoder_GetFrameCount(struct jxrlib_decoder *iface, UINT32 *count) +{ + struct decoder_proxy *This = impl_from_jxrlib_decoder(iface); + return This->decoder->GetFrameCount(This->decoder, count); +} + +static JXR_ERR CDECL decoder_SelectFrame(struct jxrlib_decoder *iface, UINT32 index) +{ + struct decoder_proxy *This = impl_from_jxrlib_decoder(iface); + return This->decoder->SelectFrame(This->decoder, index); +} + +static JXR_ERR CDECL decoder_Release(struct jxrlib_decoder **iface) +{ + struct decoder_proxy *This = impl_from_jxrlib_decoder(*iface); + JXR_ERR err; + + if ((err = This->decoder->Release(&This->decoder))) return err; + + free(This); + *iface = NULL; + + return err; +} + +static HRESULT CDECL jxrlib_decoder_create(struct jxrlib_decoder **out) +{ + struct decoder_proxy *This; + PKImageDecode *decoder; + + if (pPKImageDecode_Create_WMP(&decoder)) return E_FAIL; + if (!(This = malloc(sizeof(*This)))) return E_OUTOFMEMORY; + + This->decoder_iface.Initialize = &decoder_Initialize; + This->decoder_iface.GetPixelFormat = &decoder_GetPixelFormat; + This->decoder_iface.GetSize = &decoder_GetSize; + This->decoder_iface.GetResolution = &decoder_GetResolution; + This->decoder_iface.Copy = &decoder_Copy; + This->decoder_iface.GetFrameCount = &decoder_GetFrameCount; + This->decoder_iface.SelectFrame = &decoder_SelectFrame; + This->decoder_iface.Release = &decoder_Release; + + This->WMPStream_iface.Close = &wmp_stream_Close; + This->WMPStream_iface.EOS = &wmp_stream_EOS; + This->WMPStream_iface.Read = &wmp_stream_Read; + This->WMPStream_iface.Write = &wmp_stream_Write; + This->WMPStream_iface.SetPos = &wmp_stream_SetPos; + This->WMPStream_iface.GetPos = &wmp_stream_GetPos; + + This->decoder = decoder; + This->stream = NULL; + + *out = &This->decoder_iface; + return S_OK; +} +#else +static HRESULT CDECL jxrlib_decoder_create(struct jxrlib_decoder **out) +{ + FIXME("JPEG-XR support not compiled in!\n"); + return E_NOTIMPL; +} #endif
static const struct jxrlib_funcs jxrlib_funcs = { + jxrlib_decoder_create, };
NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out) @@ -61,6 +226,12 @@ NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *pt WARN("failed to load %s\n", SONAME_LIBJXRGLUE); return STATUS_DLL_NOT_FOUND; } + + if (!(pPKImageDecode_Create_WMP = dlsym(libjxrglue, "PKImageDecode_Create_WMP"))) + { + ERR("unable to find PKImageDecode_Create_WMP in %s!\n", SONAME_LIBJXRGLUE); + return FALSE; + } #endif
*(const struct jxrlib_funcs **)ptr_out = &jxrlib_funcs; diff --git a/dlls/wmphoto/main.c b/dlls/wmphoto/main.c index 83b5627f1af..0212cd4909a 100644 --- a/dlls/wmphoto/main.c +++ b/dlls/wmphoto/main.c @@ -39,11 +39,340 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
static const struct jxrlib_funcs *jxrlib_funcs;
+static inline const char *debug_wic_rect(const WICRect *rect) +{ + if (!rect) return "(null)"; + return wine_dbg_sprintf("(%u,%u)-(%u,%u)", rect->X, rect->Y, rect->Width, rect->Height); +} + +extern HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer, UINT srcwidth, UINT srcheight, INT srcstride, + const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer) DECLSPEC_HIDDEN; + +static const struct +{ + const WICPixelFormatGUID *format; + UINT bpp; +} pixel_format_bpp[] = +{ + {&GUID_WICPixelFormat128bppRGBAFixedPoint, 128}, + {&GUID_WICPixelFormat128bppRGBAFloat, 128}, + {&GUID_WICPixelFormat128bppRGBFloat, 128}, + {&GUID_WICPixelFormat16bppBGR555, 16}, + {&GUID_WICPixelFormat16bppBGR565, 16}, + {&GUID_WICPixelFormat16bppGray, 16}, + {&GUID_WICPixelFormat16bppGrayFixedPoint, 16}, + {&GUID_WICPixelFormat16bppGrayHalf, 16}, + {&GUID_WICPixelFormat24bppBGR, 24}, + {&GUID_WICPixelFormat24bppRGB, 24}, + {&GUID_WICPixelFormat32bppBGR, 32}, + {&GUID_WICPixelFormat32bppBGR101010, 32}, + {&GUID_WICPixelFormat32bppBGRA, 32}, + {&GUID_WICPixelFormat32bppCMYK, 32}, + {&GUID_WICPixelFormat32bppGrayFixedPoint, 32}, + {&GUID_WICPixelFormat32bppGrayFloat, 32}, + {&GUID_WICPixelFormat32bppRGBE, 32}, + {&GUID_WICPixelFormat40bppCMYKAlpha, 40}, + {&GUID_WICPixelFormat48bppRGB, 48}, + {&GUID_WICPixelFormat48bppRGBFixedPoint, 48}, + {&GUID_WICPixelFormat48bppRGBHalf, 48}, + {&GUID_WICPixelFormat64bppCMYK, 64}, + {&GUID_WICPixelFormat64bppRGBA, 64}, + {&GUID_WICPixelFormat64bppRGBAFixedPoint, 64}, + {&GUID_WICPixelFormat64bppRGBAHalf, 64}, + {&GUID_WICPixelFormat80bppCMYKAlpha, 80}, + {&GUID_WICPixelFormat8bppGray, 8}, + {&GUID_WICPixelFormat96bppRGBFixedPoint, 96}, + {&GUID_WICPixelFormatBlackWhite, 1}, +}; + +static inline UINT pixel_format_get_bpp(const WICPixelFormatGUID *format) +{ + int i; + for (i = 0; i < ARRAY_SIZE(pixel_format_bpp); ++i) + if (IsEqualGUID(format, pixel_format_bpp[i].format)) return pixel_format_bpp[i].bpp; + return 0; +} + +struct stream_proxy +{ + struct jxrlib_stream stream_iface; + IStream *stream; +}; + +static inline struct stream_proxy *impl_from_jxrlib_stream(struct jxrlib_stream *iface) +{ + return CONTAINING_RECORD(iface, struct stream_proxy, stream_iface); +} + +static JXR_ERR CDECL stream_Read(struct jxrlib_stream *iface, void *buf, size_t len) +{ + struct stream_proxy *This = impl_from_jxrlib_stream(iface); + ULONG count; + + TRACE("iface %p, buf %p, len %Ix.\n", iface, buf, len); + + if (FAILED(IStream_Read(This->stream, buf, len, &count)) || count < len) return WMP_errFileIO; + return WMP_errSuccess; +} + +static JXR_ERR CDECL stream_Write(struct jxrlib_stream *iface, const void *buf, size_t len) +{ + struct stream_proxy *This = impl_from_jxrlib_stream(iface); + ULONG count; + + TRACE("iface %p, buf %p, len %Ix.\n", iface, buf, len); + + if (FAILED(IStream_Write(This->stream, buf, len, &count)) || count < len) return WMP_errFileIO; + return WMP_errSuccess; +} + +static JXR_ERR CDECL stream_SetPos(struct jxrlib_stream *iface, size_t pos) +{ + struct stream_proxy *This = impl_from_jxrlib_stream(iface); + LARGE_INTEGER move; + + TRACE("iface %p, pos %Ix.\n", iface, pos); + + move.QuadPart = pos; + if (FAILED(IStream_Seek(This->stream, move, STREAM_SEEK_SET, NULL))) return WMP_errFileIO; + return WMP_errSuccess; +} + +static JXR_ERR CDECL stream_GetPos(struct jxrlib_stream *iface, size_t *pos) +{ + struct stream_proxy *This = impl_from_jxrlib_stream(iface); + ULARGE_INTEGER curr; + LARGE_INTEGER move; + + TRACE("iface %p, pos %p.\n", iface, pos); + + move.QuadPart = 0; + if (FAILED(IStream_Seek(This->stream, move, STREAM_SEEK_CUR, &curr))) return WMP_errFileIO; + *pos = curr.QuadPart; + + return WMP_errSuccess; +} + +static HRESULT jxrlib_stream_create(IStream *stream, struct jxrlib_stream **out) +{ + struct stream_proxy *This; + LARGE_INTEGER seek; + HRESULT hr; + + seek.QuadPart = 0; + if (FAILED(hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL))) return hr; + if (!(This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)))) return E_OUTOFMEMORY; + + This->stream_iface.Read = &stream_Read; + This->stream_iface.Write = &stream_Write; + This->stream_iface.SetPos = &stream_SetPos; + This->stream_iface.GetPos = &stream_GetPos; + This->stream = stream; + IStream_AddRef(stream); + + *out = &This->stream_iface; + return S_OK; +} + +static void jxrlib_stream_release(struct jxrlib_stream *iface) +{ + struct stream_proxy *This = impl_from_jxrlib_stream(iface); + IStream_Release(This->stream); + HeapFree(GetProcessHeap(), 0, This); +} + +struct wmp_decoder_frame +{ + IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; + LONG ref; + WICPixelFormatGUID format; + UINT bpp; + UINT stride; + WICRect rect; + float resx, resy; + void *image_data; +}; + +static inline struct wmp_decoder_frame *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) +{ + return CONTAINING_RECORD(iface, struct wmp_decoder_frame, IWICBitmapFrameDecode_iface); +} + +static HRESULT WINAPI wmp_decoder_frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, void **out) +{ + struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface); + + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (!out) return E_INVALIDARG; + + *out = NULL; + if (!IsEqualIID(&IID_IUnknown, iid) && + !IsEqualIID(&IID_IWICBitmapSource, iid) && + !IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) + return E_NOINTERFACE; + + *out = &This->IWICBitmapFrameDecode_iface; + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI wmp_decoder_frame_AddRef(IWICBitmapFrameDecode *iface) +{ + struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface); + ULONG ref = InterlockedIncrement(&This->ref); + TRACE("iface %p -> ref %u.\n", iface, ref); + return ref; +} + +static ULONG WINAPI wmp_decoder_frame_Release(IWICBitmapFrameDecode *iface) +{ + struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface); + ULONG ref = InterlockedDecrement(&This->ref); + TRACE("iface %p -> ref %u.\n", iface, ref); + + if (ref == 0) + { + HeapFree(GetProcessHeap(), 0, This->image_data); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +static HRESULT WINAPI wmp_decoder_frame_GetSize(IWICBitmapFrameDecode *iface, UINT *width, UINT *height) +{ + struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface); + TRACE("iface %p, width %p, height %p.\n", iface, width, height); + *width = This->rect.Width; + *height = This->rect.Height; + return S_OK; +} + +static HRESULT WINAPI wmp_decoder_frame_GetPixelFormat(IWICBitmapFrameDecode *iface, WICPixelFormatGUID *format) +{ + struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface); + TRACE("iface %p, format %p.\n", iface, format); + *format = This->format; + return S_OK; +} + +static HRESULT WINAPI wmp_decoder_frame_GetResolution(IWICBitmapFrameDecode *iface, double *dpix, double *dpiy) +{ + struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface); + TRACE("iface %p, dpix %p, dpiy %p.\n", iface, dpix, dpiy); + *dpix = This->resx; + *dpiy = This->resy; + return S_OK; +} + +static HRESULT WINAPI wmp_decoder_frame_CopyPalette(IWICBitmapFrameDecode *iface, IWICPalette *palette) +{ + TRACE("iface %p, palette %p.\n", iface, palette); + return WINCODEC_ERR_PALETTEUNAVAILABLE; +} + +static HRESULT WINAPI wmp_decoder_frame_CopyPixels(IWICBitmapFrameDecode *iface, const WICRect *rect, + UINT stride, UINT bufsize, BYTE *buffer) +{ + struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface); + TRACE("iface %p, rect %p, stride %u, bufsize %u, buffer %p.\n", iface, debug_wic_rect(rect), + stride, bufsize, buffer); + return copy_pixels(This->bpp, This->image_data, This->rect.Width, This->rect.Height, + This->stride, rect, stride, bufsize, buffer); +} + +static HRESULT WINAPI wmp_decoder_frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, + IWICMetadataQueryReader **reader) +{ + FIXME("iface %p, reader %p, stub!\n", iface, reader); + if (!reader) return E_INVALIDARG; + *reader = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI wmp_decoder_frame_GetColorContexts(IWICBitmapFrameDecode *iface, UINT maxcount, + IWICColorContext **contexts, UINT *count) +{ + FIXME("iface %p, maxcount %u, contexts %p, count %p, stub\n", iface, maxcount, contexts, count); + return E_NOTIMPL; +} + +static HRESULT WINAPI wmp_decoder_frame_GetThumbnail(IWICBitmapFrameDecode *iface, IWICBitmapSource **thumbnail) +{ + FIXME("iface %p, thumbnail %p, stub!\n", iface, thumbnail); + return WINCODEC_ERR_CODECNOTHUMBNAIL; +} + +static const IWICBitmapFrameDecodeVtbl wmp_decoder_frame_vtbl = +{ + /* IUnknown methods */ + wmp_decoder_frame_QueryInterface, + wmp_decoder_frame_AddRef, + wmp_decoder_frame_Release, + /* IWICBitmapSource methods */ + wmp_decoder_frame_GetSize, + wmp_decoder_frame_GetPixelFormat, + wmp_decoder_frame_GetResolution, + wmp_decoder_frame_CopyPalette, + wmp_decoder_frame_CopyPixels, + /* IWICBitmapFrameDecode methods */ + wmp_decoder_frame_GetMetadataQueryReader, + wmp_decoder_frame_GetColorContexts, + wmp_decoder_frame_GetThumbnail +}; + +static HRESULT wmp_decoder_frame_create(IStream *stream, UINT frame, IWICBitmapFrameDecode **out) +{ + struct wmp_decoder_frame *This = NULL; + struct jxrlib_decoder *jxrlib_decoder = NULL; + struct jxrlib_stream *jxrlib_stream = NULL; + HRESULT hr; + + TRACE("stream %p, frame %u, out %p.\n", stream, frame, out); + + *out = NULL; + if (FAILED(hr = jxrlib_stream_create(stream, &jxrlib_stream))) goto failed; + if (FAILED(hr = jxrlib_funcs->decoder_create(&jxrlib_decoder))) goto failed; + + hr = E_FAIL; + if (jxrlib_decoder->Initialize(jxrlib_decoder, jxrlib_stream)) goto failed; + if (jxrlib_decoder->SelectFrame(jxrlib_decoder, frame)) goto failed; + + hr = E_OUTOFMEMORY; + if (!(This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wmp_decoder_frame)))) goto failed; + This->IWICBitmapFrameDecode_iface.lpVtbl = &wmp_decoder_frame_vtbl; + This->ref = 1; + + hr = E_FAIL; + if (jxrlib_decoder->GetPixelFormat(jxrlib_decoder, &This->format)) goto failed; + if (jxrlib_decoder->GetSize(jxrlib_decoder, &This->rect.Width, &This->rect.Height)) goto failed; + if (jxrlib_decoder->GetResolution(jxrlib_decoder, &This->resx, &This->resy)) goto failed; + + if (!(This->bpp = pixel_format_get_bpp(&This->format))) goto failed; + This->stride = (This->rect.Width * This->bpp + 7) / 8; + if (!(This->image_data = HeapAlloc(GetProcessHeap(), 0, This->rect.Height * This->stride))) goto failed; + if (jxrlib_decoder->Copy(jxrlib_decoder, &This->rect, This->image_data, This->stride)) goto failed; + + *out = &This->IWICBitmapFrameDecode_iface; + return S_OK; + +failed: + if (This && This->image_data) HeapFree(GetProcessHeap(), 0, This->image_data); + if (This) HeapFree(GetProcessHeap(), 0, This); + if (jxrlib_decoder) jxrlib_decoder->Release(&jxrlib_decoder); + if (jxrlib_stream) jxrlib_stream_release(jxrlib_stream); + return hr; +} + struct wmp_decoder { IWICBitmapDecoder IWICBitmapDecoder_iface; + IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; LONG ref; IStream *stream; + UINT frame_count; + IWICBitmapFrameDecode *frame; CRITICAL_SECTION lock; };
@@ -87,6 +416,7 @@ static ULONG WINAPI wmp_decoder_Release(IWICBitmapDecoder *iface) { This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); + if (This->frame) IWICBitmapFrameDecode_Release(This->frame); if (This->stream) IStream_Release(This->stream); HeapFree(GetProcessHeap(), 0, This); } @@ -103,7 +433,8 @@ static HRESULT WINAPI wmp_decoder_QueryCapability(IWICBitmapDecoder *iface, IStr static HRESULT WINAPI wmp_decoder_Initialize(IWICBitmapDecoder *iface, IStream *stream, WICDecodeOptions options) { struct wmp_decoder *This = impl_from_IWICBitmapDecoder(iface); - LARGE_INTEGER seek; + struct jxrlib_decoder *jxrlib_decoder = NULL; + struct jxrlib_stream *jxrlib_stream = NULL; HRESULT hr;
TRACE("iface %p, stream %p, options %u.\n", iface, stream, options); @@ -113,8 +444,13 @@ static HRESULT WINAPI wmp_decoder_Initialize(IWICBitmapDecoder *iface, IStream * if (This->stream) hr = WINCODEC_ERR_WRONGSTATE; else { - seek.QuadPart = 0; - if (FAILED(hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL))) goto done; + if (FAILED(hr = jxrlib_stream_create(stream, &jxrlib_stream))) goto done; + if (FAILED(hr = jxrlib_funcs->decoder_create(&jxrlib_decoder))) goto done; + + hr = E_FAIL; + if (jxrlib_decoder->Initialize(jxrlib_decoder, jxrlib_stream)) goto done; + if (jxrlib_decoder->GetFrameCount(jxrlib_decoder, &This->frame_count)) goto done; + if (This->frame_count > 1) FIXME("multi frame JPEG-XR not implemented\n");
IStream_AddRef(stream); This->stream = stream; @@ -122,6 +458,8 @@ static HRESULT WINAPI wmp_decoder_Initialize(IWICBitmapDecoder *iface, IStream * }
done: + if (jxrlib_decoder) jxrlib_decoder->Release(&jxrlib_decoder); + if (jxrlib_stream) jxrlib_stream_release(jxrlib_stream); LeaveCriticalSection(&This->lock); return hr; } @@ -175,16 +513,31 @@ static HRESULT WINAPI wmp_decoder_GetFrameCount(IWICBitmapDecoder *iface, UINT * { TRACE("iface %p, count %p.\n", iface, count); if (!count) return E_INVALIDARG; - *count = 0; - return E_NOTIMPL; + *count = 1; + return S_OK; }
static HRESULT WINAPI wmp_decoder_GetFrame(IWICBitmapDecoder *iface, UINT index, IWICBitmapFrameDecode **frame) { + struct wmp_decoder *This = impl_from_IWICBitmapDecoder(iface); + HRESULT hr; + TRACE("iface %p, index %u, frame %p.\n", iface, index, frame); + if (!frame) return E_INVALIDARG; - *frame = NULL; - return E_NOTIMPL; + + EnterCriticalSection(&This->lock); + if (!This->stream) hr = WINCODEC_ERR_WRONGSTATE; + else if (index >= This->frame_count) hr = E_INVALIDARG; + else if (index >= 1) hr = E_NOTIMPL; /* FIXME: Add support for multiple frames */ + else if (This->frame) hr = S_OK; + else hr = wmp_decoder_frame_create(This->stream, index, &This->frame); + + if (This->frame) IWICBitmapFrameDecode_AddRef(This->frame); + *frame = This->frame; + LeaveCriticalSection(&This->lock); + + return hr; }
static const IWICBitmapDecoderVtbl wmp_decoder_vtbl = @@ -218,8 +571,10 @@ static HRESULT CDECL wmp_decoder_create(IUnknown *outer, IUnknown **out) if (!This) return E_OUTOFMEMORY;
This->IWICBitmapDecoder_iface.lpVtbl = &wmp_decoder_vtbl; + This->IWICBitmapFrameDecode_iface.lpVtbl = &wmp_decoder_frame_vtbl; This->ref = 1; This->stream = NULL; + This->frame = NULL; InitializeCriticalSection(&This->lock); This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wmp_decoder.lock");
diff --git a/dlls/wmphoto/wmphoto_private.h b/dlls/wmphoto/wmphoto_private.h index dce7f018039..3949983cc07 100644 --- a/dlls/wmphoto/wmphoto_private.h +++ b/dlls/wmphoto/wmphoto_private.h @@ -23,9 +23,37 @@
#include "windef.h" #include "winbase.h" +#include "wincodecsdk.h" + +typedef long JXR_ERR; + +#define WMP_errSuccess 0 +#define WMP_errFail -1 +#define WMP_errFileIO -102 + +struct jxrlib_stream +{ + JXR_ERR (CDECL *Read)(struct jxrlib_stream *iface, void *buf, size_t len); + JXR_ERR (CDECL *Write)(struct jxrlib_stream *iface, const void *buf, size_t len); + JXR_ERR (CDECL *SetPos)(struct jxrlib_stream *iface, size_t pos); + JXR_ERR (CDECL *GetPos)(struct jxrlib_stream *iface, size_t *pos); +}; + +struct jxrlib_decoder +{ + JXR_ERR (CDECL *Initialize)(struct jxrlib_decoder *iface, struct jxrlib_stream *stream); + JXR_ERR (CDECL *GetPixelFormat)(struct jxrlib_decoder *iface, GUID *guid); + JXR_ERR (CDECL *GetSize)(struct jxrlib_decoder *iface, INT32 *width, INT32 *height); + JXR_ERR (CDECL *GetResolution)(struct jxrlib_decoder *iface, FLOAT *resx, FLOAT *resy); + JXR_ERR (CDECL *Copy)(struct jxrlib_decoder *iface, const WICRect *rect, UINT8 *buffer, UINT32 stride); + JXR_ERR (CDECL *GetFrameCount)(struct jxrlib_decoder *iface, UINT32 *count); + JXR_ERR (CDECL *SelectFrame)(struct jxrlib_decoder *iface, UINT32 index); + JXR_ERR (CDECL *Release)(struct jxrlib_decoder **iface); +};
struct jxrlib_funcs { + HRESULT (CDECL *decoder_create)(struct jxrlib_decoder **out); };
#endif /* WMPHOTO_PRIVATE_H */
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=79448
Your paranoid android.
=== debiant (32 bit report) ===
d3dx10_43: d3dx10.c:1379: Test failed: Test 27: Got unexpected hr 0x80004005.
windowscodecs: wmpformat.c:111: Test failed: Initialize failed, hr=80004001 wmpformat.c:114: Test failed: Initialize returned 80004001 wmpformat.c:131: Test failed: GetFrame failed, hr=88982f04
=== debiant (32 bit French report) ===
d3dx10_43: d3dx10.c:1379: Test failed: Test 27: Got unexpected hr 0x80004005.
windowscodecs: wmpformat.c:111: Test failed: Initialize failed, hr=80004001 wmpformat.c:114: Test failed: Initialize returned 80004001 wmpformat.c:131: Test failed: GetFrame failed, hr=88982f04
=== debiant (32 bit Japanese:Japan report) ===
d3dx10_43: d3dx10.c:1379: Test failed: Test 27: Got unexpected hr 0x80004005.
windowscodecs: wmpformat.c:111: Test failed: Initialize failed, hr=80004001 wmpformat.c:114: Test failed: Initialize returned 80004001 wmpformat.c:131: Test failed: GetFrame failed, hr=88982f04
=== debiant (32 bit Chinese:China report) ===
d3dx10_43: d3dx10.c:1379: Test failed: Test 27: Got unexpected hr 0x80004005.
windowscodecs: wmpformat.c:111: Test failed: Initialize failed, hr=80004001 wmpformat.c:114: Test failed: Initialize returned 80004001 wmpformat.c:131: Test failed: GetFrame failed, hr=88982f04
=== debiant (32 bit WoW report) ===
d3dx10_43: d3dx10.c:1379: Test failed: Test 27: Got unexpected hr 0x80004005.
windowscodecs: wmpformat.c:111: Test failed: Initialize failed, hr=80004001 wmpformat.c:114: Test failed: Initialize returned 80004001 wmpformat.c:131: Test failed: GetFrame failed, hr=88982f04
=== debiant (64 bit WoW report) ===
d3dx10_43: d3dx10.c:1379: Test failed: Test 27: Got unexpected hr 0x80004005.
windowscodecs: wmpformat.c:111: Test failed: Initialize failed, hr=80004001 wmpformat.c:114: Test failed: Initialize returned 80004001 wmpformat.c:131: Test failed: GetFrame failed, hr=88982f04