Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v3: Use todo_wine win_skip instead of skip.
dlls/windowscodecs/tests/Makefile.in | 3 +- dlls/windowscodecs/tests/wmpformat.c | 179 +++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 dlls/windowscodecs/tests/wmpformat.c
diff --git a/dlls/windowscodecs/tests/Makefile.in b/dlls/windowscodecs/tests/Makefile.in index 315e975a09c..3d1e9e8a84e 100644 --- a/dlls/windowscodecs/tests/Makefile.in +++ b/dlls/windowscodecs/tests/Makefile.in @@ -15,4 +15,5 @@ C_SRCS = \ pngformat.c \ propertybag.c \ stream.c \ - tiffformat.c + tiffformat.c \ + wmpformat.c diff --git a/dlls/windowscodecs/tests/wmpformat.c b/dlls/windowscodecs/tests/wmpformat.c new file mode 100644 index 00000000000..b2a8d0fc7d6 --- /dev/null +++ b/dlls/windowscodecs/tests/wmpformat.c @@ -0,0 +1,179 @@ +/* + * 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 + */ + +#define COBJMACROS + +#include "objbase.h" +#include "wincodec.h" +#include "wine/test.h" + +/* generated with JxrEncApp -i image.bmp -o image.jxr -q 1 -c 22 */ +unsigned char wmp_imagedata[] = { + 0x49, 0x49, 0xbc, 0x01, 0x20, 0x00, 0x00, 0x00, 0x24, 0xc3, 0xdd, 0x6f, + 0x03, 0x4e, 0xfe, 0x4b, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x01, 0xbc, + 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0xbc, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbc, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x81, 0xbc, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x82, 0xbc, + 0x0b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x42, 0x83, 0xbc, + 0x0b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x42, 0xc0, 0xbc, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0xc1, 0xbc, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xc2, 0xbc, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, 0xc3, 0xbc, + 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x57, 0x4d, 0x50, 0x48, 0x4f, 0x54, 0x4f, 0x00, 0x11, 0x45, + 0xc0, 0x71, 0x00, 0x00, 0x00, 0x04, 0x60, 0x00, 0xc0, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x26, 0xff, 0xff, 0x00, 0x00, 0x01, 0x01, 0x51, 0x40, 0xc2, + 0x51, 0x88, 0x00, 0x00, 0x01, 0x02, 0x02, 0x10, 0x08, 0x62, 0x18, 0x84, + 0x21, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x18, 0x00, 0x00, 0x80, 0x40, 0x30, 0x00, 0x00, 0x00, 0x01, 0x03, 0x19, + 0x0d, 0x34, 0xd2, 0x77, 0x06, 0x62, 0xe8, 0x89, 0x8b, 0xa2, 0x26, 0x2f, + 0x11, 0xba, 0xbc, 0x46, 0xea, 0xa3, 0x6e, 0xdd, 0x72, 0x23, 0x75, 0x86, + 0xcd, 0x48, 0x73, 0xae, 0x43, 0xb9, 0x67, 0x8d, 0xfd, 0x98, 0xb0, 0xd5, + 0x52, 0x1d, 0xcb, 0x0d, 0x81, 0x06, 0xb4, 0x7d, 0xb8, 0x92, 0x5f, 0xf3, + 0x75, 0xc0, 0x3b, 0xd5, 0x07, 0xcb, 0xd0, 0xec, 0xde, 0x54, 0x1f, 0x7a, + 0x9a, 0x21, 0x8e, 0xcd, 0xe5, 0x4c, 0xdc, 0xce, 0xb8, 0x3e, 0xfa, 0x1d, + 0x8d, 0xca, 0x32, 0x94, 0xd2, 0x93, 0x2c, 0x76, 0x37, 0x2a, 0x63, 0x77, + 0x72, 0xd4, 0xd7, 0x66, 0x5a, 0xdb, 0x66, 0xed, 0x60, 0x00, 0x57, 0x4d, + 0x50, 0x48, 0x4f, 0x54, 0x4f, 0x00, 0x11, 0x45, 0xc0, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x80, 0x20, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x13, 0xff, 0xff, 0x00, 0x00, 0x01, 0x01, 0x91, 0xe2, 0x00, + 0x00, 0x01, 0x02, 0x00, 0x86, 0x00, 0x00, 0x20, 0x10, 0x0c, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x03, 0xad, 0xcf, 0xf4, 0x6b, 0x64, 0x45, 0xe1, 0x91, + 0x17, 0x8e, 0x9a, 0x51, 0x32, 0x1f, 0xe2, 0x02, 0xfa, 0x69, 0x44, 0x3b, + 0xfc, 0x7b, 0xab, 0x20, 0xfe, 0x9d, 0x35, 0xd4, 0xda, 0xb7, 0xcb, 0x77, + 0x5f, 0x4d, 0xe5, 0x0e, 0xee, 0x39, 0x97, 0x6f, 0xb9, 0x99, 0x6b, 0x6d, + 0xcc, 0xb9, 0x60}; + +static void test_decode(void) +{ + IWICBitmapDecoder *decoder; + IWICBitmapFrameDecode *framedecode; + IWICImagingFactory *factory; + IWICPalette *palette; + HRESULT hr; + HGLOBAL hwmpdata; + char *wmpdata; + IStream *wmpstream; + GUID format; + UINT count = 0, width = 0, height = 0; + BYTE imagedata[5 * 4] = {1}; + UINT i, j; + + const BYTE expected_imagedata[5 * 4] = { + 0x6d, 0xb0, 0xfc, 0x00, 0x6d, 0xb0, 0xfc, 0x00, 0x6d, 0xb0, + 0xfc, 0x00, 0x6d, 0xb0, 0xfc, 0x00, 0x6d, 0xb0, 0xfc, 0x00, + }; + + const BYTE broken_imagedata[5 * 4] = { + 0x74, 0xa2, 0xd6, 0x28, 0x73, 0xa1, 0xd4, 0x29, 0x71, 0xa9, + 0xe7, 0x16, 0x71, 0xa9, 0xe7, 0x16, 0x70, 0xa7, 0xe5, 0x17 + }; + + hr = CoCreateInstance(&CLSID_WICWmpDecoder, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICBitmapDecoder, (void **)&decoder); + if (FAILED(hr)) + { + todo_wine win_skip("WmpDecoder isn't available, skipping test\n"); + return; + } + + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICImagingFactory, (void **)&factory); + ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr); + + hwmpdata = GlobalAlloc(GMEM_MOVEABLE, sizeof(wmp_imagedata)); + ok(hwmpdata != 0, "GlobalAlloc failed\n"); + + wmpdata = GlobalLock(hwmpdata); + memcpy(wmpdata, wmp_imagedata, sizeof(wmp_imagedata)); + GlobalUnlock(hwmpdata); + + hr = CreateStreamOnHGlobal(hwmpdata, FALSE, &wmpstream); + ok(SUCCEEDED(hr), "CreateStreamOnHGlobal failed, hr=%x\n", hr); + + hr = IWICBitmapDecoder_Initialize(decoder, wmpstream, WICDecodeMetadataCacheOnLoad); + ok(hr == S_OK, "Initialize failed, hr=%x\n", hr); + + hr = IWICBitmapDecoder_GetContainerFormat(decoder, &format); + ok(SUCCEEDED(hr), "GetContainerFormat failed, hr=%x\n", hr); + ok(IsEqualGUID(&format, &GUID_ContainerFormatWmp), + "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); + + hr = IWICBitmapDecoder_GetFrame(decoder, 0, NULL); + ok(hr == E_INVALIDARG, "GetFrame(NULL) returned hr=%x\n", hr); + + for (j = 2; j > 0; --j) + { + hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode); + ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr); + + hr = IWICBitmapFrameDecode_GetSize(framedecode, &width, &height); + ok(SUCCEEDED(hr), "GetSize failed, hr=%x\n", hr); + ok(width == 1, "expected width=1, got %u\n", width); + ok(height == 5, "expected height=5, got %u\n", height); + + hr = IWICBitmapFrameDecode_GetPixelFormat(framedecode, &format); + ok(SUCCEEDED(hr), "GetPixelFormat failed, hr=%x\n", hr); + ok(IsEqualGUID(&format, &GUID_WICPixelFormat32bppBGRA), + "unexpected pixel format: %s\n", wine_dbgstr_guid(&format)); + + for (i = 2; i > 0; --i) + { + memset(imagedata, 0, sizeof(imagedata)); + hr = IWICBitmapFrameDecode_CopyPixels( + framedecode, NULL, 4, sizeof(imagedata), imagedata); + ok(SUCCEEDED(hr), "CopyPixels failed, hr=%x\n", hr); + ok(!memcmp(imagedata, expected_imagedata, sizeof(imagedata)) || + broken(!memcmp(imagedata, broken_imagedata, sizeof(imagedata)) /* w2008s64 */), + "unexpected image data\n"); + } + + hr = IWICImagingFactory_CreatePalette(factory, &palette); + ok(SUCCEEDED(hr), "CreatePalette failed, hr=%x\n", hr); + + hr = IWICBitmapDecoder_CopyPalette(decoder, palette); + ok(hr == WINCODEC_ERR_PALETTEUNAVAILABLE, "Unexpected hr %#x.\n", hr); + + hr = IWICBitmapFrameDecode_CopyPalette(framedecode, palette); + ok(hr == WINCODEC_ERR_PALETTEUNAVAILABLE, "Unexpected hr %#x.\n", hr); + + IWICPalette_Release(palette); + + IWICBitmapFrameDecode_Release(framedecode); + } + + IStream_Release(wmpstream); + GlobalFree(hwmpdata); + + IWICBitmapDecoder_Release(decoder); + IWICImagingFactory_Release(factory); +} + +START_TEST(wmpformat) +{ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + test_decode(); + + CoUninitialize(); +}
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windowscodecs/regsvr.c | 53 +++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+)
diff --git a/dlls/windowscodecs/regsvr.c b/dlls/windowscodecs/regsvr.c index 00be59c98f3..38c252c2760 100644 --- a/dlls/windowscodecs/regsvr.c +++ b/dlls/windowscodecs/regsvr.c @@ -1192,6 +1192,48 @@ static struct decoder_pattern const jpeg_patterns[] = { {0} };
+static const BYTE wmp_magic_v0[] = {0x49, 0x49, 0xbc, 0x00}; +static const BYTE wmp_magic_v1[] = {0x49, 0x49, 0xbc, 0x01}; + +static GUID const * const wmp_formats[] = { + &GUID_WICPixelFormat128bppRGBAFixedPoint, + &GUID_WICPixelFormat128bppRGBAFloat, + &GUID_WICPixelFormat128bppRGBFloat, + &GUID_WICPixelFormat16bppBGR555, + &GUID_WICPixelFormat16bppBGR565, + &GUID_WICPixelFormat16bppGray, + &GUID_WICPixelFormat16bppGrayFixedPoint, + &GUID_WICPixelFormat16bppGrayHalf, + &GUID_WICPixelFormat24bppBGR, + &GUID_WICPixelFormat24bppRGB, + &GUID_WICPixelFormat32bppBGR, + &GUID_WICPixelFormat32bppBGR101010, + &GUID_WICPixelFormat32bppBGRA, + &GUID_WICPixelFormat32bppCMYK, + &GUID_WICPixelFormat32bppGrayFixedPoint, + &GUID_WICPixelFormat32bppGrayFloat, + &GUID_WICPixelFormat32bppRGBE, + &GUID_WICPixelFormat40bppCMYKAlpha, + &GUID_WICPixelFormat48bppRGB, + &GUID_WICPixelFormat48bppRGBFixedPoint, + &GUID_WICPixelFormat48bppRGBHalf, + &GUID_WICPixelFormat64bppCMYK, + &GUID_WICPixelFormat64bppRGBA, + &GUID_WICPixelFormat64bppRGBAFixedPoint, + &GUID_WICPixelFormat64bppRGBAHalf, + &GUID_WICPixelFormat80bppCMYKAlpha, + &GUID_WICPixelFormat8bppGray, + &GUID_WICPixelFormat96bppRGBFixedPoint, + &GUID_WICPixelFormatBlackWhite, + NULL +}; + +static struct decoder_pattern const wmp_patterns[] = { + {4,0,wmp_magic_v0,mask_all,0}, + {4,0,wmp_magic_v1,mask_all,0}, + {0} +}; + static const BYTE png_magic[] = {137,80,78,71,13,10,26,10};
static GUID const * const png_formats[] = { @@ -1336,6 +1378,17 @@ static struct regsvr_decoder const decoder_list[] = { jpeg_formats, jpeg_patterns }, + { &CLSID_WICWmpDecoder, + "The Wine Project", + "JPEG-XR Decoder", + "1.0.0.0", + &GUID_VendorMicrosoft, + &GUID_ContainerFormatWmp, + "image/jxr", + ".jxr;.hdp;.wdp", + wmp_formats, + wmp_patterns + }, { &CLSID_WICPngDecoder, "The Wine Project", "PNG Decoder",
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- 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..3957a6dc283 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"); + 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)
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 20ae7577fa9..18dd06d65f2 100644 --- a/configure.ac +++ b/configure.ac @@ -60,6 +60,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]) @@ -1872,6 +1873,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/windowscodecs/tests/wmpformat.c | 15 +- dlls/wmphoto/Makefile.in | 2 +- dlls/wmphoto/main.c | 210 ++++++++++++++++++++++++++- 3 files changed, 221 insertions(+), 6 deletions(-)
diff --git a/dlls/windowscodecs/tests/wmpformat.c b/dlls/windowscodecs/tests/wmpformat.c index b2a8d0fc7d6..369f5d91488 100644 --- a/dlls/windowscodecs/tests/wmpformat.c +++ b/dlls/windowscodecs/tests/wmpformat.c @@ -108,7 +108,7 @@ static void test_decode(void) ok(SUCCEEDED(hr), "CreateStreamOnHGlobal failed, hr=%x\n", hr);
hr = IWICBitmapDecoder_Initialize(decoder, wmpstream, WICDecodeMetadataCacheOnLoad); - ok(hr == S_OK, "Initialize failed, hr=%x\n", hr); + todo_wine ok(hr == S_OK, "Initialize failed, hr=%x\n", hr);
hr = IWICBitmapDecoder_GetContainerFormat(decoder, &format); ok(SUCCEEDED(hr), "GetContainerFormat failed, hr=%x\n", hr); @@ -116,8 +116,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); @@ -125,7 +125,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); @@ -162,6 +168,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..b1a840ca28f 100644 --- a/dlls/wmphoto/Makefile.in +++ b/dlls/wmphoto/Makefile.in @@ -1,7 +1,7 @@ MODULE = wmphoto.dll IMPORTS = windowscodecs uuid kernelbase
-EXTRADLLFLAGS = -mno-cygwin +EXTRAINCL = $(JXRLIB_CFLAGS)
C_SRCS = main.c
diff --git a/dlls/wmphoto/main.c b/dlls/wmphoto/main.c index 3957a6dc283..82c9c0df769 100644 --- a/dlls/wmphoto/main.c +++ b/dlls/wmphoto/main.c @@ -17,6 +17,12 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#include "config.h" +#include "wine/port.h" + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif #include <stdarg.h> #include <stdio.h> #include <string.h> @@ -31,15 +37,205 @@ #include "wincodecsdk.h"
#include "wine/debug.h" +#include "wine/unicode.h"
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+#ifdef SONAME_LIBJXRGLUE + +static void *libjxrglue; + +struct wmp_decoder +{ + 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 = E_FAIL; + + TRACE("iface %p, stream %p, options %u.\n", iface, stream, options); + + EnterCriticalSection(&This->lock); + + seek.QuadPart = 0; + IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); + IStream_AddRef(stream); + This->stream = stream; + + 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 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; +} + +#else /* !defined(SONAME_LIBJXRGLUE) */ + static HRESULT wmp_decoder_create(IUnknown *outer, IUnknown **out) { - FIXME("outer %p, out %p, stub!\n"); + ERR("JPEG-XR support not compiled in!\n"); return E_NOTIMPL; }
+#endif + struct class_factory { IClassFactory IClassFactory_iface; @@ -117,9 +313,21 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_ATTACH: WMPHOTO_hInstance = hinstDLL; DisableThreadLibraryCalls(hinstDLL); +#ifdef SONAME_LIBJXRGLUE + if (!(libjxrglue = dlopen(SONAME_LIBJXRGLUE, RTLD_NOW))) + { + ERR("unable to load %s!\n", SONAME_LIBJXRGLUE); + return FALSE; + } +#endif break; case DLL_WINE_PREATTACH: return FALSE; /* prefer native version */ + case DLL_PROCESS_DETACH: +#ifdef SONAME_LIBJXRGLUE + dlclose(libjxrglue); +#endif + return TRUE; }
return TRUE;
Initialize should check whether a stream has already been set.
With only a single frame for now. The jxrlib decoder seems to have some quirks, and fails called multiple times, so decoding multiple frames will need a bit of investigation.
Hopefully it will not be required anytime soon.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v3: * Store the frame count and print the FIXME message on GetFrameCount as well.
* Add IWICBitmapSource interface support to wmp_decoder_frame.
dlls/windowscodecs/Makefile.in | 1 + dlls/windowscodecs/copy_pixels.c | 74 ++++++ dlls/windowscodecs/main.c | 65 ----- dlls/windowscodecs/tests/wmpformat.c | 15 +- dlls/wmphoto/Makefile.in | 5 +- dlls/wmphoto/main.c | 363 ++++++++++++++++++++++++++- 6 files changed, 442 insertions(+), 81 deletions(-) create mode 100644 dlls/windowscodecs/copy_pixels.c
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..fe19b16e90a --- /dev/null +++ b/dlls/windowscodecs/copy_pixels.c @@ -0,0 +1,74 @@ +#include "config.h" + +#include <stdarg.h> + +#include "wincodecs_private.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 369f5d91488..b2a8d0fc7d6 100644 --- a/dlls/windowscodecs/tests/wmpformat.c +++ b/dlls/windowscodecs/tests/wmpformat.c @@ -108,7 +108,7 @@ static void test_decode(void) ok(SUCCEEDED(hr), "CreateStreamOnHGlobal failed, hr=%x\n", hr);
hr = IWICBitmapDecoder_Initialize(decoder, wmpstream, WICDecodeMetadataCacheOnLoad); - todo_wine ok(hr == S_OK, "Initialize failed, hr=%x\n", hr); + ok(hr == S_OK, "Initialize failed, hr=%x\n", hr);
hr = IWICBitmapDecoder_GetContainerFormat(decoder, &format); ok(SUCCEEDED(hr), "GetContainerFormat failed, hr=%x\n", hr); @@ -116,8 +116,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); @@ -125,13 +125,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); - - if (FAILED(hr)) - { - skip("No frame returned, skipping tests\n"); - goto done; - } + ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr);
hr = IWICBitmapFrameDecode_GetSize(framedecode, &width, &height); ok(SUCCEEDED(hr), "GetSize failed, hr=%x\n", hr); @@ -168,7 +162,6 @@ 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 b1a840ca28f..18a4c191962 100644 --- a/dlls/wmphoto/Makefile.in +++ b/dlls/wmphoto/Makefile.in @@ -1,8 +1,11 @@ MODULE = wmphoto.dll IMPORTS = windowscodecs uuid kernelbase +PARENTSRC = ../windowscodecs
EXTRAINCL = $(JXRLIB_CFLAGS)
-C_SRCS = main.c +C_SRCS = \ + main.c \ + copy_pixels.c
IDL_SRCS = wmphoto.idl diff --git a/dlls/wmphoto/main.c b/dlls/wmphoto/main.c index 82c9c0df769..10d14e4bfbc 100644 --- a/dlls/wmphoto/main.c +++ b/dlls/wmphoto/main.c @@ -39,17 +39,251 @@ #include "wine/debug.h" #include "wine/unicode.h"
+#include "wincodecs_private.h" + +#ifdef SONAME_LIBJXRGLUE +#undef ERR +#define ERR JXR_ERR +#include <JXRGlue.h> +#undef ERR +#define ERR WINE_ERR +#endif + WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
#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_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 wmp_decoder_frame +{ + IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; + LONG ref; + WICPixelFormatGUID format; + UINT bpp; + UINT stride; + PKRect 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(PKImageDecode *decoder, UINT frame, IWICBitmapFrameDecode **out) +{ + struct wmp_decoder_frame *This; + + TRACE("decoder %p, frame %u, out %p.\n", decoder, frame, out); + + *out = NULL; + if (!(This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wmp_decoder_frame)))) + return E_OUTOFMEMORY; + + This->IWICBitmapFrameDecode_iface.lpVtbl = &wmp_decoder_frame_vtbl; + This->ref = 1; + + if (decoder->GetPixelFormat(decoder, &This->format)) goto done; + if (decoder->GetSize(decoder, &This->rect.Width, &This->rect.Height)) goto done; + if (decoder->GetResolution(decoder, &This->resx, &This->resy)) goto done; + + if (!(This->bpp = pixel_format_get_bpp(&This->format))) goto done; + This->stride = (This->rect.Width * This->bpp + 7) / 8; + if (!(This->image_data = HeapAlloc(GetProcessHeap(), 0, This->rect.Height * This->stride))) + goto done; + + if (decoder->Copy(decoder, &This->rect, This->image_data, This->stride)) + HeapFree(GetProcessHeap(), 0, This->image_data); + else + *out = &This->IWICBitmapFrameDecode_iface; + +done: + if (!*out) HeapFree(GetProcessHeap(), 0, This); + return *out ? S_OK : E_FAIL; +}
struct wmp_decoder { IWICBitmapDecoder IWICBitmapDecoder_iface; + IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; + struct WMPStream wmp_stream; LONG ref; IStream *stream; + PKImageDecode *decoder; + UINT frame_count; + IWICBitmapFrameDecode *frame; CRITICAL_SECTION lock; };
@@ -58,6 +292,87 @@ static inline struct wmp_decoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder return CONTAINING_RECORD(iface, struct wmp_decoder, IWICBitmapDecoder_iface); }
+static inline struct wmp_decoder *impl_from_WMPStream(struct WMPStream *iface) +{ + return CONTAINING_RECORD(iface, struct wmp_decoder, wmp_stream); +} + +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); + HRESULT hr; + ULONG count; + + TRACE("iface %p, buf %p, len %zx.\n", iface, buf, len); + + EnterCriticalSection(&This->lock); + hr = IStream_Read(This->stream, buf, len, &count); + LeaveCriticalSection(&This->lock); + + return FAILED(hr) ? WMP_errFail : 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); + HRESULT hr; + ULONG count; + + TRACE("iface %p, buf %p, len %zx.\n", iface, buf, len); + + EnterCriticalSection(&This->lock); + hr = IStream_Write(This->stream, buf, len, &count); + LeaveCriticalSection(&This->lock); + + return FAILED(hr) ? WMP_errFail : WMP_errSuccess; +} + +static JXR_ERR wmp_stream_SetPos(struct WMPStream *iface, size_t pos) +{ + struct wmp_decoder *This = impl_from_WMPStream(iface); + LARGE_INTEGER move; + HRESULT hr; + + TRACE("iface %p, pos %zx.\n", iface, pos); + + move.QuadPart = pos; + EnterCriticalSection(&This->lock); + hr = IStream_Seek(This->stream, move, STREAM_SEEK_SET, NULL); + LeaveCriticalSection(&This->lock); + + return FAILED(hr) ? WMP_errFail : WMP_errSuccess; +} + +static JXR_ERR wmp_stream_GetPos(struct WMPStream *iface, size_t *pos) +{ + struct wmp_decoder *This = impl_from_WMPStream(iface); + ULARGE_INTEGER curr; + LARGE_INTEGER move; + HRESULT hr; + + TRACE("iface %p, pos %p.\n", iface, pos); + + move.QuadPart = 0; + EnterCriticalSection(&This->lock); + hr = IStream_Seek(This->stream, move, STREAM_SEEK_CUR, &curr); + LeaveCriticalSection(&This->lock); + *pos = curr.QuadPart; + + return FAILED(hr) ? WMP_errFail : WMP_errSuccess; +} + static HRESULT WINAPI wmp_decoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, void **out) { struct wmp_decoder *This = impl_from_IWICBitmapDecoder(iface); @@ -93,6 +408,8 @@ 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->decoder) This->decoder->Release(&This->decoder); if (This->stream) IStream_Release(This->stream); HeapFree(GetProcessHeap(), 0, This); } @@ -121,6 +438,13 @@ static HRESULT WINAPI wmp_decoder_Initialize(IWICBitmapDecoder *iface, IStream * IStream_AddRef(stream); This->stream = stream;
+ if (!pPKImageDecode_Create_WMP(&This->decoder) && !This->decoder->Initialize(This->decoder, &This->wmp_stream)) + { + if (!This->decoder->GetFrameCount(This->decoder, &This->frame_count) && This->frame_count > 1) + FIXME("multi frame JPEG-XR not implemented\n"); + hr = S_OK; + } + LeaveCriticalSection(&This->lock); return hr; } @@ -172,18 +496,34 @@ static HRESULT WINAPI wmp_decoder_GetThumbnail(IWICBitmapDecoder *iface, IWICBit
static HRESULT WINAPI wmp_decoder_GetFrameCount(IWICBitmapDecoder *iface, UINT *count) { + struct wmp_decoder *This = impl_from_IWICBitmapDecoder(iface); + TRACE("iface %p, count %p.\n", iface, count); + if (!count) return E_INVALIDARG; - *count = 0; - return E_NOTIMPL; + if (This->frame_count > 1) FIXME("multi frame JPEG-XR not implemented\n"); + *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; + if (index >= 1) return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + if (This->frame) hr = S_OK; + else hr = wmp_decoder_frame_create(This->decoder, index, &This->frame); + if (This->frame) IWICBitmapFrameDecode_AddRef(This->frame); + *frame = This->frame; + LeaveCriticalSection(&This->lock); + + return hr; }
static const IWICBitmapDecoderVtbl wmp_decoder_vtbl = @@ -217,8 +557,17 @@ static HRESULT 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->wmp_stream.Close = wmp_stream_Close; + This->wmp_stream.EOS = wmp_stream_EOS; + This->wmp_stream.Read = wmp_stream_Read; + This->wmp_stream.Write = wmp_stream_Write; + This->wmp_stream.SetPos = wmp_stream_SetPos; + This->wmp_stream.GetPos = wmp_stream_GetPos; This->ref = 1; This->stream = NULL; + This->decoder = NULL; + This->frame = NULL; InitializeCriticalSection(&This->lock); This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wmp_decoder.lock");
@@ -319,6 +668,12 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) ERR("unable to load %s!\n", SONAME_LIBJXRGLUE); return FALSE; } + + if (!(pPKImageDecode_Create_WMP = dlsym(libjxrglue, "PKImageDecode_Create_WMP"))) + { + ERR("unable to find PKImageDecode_Create_WMP in %s!\n", SONAME_LIBJXRGLUE); + return FALSE; + } #endif break; case DLL_WINE_PREATTACH:
For some reason the test keeps giving me
0454:fixme:wincodecs:DllGetClassObject wmphoto: stub
But it succeeds anyway, which seems wrong.
Fixed my issue with the old dll being used and now I get this: d3dx10.c:1380: Test succeeded inside todo block: Test 27: Got unexpected hr 0.
It seems like wmp_stream_Read doesn't report the actual number of bytes read to the caller. How is it meant to report a short read?
I didn't realize you had a FIXME for multi-frame images elsewhere, we only need to report it once.
On 2020-09-21 21:57, Esme Povirk (they/them) wrote:
Fixed my issue with the old dll being used
Yeah it's a little bit annoying to have to delete the PE module, especially when editing the series or checking each patch. Maybe I should just remove the -no-cygwin flag first in the series.
and now I get this: d3dx10.c:1380: Test succeeded inside todo block: Test 27: Got unexpected hr 0.
It seems like wmp_stream_Read doesn't report the actual number of bytes read to the caller. How is it meant to report a short read?
I didn't know there were WMP tests elsewhere already, I'll have a look.
I didn't realize you had a FIXME for multi-frame images elsewhere, we only need to report it once.
Alright.