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 ---
v2: * Check for short reads in PATCH 3, and WARN in such case. Some jxrlib calls don't care about the returned value so ERR would be verbose.
* Add an ERR message when jxrlib support isn't compiled in.
Supersedes: 198075-198079 and 198035-198039
configure.ac | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/configure.ac b/configure.ac index 0f8b9f6c080..4f95a1325d4 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]) @@ -1829,6 +1830,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
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/wmphoto/Makefile.in | 11 +++- dlls/wmphoto/main.c | 133 ++++++++++++++++++++++++++++++++++++--- dlls/wmphoto/unix_lib.c | 107 +++++++++++++++++++++++++++++++ 3 files changed, 240 insertions(+), 11 deletions(-) create mode 100644 dlls/wmphoto/unix_lib.c
diff --git a/dlls/wmphoto/Makefile.in b/dlls/wmphoto/Makefile.in index 24e1f49496a..caaab56f758 100644 --- a/dlls/wmphoto/Makefile.in +++ b/dlls/wmphoto/Makefile.in @@ -1,7 +1,16 @@ MODULE = wmphoto.dll +IMPORTS = windowscodecs uuid ole32 oleaut32 propsys rpcrt4 shlwapi +PARENTSRC = ../windowscodecs
EXTRADLLFLAGS = -mno-cygwin +EXTRAINCL = $(JXRLIB_CFLAGS)
-C_SRCS = main.c +C_SRCS = \ + decoder.c \ + main.c \ + palette.c \ + unix_iface.c \ + unix_lib.c \ + wincodecs_common.c
IDL_SRCS = wmphoto.idl diff --git a/dlls/wmphoto/main.c b/dlls/wmphoto/main.c index d3a926e7704..9477df4a1cf 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,25 +18,127 @@ */
#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <setjmp.h> + +#define COBJMACROS
#include "windef.h" #include "winbase.h" +#include "winternl.h" #include "objbase.h" #include "rpcproxy.h" +#include "wincodecsdk.h"
+#include "wincodecs_private.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
-static HINSTANCE WMPHOTO_hInstance; +HRESULT create_instance(const CLSID *clsid, const IID *iid, void **ppv) +{ + return CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, ppv); +} + +HRESULT get_decoder_info(REFCLSID clsid, IWICBitmapDecoderInfo **info) +{ + IWICImagingFactory* factory; + IWICComponentInfo *compinfo; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICImagingFactory, (void **)&factory); + if (FAILED(hr)) + return hr; + + hr = IWICImagingFactory_CreateComponentInfo(factory, clsid, &compinfo); + if (FAILED(hr)) + { + IWICImagingFactory_Release(factory); + return hr; + } + + hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo, + (void **)info); + + IWICComponentInfo_Release(compinfo); + IWICImagingFactory_Release(factory); + return hr; +} + +struct class_factory +{ + IClassFactory IClassFactory_iface; +}; + +static HRESULT WINAPI wmp_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 wmp_class_factory_AddRef(IClassFactory *iface) { return 2; }
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +static ULONG WINAPI wmp_class_factory_Release(IClassFactory *iface) { return 1; } + +static HRESULT WINAPI wmp_class_factory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **out) +{ + struct decoder_info decoder_info; + struct decoder *decoder; + HRESULT hr; + + TRACE("iface %p, outer %p, iid %s, out %p.\n", iface, outer, debugstr_guid(iid), out); + + *out = NULL; + if (outer) return CLASS_E_NOAGGREGATION; + + hr = get_unix_decoder(&CLSID_WICWmpDecoder, &decoder_info, &decoder); + + if (SUCCEEDED(hr)) + hr = CommonDecoder_CreateInstance(decoder, &decoder_info, iid, out); + + return hr; +} + +static HRESULT WINAPI wmp_class_factory_LockServer(IClassFactory *iface, BOOL lock) +{ + FIXME("iface %p, lock %d, stub!\n", iface, lock); + return S_OK; +} + +static const IClassFactoryVtbl wmp_class_factory_vtbl = +{ + wmp_class_factory_QueryInterface, + wmp_class_factory_AddRef, + wmp_class_factory_Release, + wmp_class_factory_CreateInstance, + wmp_class_factory_LockServer, +}; + +static struct class_factory wmp_class_factory = {{&wmp_class_factory_vtbl}}; + +HMODULE windowscodecs_module = 0; + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { - switch (fdwReason) + TRACE("instance %p, reason %d, reserved %p\n", instance, reason, reserved); + + switch (reason) { case DLL_PROCESS_ATTACH: - WMPHOTO_hInstance = hinstDLL; - DisableThreadLibraryCalls(hinstDLL); + windowscodecs_module = instance; + DisableThreadLibraryCalls(instance); break; case DLL_WINE_PREATTACH: return FALSE; /* prefer native version */ @@ -49,18 +152,28 @@ 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_class_factory; + 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) { - return __wine_register_resources( WMPHOTO_hInstance ); + return __wine_register_resources( windowscodecs_module ); }
HRESULT WINAPI DllUnregisterServer(void) { - return __wine_unregister_resources( WMPHOTO_hInstance ); + return __wine_unregister_resources( windowscodecs_module ); } diff --git a/dlls/wmphoto/unix_lib.c b/dlls/wmphoto/unix_lib.c new file mode 100644 index 00000000000..d8108bfc584 --- /dev/null +++ b/dlls/wmphoto/unix_lib.c @@ -0,0 +1,107 @@ +/* + * unix_lib.c - This is the Unix side of the Unix interface. + * + * Copyright 2020 Esme Povirk + * 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 <stdarg.h> + +#define NONAMELESSUNION + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" +#include "winbase.h" +#include "objbase.h" + +#include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + +#include "wincodecs_common.h" + +static const struct win32_funcs *win32_funcs; + +HRESULT CDECL stream_getsize(IStream *stream, ULONGLONG *size) +{ + return win32_funcs->stream_getsize(stream, size); +} + +HRESULT CDECL stream_read(IStream *stream, void *buffer, ULONG read, ULONG *bytes_read) +{ + return win32_funcs->stream_read(stream, buffer, read, bytes_read); +} + +HRESULT CDECL stream_seek(IStream *stream, LONGLONG ofs, DWORD origin, ULONGLONG *new_position) +{ + return win32_funcs->stream_seek(stream, ofs, origin, new_position); +} + +HRESULT CDECL stream_write(IStream *stream, const void *buffer, ULONG write, ULONG *bytes_written) +{ + return win32_funcs->stream_write(stream, buffer, write, bytes_written); +} + +HRESULT CDECL decoder_create(const CLSID *decoder_clsid, struct decoder_info *info, struct decoder **result) +{ + FIXME("decoder_clsid %s, info %p, result %p, stub!\n", debugstr_guid(decoder_clsid), info, result); + return E_NOTIMPL; +} + +HRESULT CDECL encoder_create(const CLSID *encoder_clsid, struct encoder_info *info, struct encoder **result) +{ + FIXME("encoder_clsid %s, info %p, result %p, stub!\n", debugstr_guid(encoder_clsid), info, result); + return E_NOTIMPL; +} + +static const struct unix_funcs unix_funcs = { + decoder_create, + decoder_initialize, + decoder_get_frame_info, + decoder_copy_pixels, + decoder_get_metadata_blocks, + decoder_get_color_context, + decoder_destroy, + encoder_create, + encoder_initialize, + encoder_get_supported_format, + encoder_create_frame, + encoder_write_lines, + encoder_commit_frame, + encoder_commit_file, + encoder_destroy +}; + +NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out ) +{ + if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS; + + win32_funcs = ptr_in; + + *(const struct unix_funcs **)ptr_out = &unix_funcs; + return STATUS_SUCCESS; +}
We shouldn't need palette.c for this.
I'm also not a fan of duplicating all of unix_lib.c. I was thinking we could just have an ifdef for decoder_create/encoder_create.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/d3dx10_43/tests/d3dx10.c | 7 +- dlls/windowscodecs/tests/wmpformat.c | 4 +- dlls/wmphoto/unix_lib.c | 381 ++++++++++++++++++++++++++- 3 files changed, 383 insertions(+), 9 deletions(-)
diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c index c8a1f9d7f71..b0800d26407 100644 --- a/dlls/d3dx10_43/tests/d3dx10.c +++ b/dlls/d3dx10_43/tests/d3dx10.c @@ -1531,8 +1531,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__); @@ -1552,13 +1551,11 @@ static void test_get_image_info(void) create_file(test_filename, test_image[i].data, test_image[i].size, path);
hr = D3DX10GetImageInfoFromFileW(path, 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); if (hr == S_OK) check_image_info(&image_info, i, __LINE__);
hr = D3DX10GetImageInfoFromFileA(get_str_a(path), 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); if (hr == S_OK) check_image_info(&image_info, i, __LINE__); @@ -1583,13 +1580,11 @@ static void test_get_image_info(void) resource_module = create_resource_module(test_resource_name, test_image[i].data, test_image[i].size);
hr = D3DX10GetImageInfoFromResourceW(resource_module, test_resource_name, 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); if (hr == S_OK) check_image_info(&image_info, i, __LINE__);
hr = D3DX10GetImageInfoFromResourceA(resource_module, get_str_a(test_resource_name), 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); if (hr == S_OK) check_image_info(&image_info, i, __LINE__); diff --git a/dlls/windowscodecs/tests/wmpformat.c b/dlls/windowscodecs/tests/wmpformat.c index 2e2809701f6..c4f947d8acf 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; }
@@ -123,7 +123,7 @@ static void test_decode(void) 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); + todo_wine ok(hr == E_INVALIDARG, "GetFrame(NULL) returned hr=%x\n", hr);
for (j = 2; j > 0; --j) { diff --git a/dlls/wmphoto/unix_lib.c b/dlls/wmphoto/unix_lib.c index d8108bfc584..4ac3693505d 100644 --- a/dlls/wmphoto/unix_lib.c +++ b/dlls/wmphoto/unix_lib.c @@ -37,6 +37,14 @@ #include "winbase.h" #include "objbase.h"
+#include "initguid.h" + +#ifdef SONAME_LIBJXRGLUE +#define ERR JXR_ERR +#include <JXRGlue.h> +#undef ERR +#endif + #include "wincodecs_private.h" #include "wine/debug.h"
@@ -44,6 +52,358 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
#include "wincodecs_common.h"
+#ifdef SONAME_LIBJXRGLUE +static void *libjxrglue; +static typeof(PKImageDecode_Create_WMP) *pPKImageDecode_Create_WMP; + +static const struct +{ + const WICPixelFormatGUID *format; + UINT bpp; +} pixel_format_bpp[] = +{ + {&GUID_PKPixelFormat128bppRGBAFixedPoint, 128}, + {&GUID_PKPixelFormat128bppRGBAFloat, 128}, + {&GUID_PKPixelFormat128bppRGBFloat, 128}, + {&GUID_PKPixelFormat16bppRGB555, 16}, + {&GUID_PKPixelFormat16bppRGB565, 16}, + {&GUID_PKPixelFormat16bppGray, 16}, + {&GUID_PKPixelFormat16bppGrayFixedPoint, 16}, + {&GUID_PKPixelFormat16bppGrayHalf, 16}, + {&GUID_PKPixelFormat24bppBGR, 24}, + {&GUID_PKPixelFormat24bppRGB, 24}, + {&GUID_PKPixelFormat32bppBGR, 32}, + {&GUID_PKPixelFormat32bppRGB101010, 32}, + {&GUID_PKPixelFormat32bppBGRA, 32}, + {&GUID_PKPixelFormat32bppCMYK, 32}, + {&GUID_PKPixelFormat32bppGrayFixedPoint, 32}, + {&GUID_PKPixelFormat32bppGrayFloat, 32}, + {&GUID_PKPixelFormat32bppRGBE, 32}, + {&GUID_PKPixelFormat40bppCMYKAlpha, 40}, + {&GUID_PKPixelFormat48bppRGB, 48}, + {&GUID_PKPixelFormat48bppRGBFixedPoint, 48}, + {&GUID_PKPixelFormat48bppRGBHalf, 48}, + {&GUID_PKPixelFormat64bppCMYK, 64}, + {&GUID_PKPixelFormat64bppRGBA, 64}, + {&GUID_PKPixelFormat64bppRGBAFixedPoint, 64}, + {&GUID_PKPixelFormat64bppRGBAHalf, 64}, + {&GUID_PKPixelFormat80bppCMYKAlpha, 80}, + {&GUID_PKPixelFormat8bppGray, 8}, + {&GUID_PKPixelFormat96bppRGBFixedPoint, 96}, + {&GUID_PKPixelFormatBlackWhite, 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 wmp_decoder +{ + struct decoder decoder_iface; + struct WMPStream WMPStream_iface; + PKImageDecode *decoder; + IStream *stream; + struct decoder_frame frame; + UINT frame_stride; + BYTE *frame_data; +}; + +static inline struct wmp_decoder *impl_from_decoder(struct decoder *iface) +{ + return CONTAINING_RECORD(iface, struct wmp_decoder, decoder_iface); +} + +static inline struct wmp_decoder *impl_from_WMPStream(struct WMPStream *iface) +{ + return CONTAINING_RECORD(iface, struct wmp_decoder, 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 wmp_decoder *This = impl_from_WMPStream(iface); + ULONG count; + if (FAILED(stream_read(This->stream, buf, len, &count)) || count != len) + { + WARN("Failed to read data!\n"); + return WMP_errFileIO; + } + return WMP_errSuccess; +} + +static JXR_ERR wmp_stream_Write(struct WMPStream *iface, const void *buf, size_t len) +{ + struct wmp_decoder *This = impl_from_WMPStream(iface); + ULONG count; + if (FAILED(stream_write(This->stream, buf, len, &count)) || count != len) + { + WARN("Failed to write data!\n"); + return WMP_errFileIO; + } + return WMP_errSuccess; +} + +static JXR_ERR wmp_stream_SetPos(struct WMPStream *iface, size_t pos) +{ + struct wmp_decoder *This = impl_from_WMPStream(iface); + if (FAILED(stream_seek(This->stream, pos, STREAM_SEEK_SET, NULL))) + { + WARN("Failed to set stream pos!\n"); + return WMP_errFileIO; + } + return WMP_errSuccess; +} + +static JXR_ERR wmp_stream_GetPos(struct WMPStream *iface, size_t *pos) +{ + struct wmp_decoder *This = impl_from_WMPStream(iface); + ULONGLONG ofs; + if (FAILED(stream_seek(This->stream, 0, STREAM_SEEK_CUR, &ofs))) + { + WARN("Failed to get stream pos!\n"); + return WMP_errFileIO; + } + *pos = ofs; + return WMP_errSuccess; +} + +HRESULT CDECL wmp_decoder_initialize(struct decoder *iface, IStream *stream, struct decoder_stat *st) +{ + struct wmp_decoder *This = impl_from_decoder(iface); + HRESULT hr; + Float dpix, dpiy; + I32 width, height; + U32 count; + + TRACE("iface %p, stream %p, st %p\n", iface, stream, st); + + if (This->stream) + return WINCODEC_ERR_WRONGSTATE; + + This->stream = stream; + if (FAILED(hr = stream_seek(This->stream, 0, STREAM_SEEK_SET, NULL))) + return hr; + if (This->decoder->Initialize(This->decoder, &This->WMPStream_iface)) + { + ERR("Failed to initialize jxrlib decoder!\n"); + return E_FAIL; + } + + if (This->decoder->GetFrameCount(This->decoder, &st->frame_count)) + { + ERR("Failed to get frame count!\n"); + return E_FAIL; + } + + if (st->frame_count > 1) FIXME("multi frame JPEG-XR not implemented\n"); + st->frame_count = 1; + st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages | + WICBitmapDecoderCapabilityCanDecodeSomeImages | + WICBitmapDecoderCapabilityCanEnumerateMetadata; + + if (This->decoder->SelectFrame(This->decoder, 0)) + { + ERR("Failed to select frame 0!\n"); + return E_FAIL; + } + if (This->decoder->GetPixelFormat(This->decoder, &This->frame.pixel_format)) + { + ERR("Failed to get frame pixel format!\n"); + return E_FAIL; + } + if (This->decoder->GetSize(This->decoder, &width, &height)) + { + ERR("Failed to get frame size!\n"); + return E_FAIL; + } + if (This->decoder->GetResolution(This->decoder, &dpix, &dpiy)) + { + ERR("Failed to get frame resolution!\n"); + return E_FAIL; + } + if (This->decoder->GetColorContext(This->decoder, NULL, &count)) + { + ERR("Failed to get frame color context size!\n"); + return E_FAIL; + } + + if (!(This->frame.bpp = pixel_format_get_bpp(&This->frame.pixel_format))) return E_FAIL; + This->frame.width = width; + This->frame.height = height; + This->frame.dpix = dpix; + This->frame.dpiy = dpiy; + This->frame.num_colors = 0; + if (count) This->frame.num_color_contexts = 1; + else This->frame.num_color_contexts = 0; + + return S_OK; +} + +HRESULT CDECL wmp_decoder_get_frame_info(struct decoder *iface, UINT frame, struct decoder_frame *info) +{ + struct wmp_decoder *This = impl_from_decoder(iface); + + TRACE("iface %p, frame %d, info %p\n", iface, frame, info); + + if (frame > 0) + { + FIXME("multi frame JPEG-XR not implemented\n"); + return E_NOTIMPL; + } + + *info = This->frame; + return S_OK; +} + +HRESULT CDECL wmp_decoder_copy_pixels(struct decoder *iface, UINT frame, const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer) +{ + struct wmp_decoder *This = impl_from_decoder(iface); + PKRect pkrect; + U8 *frame_data; + + TRACE("iface %p, frame %d, rect %p, stride %d, buffersize %d, buffer %p\n", iface, frame, prc, stride, buffersize, buffer); + + if (frame > 0) + { + FIXME("multi frame JPEG-XR not implemented\n"); + return E_NOTIMPL; + } + + if (!This->frame_data) + { + pkrect.X = 0; + pkrect.Y = 0; + pkrect.Width = This->frame.width; + pkrect.Height = This->frame.height; + This->frame_stride = (This->frame.width * This->frame.bpp + 7) / 8; + if (!(frame_data = RtlAllocateHeap(GetProcessHeap(), 0, This->frame.height * This->frame_stride))) + return E_FAIL; + if (This->decoder->Copy(This->decoder, &pkrect, frame_data, stride)) + { + ERR("Failed to copy frame data!\n"); + RtlFreeHeap(GetProcessHeap(), 0, frame_data); + return E_FAIL; + } + + This->frame_data = frame_data; + } + + return copy_pixels(This->frame.bpp, This->frame_data, + This->frame.width, This->frame.height, This->frame_stride, + prc, stride, buffersize, buffer); +} + +HRESULT CDECL wmp_decoder_get_metadata_blocks(struct decoder* iface, UINT frame, UINT *count, struct decoder_block **blocks) +{ + TRACE("iface %p, frame %d, count %p, blocks %p\n", iface, frame, count, blocks); + + *count = 0; + *blocks = NULL; + return S_OK; +} + +HRESULT CDECL wmp_decoder_get_color_context(struct decoder* iface, UINT frame, UINT num, BYTE **data, DWORD *datasize) +{ + struct wmp_decoder *This = impl_from_decoder(iface); + U32 count; + U8 *bytes; + + TRACE("iface %p, frame %d, num %u, data %p, datasize %p\n", iface, frame, num, data, datasize); + + *datasize = 0; + *data = NULL; + + if (This->decoder->GetColorContext(This->decoder, NULL, &count)) + { + ERR("Failed to get frame color context size!\n"); + return E_FAIL; + } + *datasize = count; + + bytes = RtlAllocateHeap(GetProcessHeap(), 0, count); + if (!bytes) + return E_OUTOFMEMORY; + + if (This->decoder->GetColorContext(This->decoder, bytes, &count)) + { + ERR("Failed to get frame color context!\n"); + RtlFreeHeap(GetProcessHeap(), 0, bytes); + return E_FAIL; + } + + *data = bytes; + return S_OK; +} + +void CDECL wmp_decoder_destroy(struct decoder* iface) +{ + struct wmp_decoder *This = impl_from_decoder(iface); + + TRACE("iface %p\n", iface); + + This->decoder->Release(&This->decoder); + RtlFreeHeap(GetProcessHeap(), 0, This->frame_data); + RtlFreeHeap(GetProcessHeap(), 0, This); +} + +static const struct decoder_funcs wmp_decoder_vtable = { + wmp_decoder_initialize, + wmp_decoder_get_frame_info, + wmp_decoder_copy_pixels, + wmp_decoder_get_metadata_blocks, + wmp_decoder_get_color_context, + wmp_decoder_destroy +}; + +HRESULT CDECL wmp_decoder_create(struct decoder_info *info, struct decoder **result) +{ + struct wmp_decoder *This; + PKImageDecode *decoder; + + if (!pPKImageDecode_Create_WMP || pPKImageDecode_Create_WMP(&decoder)) return E_FAIL; + This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This)); + if (!This) + return E_OUTOFMEMORY; + + This->decoder_iface.vtable = &wmp_decoder_vtable; + 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; + memset(&This->frame, 0, sizeof(This->frame)); + This->frame_stride = 0; + This->frame_data = NULL; + + *result = &This->decoder_iface; + + info->container_format = GUID_ContainerFormatWmp; + info->block_format = GUID_ContainerFormatWmp; + info->clsid = CLSID_WICWmpDecoder; + + return S_OK; +} +#endif + static const struct win32_funcs *win32_funcs;
HRESULT CDECL stream_getsize(IStream *stream, ULONGLONG *size) @@ -68,7 +428,17 @@ HRESULT CDECL stream_write(IStream *stream, const void *buffer, ULONG write, ULO
HRESULT CDECL decoder_create(const CLSID *decoder_clsid, struct decoder_info *info, struct decoder **result) { - FIXME("decoder_clsid %s, info %p, result %p, stub!\n", debugstr_guid(decoder_clsid), info, result); + if (IsEqualGUID(decoder_clsid, &CLSID_WICWmpDecoder)) +#ifdef SONAME_LIBJXRGLUE + return wmp_decoder_create(info, result); +#else + { + WARN("jxrlib support not compiled in, returning E_NOINTERFACE.\n"); + return E_NOINTERFACE; + } +#endif + + FIXME("encoder_clsid %s, info %p, result %p, stub!\n", debugstr_guid(decoder_clsid), info, result); return E_NOTIMPL; }
@@ -102,6 +472,15 @@ NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *p
win32_funcs = ptr_in;
+#ifdef SONAME_LIBJXRGLUE + if (!(libjxrglue = dlopen(SONAME_LIBJXRGLUE, RTLD_NOW))) + ERR("failed to load %s\n", SONAME_LIBJXRGLUE); + else if (!(pPKImageDecode_Create_WMP = dlsym(libjxrglue, "PKImageDecode_Create_WMP"))) + ERR("unable to find PKImageDecode_Create_WMP in %s!\n", SONAME_LIBJXRGLUE); +#else + ERR("jxrlib support not compiled in!\n"); +#endif + *(const struct unix_funcs **)ptr_out = &unix_funcs; return STATUS_SUCCESS; }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windowscodecs/decoder.c | 2 +- dlls/windowscodecs/tests/wmpformat.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/windowscodecs/decoder.c b/dlls/windowscodecs/decoder.c index b0fcd34c742..89e352b8946 100644 --- a/dlls/windowscodecs/decoder.c +++ b/dlls/windowscodecs/decoder.c @@ -724,7 +724,7 @@ static HRESULT WINAPI CommonDecoder_GetFrame(IWICBitmapDecoder *iface, TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
if (!ppIBitmapFrame) - return E_POINTER; + return E_INVALIDARG;
EnterCriticalSection(&This->lock);
diff --git a/dlls/windowscodecs/tests/wmpformat.c b/dlls/windowscodecs/tests/wmpformat.c index c4f947d8acf..c1a320b6ec0 100644 --- a/dlls/windowscodecs/tests/wmpformat.c +++ b/dlls/windowscodecs/tests/wmpformat.c @@ -123,7 +123,7 @@ static void test_decode(void) ok(count == 1, "unexpected count %u\n", count);
hr = IWICBitmapDecoder_GetFrame(decoder, 0, NULL); - todo_wine ok(hr == E_INVALIDARG, "GetFrame(NULL) returned hr=%x\n", hr); + ok(hr == E_INVALIDARG, "GetFrame(NULL) returned hr=%x\n", hr);
for (j = 2; j > 0; --j) {
On Thu, 28 Jan 2021, Rémi Bernon wrote: [...]
It is available for most Linux distributions already, and is also an optional dependency for imagemagick, freeimage or calibre:
Actually openSUSE (Leap 15.2 and Tumbleweed) and Arch (Manjaro, etc. as of today) don't have the 32-bit library :-( Hopefully they will fix that.
RHEL 8 seems to have neither the 32- nor the 64-bit version. That's not entirely unexpected: it tends to be lacking in the multimedia department. Savvy users may be able to grab a package from RPMFind or Fedora.
Debian (Ubuntu, Mint, etc.) and Fedora appear to be ok.
None of that is meant to be held against the patchset.