Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v5: First 3 patches didn't change but I rewrote the end of the series to use the new unix lib mechanism instead of going back to ELF builtin DLL for wmphoto, and address some other issues.
dlls/windowscodecs/tests/Makefile.in | 3 +- dlls/windowscodecs/tests/wmpformat.c | 182 +++++++++++++++++++++++++++ 2 files changed, 184 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..2e2809701f6 --- /dev/null +++ b/dlls/windowscodecs/tests/wmpformat.c @@ -0,0 +1,182 @@ +/* + * 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_Initialize(decoder, wmpstream, WICDecodeMetadataCacheOnLoad); + ok(hr == WINCODEC_ERR_WRONGSTATE, "Initialize returned %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..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 ---
v5: Moved this patch ahead, as it doesn't depend on jxrlib. We now always succeed in creating WmpDecoder, but it will then possibly fail to initialize if jxrlib wasn't enabled.
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 cb9fc47f459..91834327ce7 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]) @@ -1852,6 +1853,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
Hi Remi,
You should merge the Patch 5 and 6 of this series into a single patch.
Thanks, Vijay
On Thu, Sep 24, 2020 at 10:16 PM Rémi Bernon rbernon@codeweavers.com wrote:
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:
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 cb9fc47f459..91834327ce7 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]) @@ -1852,6 +1853,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 -- 2.28.0
On 2020-09-24 22:27, Vijay Kiran Kamuju wrote:
Hi Remi,
You should merge the Patch 5 and 6 of this series into a single patch.
Thanks, Vijay
Is there a specific reason why I should? The last patch is already pretty big and I think the unix lib introduction that loads jxrlib or fails is a possible functional change and source of regression on its own.
I don't really mind but it could also very well be merged with PATH 5/7 which doesn't really add any feature either. Plus it's already v5 and I'm starting to feel like I'm spamming the list a bit with these patches.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v5: This is a new patch that bootstraps the unix library side for wmphoto. We call __wine_init_unix_lib in DllMain, and it may fail if JPEG-XR support was compiled in but jxrlib cannot be loaded for some reason, preventing the wmphoto dll to load.
If JPEG-XR support was not compiled in, we always succeed loading the DLL but it will then fail to actually initialize decoders.
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 ---
v5: Move part of the implementation to the unix side, mostly the WMPStream to IStream bridge. The unix interface follows the jxrlib decoder interface otherwise, with a few adaptations to make it simpler to use. This should make it fairly easy to move to a full PE build if we want/need it at some point.
Don't keep reference on jxrlib decoder anymore, create one on Initialize to get the frame count, and on frame request to decode the frame, then release it as soon as it's not needed.
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 | 195 +++++++++++++++++++ dlls/wmphoto/main.c | 275 ++++++++++++++++++++++++++- dlls/wmphoto/wmphoto_private.h | 16 ++ 9 files changed, 578 insertions(+), 74 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..b5f24e46c2e 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,190 @@ 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; + PKImageDecode *decoder; + IStream *stream; +}; + +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); + ULONG count; + + TRACE("iface %p, buf %p, len %zx.\n", iface, buf, len); + + if (FAILED(IStream_Read(This->stream, buf, len, &count)) || count < len) return WMP_errFileIO; + return WMP_errSuccess; +} + +static JXR_ERR wmp_stream_Write(struct WMPStream *iface, const void *buf, size_t len) +{ + struct decoder_proxy *This = impl_from_WMPStream(iface); + ULONG count; + + TRACE("iface %p, buf %p, len %zx.\n", iface, buf, len); + + if (FAILED(IStream_Write(This->stream, buf, len, &count)) || count < len) return WMP_errFileIO; + return WMP_errSuccess; +} + +static JXR_ERR wmp_stream_SetPos(struct WMPStream *iface, size_t pos) +{ + struct decoder_proxy *This = impl_from_WMPStream(iface); + LARGE_INTEGER move; + + TRACE("iface %p, pos %zx.\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 wmp_stream_GetPos(struct WMPStream *iface, size_t *pos) +{ + struct decoder_proxy *This = impl_from_WMPStream(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 JXR_ERR CDECL decoder_Initialize(struct jxrlib_decoder *iface, IStream *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 +250,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..4fe3714a6da 100644 --- a/dlls/wmphoto/main.c +++ b/dlls/wmphoto/main.c @@ -39,11 +39,252 @@ 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 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 *decoder = NULL; + LARGE_INTEGER seek; + HRESULT hr; + + TRACE("stream %p, frame %u, out %p.\n", stream, frame, out); + + *out = NULL; + seek.QuadPart = 0; + if (FAILED(hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL))) goto failed; + if (FAILED(hr = jxrlib_funcs->decoder_create(&decoder))) goto failed; + + hr = E_FAIL; + if (decoder->Initialize(decoder, stream)) goto failed; + if (decoder->SelectFrame(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 (decoder->GetPixelFormat(decoder, &This->format)) goto failed; + if (decoder->GetSize(decoder, &This->rect.Width, &This->rect.Height)) goto failed; + if (decoder->GetResolution(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 (decoder->Copy(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 (decoder) decoder->Release(&decoder); + 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 +328,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,6 +345,7 @@ 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); + struct jxrlib_decoder *decoder = NULL; LARGE_INTEGER seek; HRESULT hr;
@@ -115,6 +358,12 @@ static HRESULT WINAPI wmp_decoder_Initialize(IWICBitmapDecoder *iface, IStream * { seek.QuadPart = 0; if (FAILED(hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL))) goto done; + if (FAILED(hr = jxrlib_funcs->decoder_create(&decoder))) goto done; + + hr = E_FAIL; + if (decoder->Initialize(decoder, stream)) goto done; + if (decoder->GetFrameCount(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 +371,7 @@ static HRESULT WINAPI wmp_decoder_Initialize(IWICBitmapDecoder *iface, IStream * }
done: + if (decoder) decoder->Release(&decoder); LeaveCriticalSection(&This->lock); return hr; } @@ -175,16 +425,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 +483,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..a2148b6c13b 100644 --- a/dlls/wmphoto/wmphoto_private.h +++ b/dlls/wmphoto/wmphoto_private.h @@ -23,9 +23,25 @@
#include "windef.h" #include "winbase.h" +#include "wincodecsdk.h" + +typedef long JXR_ERR; + +struct jxrlib_decoder +{ + JXR_ERR (CDECL *Initialize)(struct jxrlib_decoder *iface, IStream *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=79296
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
Are unix parts allowed to call into Windows code for the IStream methods?
Please ignore 193344 and 193346 (PATCH 1/7 and PATCH 2/7), they got committed already.
Thanks!
On 2020-09-24 23:05, Rémi Bernon wrote:
Please ignore 193344 and 193346 (PATCH 1/7 and PATCH 2/7), they got committed already.
Thanks!
FWIW, this series supersedes 193211-193214 and 193043-193048 (which were already supposed to be).