[PATCH 4/4] wmphoto: Implement WMP decoder using jxrlib.

Rémi Bernon rbernon at codeweavers.com
Fri Jan 15 05:07:15 CST 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/d3dx10_43/tests/d3dx10.c        |   7 +-
 dlls/windowscodecs/tests/wmpformat.c |   4 +-
 dlls/wmphoto/Makefile.in             |   7 +-
 dlls/wmphoto/main.c                  |  37 ++-
 dlls/wmphoto/unix_lib.c              | 341 ++++++++++++++++++++++++++-
 5 files changed, 384 insertions(+), 12 deletions(-)

diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c
index c8a1f9d7f71..b0800d26407 100644
--- a/dlls/d3dx10_43/tests/d3dx10.c
+++ b/dlls/d3dx10_43/tests/d3dx10.c
@@ -1531,8 +1531,7 @@ static void test_get_image_info(void)
     for (i = 0; i < ARRAY_SIZE(test_image); ++i)
     {
         hr = D3DX10GetImageInfoFromMemory(test_image[i].data, test_image[i].size, NULL, &image_info, NULL);
-        todo_wine_if(test_image[i].expected.ImageFileFormat == D3DX10_IFF_WMP)
-            ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+        ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
         if (hr != S_OK)
             continue;
         check_image_info(&image_info, i, __LINE__);
@@ -1552,13 +1551,11 @@ static void test_get_image_info(void)
         create_file(test_filename, test_image[i].data, test_image[i].size, path);
 
         hr = D3DX10GetImageInfoFromFileW(path, NULL, &image_info, NULL);
-        todo_wine_if(test_image[i].expected.ImageFileFormat == D3DX10_IFF_WMP)
         ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
         if (hr == S_OK)
             check_image_info(&image_info, i, __LINE__);
 
         hr = D3DX10GetImageInfoFromFileA(get_str_a(path), NULL, &image_info, NULL);
-        todo_wine_if(test_image[i].expected.ImageFileFormat == D3DX10_IFF_WMP)
         ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
         if (hr == S_OK)
             check_image_info(&image_info, i, __LINE__);
@@ -1583,13 +1580,11 @@ static void test_get_image_info(void)
         resource_module = create_resource_module(test_resource_name, test_image[i].data, test_image[i].size);
 
         hr = D3DX10GetImageInfoFromResourceW(resource_module, test_resource_name, NULL, &image_info, NULL);
-        todo_wine_if(test_image[i].expected.ImageFileFormat == D3DX10_IFF_WMP)
         ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
         if (hr == S_OK)
             check_image_info(&image_info, i, __LINE__);
 
         hr = D3DX10GetImageInfoFromResourceA(resource_module, get_str_a(test_resource_name), NULL, &image_info, NULL);
-        todo_wine_if(test_image[i].expected.ImageFileFormat == D3DX10_IFF_WMP)
         ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
         if (hr == S_OK)
             check_image_info(&image_info, i, __LINE__);
diff --git a/dlls/windowscodecs/tests/wmpformat.c b/dlls/windowscodecs/tests/wmpformat.c
index 2e2809701f6..c4f947d8acf 100644
--- a/dlls/windowscodecs/tests/wmpformat.c
+++ b/dlls/windowscodecs/tests/wmpformat.c
@@ -89,7 +89,7 @@ static void test_decode(void)
                           &IID_IWICBitmapDecoder, (void **)&decoder);
     if (FAILED(hr))
     {
-        todo_wine win_skip("WmpDecoder isn't available, skipping test\n");
+        win_skip("WmpDecoder isn't available, skipping test\n");
         return;
     }
 
@@ -123,7 +123,7 @@ static void test_decode(void)
     ok(count == 1, "unexpected count %u\n", count);
 
     hr = IWICBitmapDecoder_GetFrame(decoder, 0, NULL);
-    ok(hr == E_INVALIDARG, "GetFrame(NULL) returned hr=%x\n", hr);
+    todo_wine ok(hr == E_INVALIDARG, "GetFrame(NULL) returned hr=%x\n", hr);
 
     for (j = 2; j > 0; --j)
     {
diff --git a/dlls/wmphoto/Makefile.in b/dlls/wmphoto/Makefile.in
index 0780271ed7c..7f87d92c939 100644
--- a/dlls/wmphoto/Makefile.in
+++ b/dlls/wmphoto/Makefile.in
@@ -1,5 +1,5 @@
 MODULE = wmphoto.dll
-IMPORTS = windowscodecs uuid kernelbase combase shcore
+IMPORTS = windowscodecs uuid ole32 oleaut32 propsys rpcrt4 shlwapi
 PARENTSRC = ../windowscodecs
 
 EXTRADLLFLAGS = -mno-cygwin
@@ -7,9 +7,12 @@ EXTRAINCL = $(JXRLIB_CFLAGS)
 
 C_SRCS = \
 	decoder.c \
+	main.c \
+	metadataquery.c \
+	palette.c \
 	stream.c \
 	unix_iface.c \
 	unix_lib.c \
-	main.c
+	wincodecs_common.c
 
 IDL_SRCS = wmphoto.idl
diff --git a/dlls/wmphoto/main.c b/dlls/wmphoto/main.c
index 8d507560dc2..73d0778581a 100644
--- a/dlls/wmphoto/main.c
+++ b/dlls/wmphoto/main.c
@@ -36,7 +36,42 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 
-#include "wincodecs_common.h"
+HRESULT create_instance(CLSID *clsid, const IID *iid, void **ppv)
+{
+    return CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, ppv);
+}
+
+HRESULT ImagingFactory_CreateInstance(REFIID iid, void** ppv)
+{
+    return CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
+                            iid, ppv);
+}
+
+HRESULT get_decoder_info(REFCLSID clsid, IWICBitmapDecoderInfo **info)
+{
+    IWICImagingFactory* factory;
+    IWICComponentInfo *compinfo;
+    HRESULT hr;
+
+    hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
+                          &IID_IWICImagingFactory, (void **)&factory);
+    if (FAILED(hr))
+        return hr;
+
+    hr = IWICImagingFactory_CreateComponentInfo(factory, clsid, &compinfo);
+    if (FAILED(hr))
+    {
+        IWICImagingFactory_Release(factory);
+        return hr;
+    }
+
+    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
+        (void **)info);
+
+    IWICComponentInfo_Release(compinfo);
+    IWICImagingFactory_Release(factory);
+    return hr;
+}
 
 struct class_factory
 {
diff --git a/dlls/wmphoto/unix_lib.c b/dlls/wmphoto/unix_lib.c
index d8108bfc584..6647b582eab 100644
--- a/dlls/wmphoto/unix_lib.c
+++ b/dlls/wmphoto/unix_lib.c
@@ -37,6 +37,14 @@
 #include "winbase.h"
 #include "objbase.h"
 
+#include "initguid.h"
+
+#ifdef SONAME_LIBJXRGLUE
+#define ERR JXR_ERR
+#include <JXRGlue.h>
+#undef ERR
+#endif
+
 #include "wincodecs_private.h"
 #include "wine/debug.h"
 
@@ -44,6 +52,320 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 
 #include "wincodecs_common.h"
 
+#ifdef SONAME_LIBJXRGLUE
+static void *libjxrglue;
+static typeof(PKImageDecode_Create_WMP) *pPKImageDecode_Create_WMP;
+
+static const struct
+{
+    const WICPixelFormatGUID *format;
+    UINT bpp;
+} pixel_format_bpp[] =
+{
+    {&GUID_PKPixelFormat128bppRGBAFixedPoint, 128},
+    {&GUID_PKPixelFormat128bppRGBAFloat, 128},
+    {&GUID_PKPixelFormat128bppRGBFloat, 128},
+    {&GUID_PKPixelFormat16bppRGB555, 16},
+    {&GUID_PKPixelFormat16bppRGB565, 16},
+    {&GUID_PKPixelFormat16bppGray, 16},
+    {&GUID_PKPixelFormat16bppGrayFixedPoint, 16},
+    {&GUID_PKPixelFormat16bppGrayHalf, 16},
+    {&GUID_PKPixelFormat24bppBGR, 24},
+    {&GUID_PKPixelFormat24bppRGB, 24},
+    {&GUID_PKPixelFormat32bppBGR, 32},
+    {&GUID_PKPixelFormat32bppRGB101010, 32},
+    {&GUID_PKPixelFormat32bppBGRA, 32},
+    {&GUID_PKPixelFormat32bppCMYK, 32},
+    {&GUID_PKPixelFormat32bppGrayFixedPoint, 32},
+    {&GUID_PKPixelFormat32bppGrayFloat, 32},
+    {&GUID_PKPixelFormat32bppRGBE, 32},
+    {&GUID_PKPixelFormat40bppCMYKAlpha, 40},
+    {&GUID_PKPixelFormat48bppRGB, 48},
+    {&GUID_PKPixelFormat48bppRGBFixedPoint, 48},
+    {&GUID_PKPixelFormat48bppRGBHalf, 48},
+    {&GUID_PKPixelFormat64bppCMYK, 64},
+    {&GUID_PKPixelFormat64bppRGBA, 64},
+    {&GUID_PKPixelFormat64bppRGBAFixedPoint, 64},
+    {&GUID_PKPixelFormat64bppRGBAHalf, 64},
+    {&GUID_PKPixelFormat80bppCMYKAlpha, 80},
+    {&GUID_PKPixelFormat8bppGray, 8},
+    {&GUID_PKPixelFormat96bppRGBFixedPoint, 96},
+    {&GUID_PKPixelFormatBlackWhite, 1},
+};
+
+static inline UINT pixel_format_get_bpp(const WICPixelFormatGUID *format)
+{
+    int i;
+    for (i = 0; i < ARRAY_SIZE(pixel_format_bpp); ++i)
+        if (IsEqualGUID(format, pixel_format_bpp[i].format)) return pixel_format_bpp[i].bpp;
+    return 0;
+}
+
+struct wmp_decoder
+{
+    struct decoder decoder_iface;
+    struct WMPStream WMPStream_iface;
+    PKImageDecode *decoder;
+    IStream *stream;
+    struct decoder_frame frame;
+    UINT frame_stride;
+    BYTE *frame_data;
+};
+
+static inline struct wmp_decoder *impl_from_decoder(struct decoder *iface)
+{
+    return CONTAINING_RECORD(iface, struct wmp_decoder, decoder_iface);
+}
+
+static inline struct wmp_decoder *impl_from_WMPStream(struct WMPStream *iface)
+{
+    return CONTAINING_RECORD(iface, struct wmp_decoder, WMPStream_iface);
+}
+
+static JXR_ERR wmp_stream_Close(struct WMPStream **piface)
+{
+    TRACE("iface %p\n", piface);
+    return WMP_errSuccess;
+}
+
+static Bool wmp_stream_EOS(struct WMPStream *iface)
+{
+    FIXME("iface %p, stub!\n", iface);
+    return FALSE;
+}
+
+static JXR_ERR wmp_stream_Read(struct WMPStream *iface, void *buf, size_t len)
+{
+    struct wmp_decoder *This = impl_from_WMPStream(iface);
+    ULONG count;
+    if (FAILED(stream_read(This->stream, buf, len, &count)))
+        return WMP_errFileIO;
+    return WMP_errSuccess;
+}
+
+static JXR_ERR wmp_stream_Write(struct WMPStream *iface, const void *buf, size_t len)
+{
+    struct wmp_decoder *This = impl_from_WMPStream(iface);
+    ULONG count;
+    if (FAILED(stream_write(This->stream, buf, len, &count)))
+        return WMP_errFileIO;
+    return WMP_errSuccess;
+}
+
+static JXR_ERR wmp_stream_SetPos(struct WMPStream *iface, size_t pos)
+{
+    struct wmp_decoder *This = impl_from_WMPStream(iface);
+    if (FAILED(stream_seek(This->stream, pos, STREAM_SEEK_SET, NULL)))
+        return WMP_errFileIO;
+    return WMP_errSuccess;
+}
+
+static JXR_ERR wmp_stream_GetPos(struct WMPStream *iface, size_t *pos)
+{
+    struct wmp_decoder *This = impl_from_WMPStream(iface);
+    ULONGLONG ofs;
+    if (FAILED(stream_seek(This->stream, 0, STREAM_SEEK_CUR, &ofs)))
+        return WMP_errFileIO;
+    *pos = ofs;
+    return WMP_errSuccess;
+}
+
+HRESULT CDECL wmp_decoder_initialize(struct decoder *iface, IStream *stream, struct decoder_stat *st)
+{
+    struct wmp_decoder *This = impl_from_decoder(iface);
+    HRESULT hr;
+    Float dpix, dpiy;
+    I32 width, height;
+    U32 count;
+
+    TRACE("iface %p, stream %p, st %p\n", iface, stream, st);
+
+    if (This->stream)
+        return WINCODEC_ERR_WRONGSTATE;
+
+    This->stream = stream;
+    if (FAILED(hr = stream_seek(This->stream, 0, STREAM_SEEK_SET, NULL)))
+        return hr;
+    if (This->decoder->Initialize(This->decoder, &This->WMPStream_iface))
+        return E_FAIL;
+
+    if (This->decoder->GetFrameCount(This->decoder, &st->frame_count))
+        return E_FAIL;
+
+    if (st->frame_count > 1) FIXME("multi frame JPEG-XR not implemented\n");
+    st->frame_count = 1;
+    st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
+                WICBitmapDecoderCapabilityCanDecodeSomeImages |
+                WICBitmapDecoderCapabilityCanEnumerateMetadata;
+
+    if (This->decoder->SelectFrame(This->decoder, 0))
+        return E_FAIL;
+    if (This->decoder->GetPixelFormat(This->decoder, &This->frame.pixel_format))
+        return E_FAIL;
+    if (This->decoder->GetSize(This->decoder, &width, &height))
+        return E_FAIL;
+    if (This->decoder->GetResolution(This->decoder, &dpix, &dpiy))
+        return E_FAIL;
+    if (This->decoder->GetColorContext(This->decoder, NULL, &count))
+        return E_FAIL;
+
+    if (!(This->frame.bpp = pixel_format_get_bpp(&This->frame.pixel_format))) return E_FAIL;
+    This->frame.width = width;
+    This->frame.height = height;
+    This->frame.dpix = dpix;
+    This->frame.dpiy = dpiy;
+    This->frame.num_colors = 0;
+    if (count) This->frame.num_color_contexts = 1;
+    else This->frame.num_color_contexts = 0;
+
+    return S_OK;
+}
+
+HRESULT CDECL wmp_decoder_get_frame_info(struct decoder *iface, UINT frame, struct decoder_frame *info)
+{
+    struct wmp_decoder *This = impl_from_decoder(iface);
+
+    TRACE("iface %p, frame %d, info %p\n", iface, frame, info);
+
+    if (frame > 0)
+    {
+        FIXME("multi frame JPEG-XR not implemented\n");
+        return E_NOTIMPL;
+    }
+
+    *info = This->frame;
+    return S_OK;
+}
+
+HRESULT CDECL wmp_decoder_copy_pixels(struct decoder *iface, UINT frame, const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer)
+{
+    struct wmp_decoder *This = impl_from_decoder(iface);
+    PKRect pkrect;
+    U8 *frame_data;
+
+    TRACE("iface %p, frame %d, rect %p, stride %d, buffersize %d, buffer %p\n", iface, frame, prc, stride, buffersize, buffer);
+
+    if (frame > 0)
+    {
+        FIXME("multi frame JPEG-XR not implemented\n");
+        return E_NOTIMPL;
+    }
+
+    if (!This->frame_data)
+    {
+        pkrect.X = 0;
+        pkrect.Y = 0;
+        pkrect.Width = This->frame.width;
+        pkrect.Height = This->frame.height;
+        This->frame_stride = (This->frame.width * This->frame.bpp + 7) / 8;
+        if (!(frame_data = RtlAllocateHeap(GetProcessHeap(), 0, This->frame.height * This->frame_stride)))
+            return E_FAIL;
+        if (This->decoder->Copy(This->decoder, &pkrect, frame_data, stride))
+        {
+            RtlFreeHeap(GetProcessHeap(), 0, frame_data);
+            return E_FAIL;
+        }
+
+        This->frame_data = frame_data;
+    }
+
+    return copy_pixels(This->frame.bpp, This->frame_data,
+        This->frame.width, This->frame.height, This->frame_stride,
+        prc, stride, buffersize, buffer);
+}
+
+HRESULT CDECL wmp_decoder_get_metadata_blocks(struct decoder* iface, UINT frame, UINT *count, struct decoder_block **blocks)
+{
+    TRACE("iface %p, frame %d, count %p, blocks %p\n", iface, frame, count, blocks);
+
+    *count = 0;
+    *blocks = NULL;
+    return S_OK;
+}
+
+HRESULT CDECL wmp_decoder_get_color_context(struct decoder* iface, UINT frame, UINT num, BYTE **data, DWORD *datasize)
+{
+    struct wmp_decoder *This = impl_from_decoder(iface);
+    U32 count;
+    U8 *bytes;
+
+    TRACE("iface %p, frame %d, num %u, data %p, datasize %p\n", iface, frame, num, data, datasize);
+
+    *datasize = 0;
+    *data = NULL;
+
+    if (This->decoder->GetColorContext(This->decoder, NULL, &count))
+        return E_FAIL;
+    *datasize = count;
+
+    bytes = RtlAllocateHeap(GetProcessHeap(), 0, count);
+    if (!bytes)
+        return E_OUTOFMEMORY;
+
+    if (This->decoder->GetColorContext(This->decoder, bytes, &count))
+    {
+        RtlFreeHeap(GetProcessHeap(), 0, bytes);
+        return E_FAIL;
+    }
+
+    *data = bytes;
+    return S_OK;
+}
+
+void CDECL wmp_decoder_destroy(struct decoder* iface)
+{
+    struct wmp_decoder *This = impl_from_decoder(iface);
+
+    TRACE("iface %p\n", iface);
+
+    This->decoder->Release(&This->decoder);
+    RtlFreeHeap(GetProcessHeap(), 0, This->frame_data);
+    RtlFreeHeap(GetProcessHeap(), 0, This);
+}
+
+static const struct decoder_funcs wmp_decoder_vtable = {
+    wmp_decoder_initialize,
+    wmp_decoder_get_frame_info,
+    wmp_decoder_copy_pixels,
+    wmp_decoder_get_metadata_blocks,
+    wmp_decoder_get_color_context,
+    wmp_decoder_destroy
+};
+
+HRESULT CDECL wmp_decoder_create(struct decoder_info *info, struct decoder **result)
+{
+    struct wmp_decoder *This;
+    PKImageDecode *decoder;
+
+    if (!pPKImageDecode_Create_WMP || pPKImageDecode_Create_WMP(&decoder)) return E_FAIL;
+    This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
+    if (!This)
+        return E_OUTOFMEMORY;
+
+    This->decoder_iface.vtable = &wmp_decoder_vtable;
+    This->WMPStream_iface.Close = &wmp_stream_Close;
+    This->WMPStream_iface.EOS = &wmp_stream_EOS;
+    This->WMPStream_iface.Read = &wmp_stream_Read;
+    This->WMPStream_iface.Write = &wmp_stream_Write;
+    This->WMPStream_iface.SetPos = &wmp_stream_SetPos;
+    This->WMPStream_iface.GetPos = &wmp_stream_GetPos;
+
+    This->decoder = decoder;
+    This->stream = NULL;
+    memset(&This->frame, 0, sizeof(This->frame));
+    This->frame_stride = 0;
+    This->frame_data = NULL;
+
+    *result = &This->decoder_iface;
+
+    info->container_format = GUID_ContainerFormatWmp;
+    info->block_format = GUID_ContainerFormatWmp;
+    info->clsid = CLSID_WICWmpDecoder;
+
+    return S_OK;
+}
+#endif
+
 static const struct win32_funcs *win32_funcs;
 
 HRESULT CDECL stream_getsize(IStream *stream, ULONGLONG *size)
@@ -68,7 +390,17 @@ HRESULT CDECL stream_write(IStream *stream, const void *buffer, ULONG write, ULO
 
 HRESULT CDECL decoder_create(const CLSID *decoder_clsid, struct decoder_info *info, struct decoder **result)
 {
-    FIXME("decoder_clsid %s, info %p, result %p, stub!\n", debugstr_guid(decoder_clsid), info, result);
+    if (IsEqualGUID(decoder_clsid, &CLSID_WICWmpDecoder))
+#ifdef SONAME_LIBJXRGLUE
+        return wmp_decoder_create(info, result);
+#else
+    {
+        WARN("jxrlib support not compiled in!\n");
+        return E_NOINTERFACE;
+    }
+#endif
+
+    FIXME("encoder_clsid %s, info %p, result %p, stub!\n", debugstr_guid(decoder_clsid), info, result);
     return E_NOTIMPL;
 }
 
@@ -102,6 +434,13 @@ NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *p
 
     win32_funcs = ptr_in;
 
+#ifdef SONAME_LIBJXRGLUE
+    if (!(libjxrglue = dlopen(SONAME_LIBJXRGLUE, RTLD_NOW)))
+        ERR("failed to load %s\n", SONAME_LIBJXRGLUE);
+    else if (!(pPKImageDecode_Create_WMP = dlsym(libjxrglue, "PKImageDecode_Create_WMP")))
+        ERR("unable to find PKImageDecode_Create_WMP in %s!\n", SONAME_LIBJXRGLUE);
+#endif
+
     *(const struct unix_funcs **)ptr_out = &unix_funcs;
     return STATUS_SUCCESS;
 }
-- 
2.30.0




More information about the wine-devel mailing list