[PATCH v6 5/5] wmphoto: Implement WmpDecoder using jxrlib.
Rémi Bernon
rbernon at codeweavers.com
Tue Sep 29 03:59:03 CDT 2020
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 at codeweavers.com>
---
v6: Use stream proxy object on the PE side for jxrlib callbacks instead
of calling IStream vtable directly.
dlls/d3dx10_43/tests/d3dx10.c | 3 +-
dlls/windowscodecs/Makefile.in | 1 +
dlls/windowscodecs/copy_pixels.c | 90 +++++++
dlls/windowscodecs/main.c | 65 -----
dlls/windowscodecs/tests/wmpformat.c | 6 +-
dlls/wmphoto/Makefile.in | 1 +
dlls/wmphoto/jxrlib.c | 171 +++++++++++++
dlls/wmphoto/main.c | 369 ++++++++++++++++++++++++++-
dlls/wmphoto/wmphoto_private.h | 28 ++
9 files changed, 657 insertions(+), 77 deletions(-)
create mode 100644 dlls/windowscodecs/copy_pixels.c
diff --git a/dlls/d3dx10_43/tests/d3dx10.c b/dlls/d3dx10_43/tests/d3dx10.c
index 640e83fcd0f..fb5eb79e4e4 100644
--- a/dlls/d3dx10_43/tests/d3dx10.c
+++ b/dlls/d3dx10_43/tests/d3dx10.c
@@ -1376,8 +1376,7 @@ static void test_get_image_info(void)
for (i = 0; i < ARRAY_SIZE(test_image); ++i)
{
hr = D3DX10GetImageInfoFromMemory(test_image[i].data, test_image[i].size, NULL, &image_info, NULL);
- todo_wine_if(test_image[i].expected.ImageFileFormat == D3DX10_IFF_WMP)
- ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
+ ok(hr == S_OK, "Test %u: Got unexpected hr %#x.\n", i, hr);
if (hr != S_OK)
continue;
check_image_info(&image_info, i, __LINE__);
diff --git a/dlls/windowscodecs/Makefile.in b/dlls/windowscodecs/Makefile.in
index fac90344fa3..56fa821939f 100644
--- a/dlls/windowscodecs/Makefile.in
+++ b/dlls/windowscodecs/Makefile.in
@@ -13,6 +13,7 @@ C_SRCS = \
colorcontext.c \
colortransform.c \
converter.c \
+ copy_pixels.c \
ddsformat.c \
fliprotate.c \
gifformat.c \
diff --git a/dlls/windowscodecs/copy_pixels.c b/dlls/windowscodecs/copy_pixels.c
new file mode 100644
index 00000000000..da905557b3f
--- /dev/null
+++ b/dlls/windowscodecs/copy_pixels.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "wincodecsdk.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
+ UINT srcwidth, UINT srcheight, INT srcstride,
+ const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
+{
+ UINT bytesperrow;
+ UINT row_offset; /* number of bits into the source rows where the data starts */
+ WICRect rect;
+
+ if (!rc)
+ {
+ rect.X = 0;
+ rect.Y = 0;
+ rect.Width = srcwidth;
+ rect.Height = srcheight;
+ rc = ▭
+ }
+ else
+ {
+ if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
+ return E_INVALIDARG;
+ }
+
+ bytesperrow = ((bpp * rc->Width)+7)/8;
+
+ if (dststride < bytesperrow)
+ return E_INVALIDARG;
+
+ if ((dststride * (rc->Height-1)) + bytesperrow > dstbuffersize)
+ return E_INVALIDARG;
+
+ /* if the whole bitmap is copied and the buffer format matches then it's a matter of a single memcpy */
+ if (rc->X == 0 && rc->Y == 0 && rc->Width == srcwidth && rc->Height == srcheight &&
+ srcstride == dststride && srcstride == bytesperrow)
+ {
+ memcpy(dstbuffer, srcbuffer, srcstride * srcheight);
+ return S_OK;
+ }
+
+ row_offset = rc->X * bpp;
+
+ if (row_offset % 8 == 0)
+ {
+ /* everything lines up on a byte boundary */
+ INT row;
+ const BYTE *src;
+ BYTE *dst;
+
+ src = srcbuffer + (row_offset / 8) + srcstride * rc->Y;
+ dst = dstbuffer;
+ for (row=0; row < rc->Height; row++)
+ {
+ memcpy(dst, src, bytesperrow);
+ src += srcstride;
+ dst += dststride;
+ }
+ return S_OK;
+ }
+ else
+ {
+ /* we have to do a weird bitwise copy. eww. */
+ FIXME("cannot reliably copy bitmap data if bpp < 8\n");
+ return E_FAIL;
+ }
+}
diff --git a/dlls/windowscodecs/main.c b/dlls/windowscodecs/main.c
index 7e03112a63c..ca708d26fd4 100644
--- a/dlls/windowscodecs/main.c
+++ b/dlls/windowscodecs/main.c
@@ -55,71 +55,6 @@ HRESULT WINAPI DllCanUnloadNow(void)
return S_FALSE;
}
-HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
- UINT srcwidth, UINT srcheight, INT srcstride,
- const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
-{
- UINT bytesperrow;
- UINT row_offset; /* number of bits into the source rows where the data starts */
- WICRect rect;
-
- if (!rc)
- {
- rect.X = 0;
- rect.Y = 0;
- rect.Width = srcwidth;
- rect.Height = srcheight;
- rc = ▭
- }
- else
- {
- if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
- return E_INVALIDARG;
- }
-
- bytesperrow = ((bpp * rc->Width)+7)/8;
-
- if (dststride < bytesperrow)
- return E_INVALIDARG;
-
- if ((dststride * (rc->Height-1)) + bytesperrow > dstbuffersize)
- return E_INVALIDARG;
-
- /* if the whole bitmap is copied and the buffer format matches then it's a matter of a single memcpy */
- if (rc->X == 0 && rc->Y == 0 && rc->Width == srcwidth && rc->Height == srcheight &&
- srcstride == dststride && srcstride == bytesperrow)
- {
- memcpy(dstbuffer, srcbuffer, srcstride * srcheight);
- return S_OK;
- }
-
- row_offset = rc->X * bpp;
-
- if (row_offset % 8 == 0)
- {
- /* everything lines up on a byte boundary */
- INT row;
- const BYTE *src;
- BYTE *dst;
-
- src = srcbuffer + (row_offset / 8) + srcstride * rc->Y;
- dst = dstbuffer;
- for (row=0; row < rc->Height; row++)
- {
- memcpy(dst, src, bytesperrow);
- src += srcstride;
- dst += dststride;
- }
- return S_OK;
- }
- else
- {
- /* we have to do a weird bitwise copy. eww. */
- FIXME("cannot reliably copy bitmap data if bpp < 8\n");
- return E_FAIL;
- }
-}
-
HRESULT configure_write_source(IWICBitmapFrameEncode *iface,
IWICBitmapSource *source, const WICRect *prc,
const WICPixelFormatGUID *format,
diff --git a/dlls/windowscodecs/tests/wmpformat.c b/dlls/windowscodecs/tests/wmpformat.c
index 12bc1275919..e808e6fee53 100644
--- a/dlls/windowscodecs/tests/wmpformat.c
+++ b/dlls/windowscodecs/tests/wmpformat.c
@@ -119,8 +119,8 @@ static void test_decode(void)
"unexpected container format\n");
hr = IWICBitmapDecoder_GetFrameCount(decoder, &count);
- todo_wine ok(SUCCEEDED(hr), "GetFrameCount failed, hr=%x\n", hr);
- todo_wine ok(count == 1, "unexpected count %u\n", count);
+ ok(SUCCEEDED(hr), "GetFrameCount failed, hr=%x\n", hr);
+ ok(count == 1, "unexpected count %u\n", count);
hr = IWICBitmapDecoder_GetFrame(decoder, 0, NULL);
ok(hr == E_INVALIDARG, "GetFrame(NULL) returned hr=%x\n", hr);
@@ -128,7 +128,7 @@ static void test_decode(void)
for (j = 2; j > 0; --j)
{
hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
- todo_wine ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr);
+ ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr);
if (FAILED(hr))
{
diff --git a/dlls/wmphoto/Makefile.in b/dlls/wmphoto/Makefile.in
index 37c879aed49..a9dce70a4de 100644
--- a/dlls/wmphoto/Makefile.in
+++ b/dlls/wmphoto/Makefile.in
@@ -6,6 +6,7 @@ EXTRADLLFLAGS = -mno-cygwin
EXTRAINCL = $(JXRLIB_CFLAGS)
C_SRCS = \
+ copy_pixels.c \
jxrlib.c \
main.c
diff --git a/dlls/wmphoto/jxrlib.c b/dlls/wmphoto/jxrlib.c
index 3fc78bee9de..1e7ec5e92bc 100644
--- a/dlls/wmphoto/jxrlib.c
+++ b/dlls/wmphoto/jxrlib.c
@@ -28,12 +28,21 @@
#include <string.h>
#include <stdlib.h>
+#define COBJMACROS
+
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winternl.h"
+#include "objidl.h"
+
+#ifdef SONAME_LIBJXRGLUE
+#define ERR JXR_ERR
+#include <JXRGlue.h>
+#undef ERR
+#endif
#include "wine/debug.h"
@@ -43,10 +52,166 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
#ifdef SONAME_LIBJXRGLUE
static void *libjxrglue;
+static typeof(PKImageDecode_Create_WMP) *pPKImageDecode_Create_WMP;
+
+struct decoder_proxy
+{
+ struct jxrlib_decoder decoder_iface;
+ struct WMPStream WMPStream_iface;
+ struct jxrlib_stream *stream;
+ PKImageDecode *decoder;
+};
+
+static inline struct decoder_proxy *impl_from_jxrlib_decoder(struct jxrlib_decoder *iface)
+{
+ return CONTAINING_RECORD(iface, struct decoder_proxy, decoder_iface);
+}
+
+static inline struct decoder_proxy *impl_from_WMPStream(struct WMPStream *iface)
+{
+ return CONTAINING_RECORD(iface, struct decoder_proxy, WMPStream_iface);
+}
+
+static JXR_ERR wmp_stream_Close(struct WMPStream **piface)
+{
+ TRACE("iface %p.\n", piface);
+ return WMP_errSuccess;
+}
+
+static Bool wmp_stream_EOS(struct WMPStream *iface)
+{
+ FIXME("iface %p, stub!\n", iface);
+ return FALSE;
+}
+
+static JXR_ERR wmp_stream_Read(struct WMPStream *iface, void *buf, size_t len)
+{
+ struct decoder_proxy *This = impl_from_WMPStream(iface);
+ return This->stream->Read(This->stream, buf, len);
+}
+
+static JXR_ERR wmp_stream_Write(struct WMPStream *iface, const void *buf, size_t len)
+{
+ struct decoder_proxy *This = impl_from_WMPStream(iface);
+ return This->stream->Write(This->stream, buf, len);
+}
+
+static JXR_ERR wmp_stream_SetPos(struct WMPStream *iface, size_t pos)
+{
+ struct decoder_proxy *This = impl_from_WMPStream(iface);
+ return This->stream->SetPos(This->stream, pos);
+}
+
+static JXR_ERR wmp_stream_GetPos(struct WMPStream *iface, size_t *pos)
+{
+ struct decoder_proxy *This = impl_from_WMPStream(iface);
+ return This->stream->GetPos(This->stream, pos);
+}
+
+static JXR_ERR CDECL decoder_Initialize(struct jxrlib_decoder *iface, struct jxrlib_stream *stream)
+{
+ struct decoder_proxy *This = impl_from_jxrlib_decoder(iface);
+ if (This->stream) return WMP_errFail;
+ This->stream = stream;
+ return This->decoder->Initialize(This->decoder, &This->WMPStream_iface);
+}
+
+static JXR_ERR CDECL decoder_GetPixelFormat(struct jxrlib_decoder *iface, GUID *guid)
+{
+ struct decoder_proxy *This = impl_from_jxrlib_decoder(iface);
+ return This->decoder->GetPixelFormat(This->decoder, guid);
+}
+
+static JXR_ERR CDECL decoder_GetSize(struct jxrlib_decoder *iface, INT32 *width, INT32 *height)
+{
+ struct decoder_proxy *This = impl_from_jxrlib_decoder(iface);
+ return This->decoder->GetSize(This->decoder, width, height);
+}
+
+static JXR_ERR CDECL decoder_GetResolution(struct jxrlib_decoder *iface, FLOAT *resx, FLOAT *resy)
+{
+ struct decoder_proxy *This = impl_from_jxrlib_decoder(iface);
+ return This->decoder->GetResolution(This->decoder, resx, resy);
+}
+
+static JXR_ERR CDECL decoder_Copy(struct jxrlib_decoder *iface, const WICRect *rect, UINT8 *buffer, UINT32 stride)
+{
+ struct decoder_proxy *This = impl_from_jxrlib_decoder(iface);
+ PKRect pkrect;
+ if (!rect) return WMP_errFail;
+ pkrect.X = rect->X;
+ pkrect.Y = rect->Y;
+ pkrect.Width = rect->Width;
+ pkrect.Height = rect->Height;
+ return This->decoder->Copy(This->decoder, &pkrect, buffer, stride);
+}
+
+static JXR_ERR CDECL decoder_GetFrameCount(struct jxrlib_decoder *iface, UINT32 *count)
+{
+ struct decoder_proxy *This = impl_from_jxrlib_decoder(iface);
+ return This->decoder->GetFrameCount(This->decoder, count);
+}
+
+static JXR_ERR CDECL decoder_SelectFrame(struct jxrlib_decoder *iface, UINT32 index)
+{
+ struct decoder_proxy *This = impl_from_jxrlib_decoder(iface);
+ return This->decoder->SelectFrame(This->decoder, index);
+}
+
+static JXR_ERR CDECL decoder_Release(struct jxrlib_decoder **iface)
+{
+ struct decoder_proxy *This = impl_from_jxrlib_decoder(*iface);
+ JXR_ERR err;
+
+ if ((err = This->decoder->Release(&This->decoder))) return err;
+
+ free(This);
+ *iface = NULL;
+
+ return err;
+}
+
+static HRESULT CDECL jxrlib_decoder_create(struct jxrlib_decoder **out)
+{
+ struct decoder_proxy *This;
+ PKImageDecode *decoder;
+
+ if (pPKImageDecode_Create_WMP(&decoder)) return E_FAIL;
+ if (!(This = malloc(sizeof(*This)))) return E_OUTOFMEMORY;
+
+ This->decoder_iface.Initialize = &decoder_Initialize;
+ This->decoder_iface.GetPixelFormat = &decoder_GetPixelFormat;
+ This->decoder_iface.GetSize = &decoder_GetSize;
+ This->decoder_iface.GetResolution = &decoder_GetResolution;
+ This->decoder_iface.Copy = &decoder_Copy;
+ This->decoder_iface.GetFrameCount = &decoder_GetFrameCount;
+ This->decoder_iface.SelectFrame = &decoder_SelectFrame;
+ This->decoder_iface.Release = &decoder_Release;
+
+ This->WMPStream_iface.Close = &wmp_stream_Close;
+ This->WMPStream_iface.EOS = &wmp_stream_EOS;
+ This->WMPStream_iface.Read = &wmp_stream_Read;
+ This->WMPStream_iface.Write = &wmp_stream_Write;
+ This->WMPStream_iface.SetPos = &wmp_stream_SetPos;
+ This->WMPStream_iface.GetPos = &wmp_stream_GetPos;
+
+ This->decoder = decoder;
+ This->stream = NULL;
+
+ *out = &This->decoder_iface;
+ return S_OK;
+}
+#else
+static HRESULT CDECL jxrlib_decoder_create(struct jxrlib_decoder **out)
+{
+ FIXME("JPEG-XR support not compiled in!\n");
+ return E_NOTIMPL;
+}
#endif
static const struct jxrlib_funcs jxrlib_funcs =
{
+ jxrlib_decoder_create,
};
NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *ptr_in, void *ptr_out)
@@ -61,6 +226,12 @@ NTSTATUS CDECL __wine_init_unix_lib(HMODULE module, DWORD reason, const void *pt
WARN("failed to load %s\n", SONAME_LIBJXRGLUE);
return STATUS_DLL_NOT_FOUND;
}
+
+ if (!(pPKImageDecode_Create_WMP = dlsym(libjxrglue, "PKImageDecode_Create_WMP")))
+ {
+ ERR("unable to find PKImageDecode_Create_WMP in %s!\n", SONAME_LIBJXRGLUE);
+ return FALSE;
+ }
#endif
*(const struct jxrlib_funcs **)ptr_out = &jxrlib_funcs;
diff --git a/dlls/wmphoto/main.c b/dlls/wmphoto/main.c
index 83b5627f1af..0212cd4909a 100644
--- a/dlls/wmphoto/main.c
+++ b/dlls/wmphoto/main.c
@@ -39,11 +39,340 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
static const struct jxrlib_funcs *jxrlib_funcs;
+static inline const char *debug_wic_rect(const WICRect *rect)
+{
+ if (!rect) return "(null)";
+ return wine_dbg_sprintf("(%u,%u)-(%u,%u)", rect->X, rect->Y, rect->Width, rect->Height);
+}
+
+extern HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer, UINT srcwidth, UINT srcheight, INT srcstride,
+ const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer) DECLSPEC_HIDDEN;
+
+static const struct
+{
+ const WICPixelFormatGUID *format;
+ UINT bpp;
+} pixel_format_bpp[] =
+{
+ {&GUID_WICPixelFormat128bppRGBAFixedPoint, 128},
+ {&GUID_WICPixelFormat128bppRGBAFloat, 128},
+ {&GUID_WICPixelFormat128bppRGBFloat, 128},
+ {&GUID_WICPixelFormat16bppBGR555, 16},
+ {&GUID_WICPixelFormat16bppBGR565, 16},
+ {&GUID_WICPixelFormat16bppGray, 16},
+ {&GUID_WICPixelFormat16bppGrayFixedPoint, 16},
+ {&GUID_WICPixelFormat16bppGrayHalf, 16},
+ {&GUID_WICPixelFormat24bppBGR, 24},
+ {&GUID_WICPixelFormat24bppRGB, 24},
+ {&GUID_WICPixelFormat32bppBGR, 32},
+ {&GUID_WICPixelFormat32bppBGR101010, 32},
+ {&GUID_WICPixelFormat32bppBGRA, 32},
+ {&GUID_WICPixelFormat32bppCMYK, 32},
+ {&GUID_WICPixelFormat32bppGrayFixedPoint, 32},
+ {&GUID_WICPixelFormat32bppGrayFloat, 32},
+ {&GUID_WICPixelFormat32bppRGBE, 32},
+ {&GUID_WICPixelFormat40bppCMYKAlpha, 40},
+ {&GUID_WICPixelFormat48bppRGB, 48},
+ {&GUID_WICPixelFormat48bppRGBFixedPoint, 48},
+ {&GUID_WICPixelFormat48bppRGBHalf, 48},
+ {&GUID_WICPixelFormat64bppCMYK, 64},
+ {&GUID_WICPixelFormat64bppRGBA, 64},
+ {&GUID_WICPixelFormat64bppRGBAFixedPoint, 64},
+ {&GUID_WICPixelFormat64bppRGBAHalf, 64},
+ {&GUID_WICPixelFormat80bppCMYKAlpha, 80},
+ {&GUID_WICPixelFormat8bppGray, 8},
+ {&GUID_WICPixelFormat96bppRGBFixedPoint, 96},
+ {&GUID_WICPixelFormatBlackWhite, 1},
+};
+
+static inline UINT pixel_format_get_bpp(const WICPixelFormatGUID *format)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(pixel_format_bpp); ++i)
+ if (IsEqualGUID(format, pixel_format_bpp[i].format)) return pixel_format_bpp[i].bpp;
+ return 0;
+}
+
+struct stream_proxy
+{
+ struct jxrlib_stream stream_iface;
+ IStream *stream;
+};
+
+static inline struct stream_proxy *impl_from_jxrlib_stream(struct jxrlib_stream *iface)
+{
+ return CONTAINING_RECORD(iface, struct stream_proxy, stream_iface);
+}
+
+static JXR_ERR CDECL stream_Read(struct jxrlib_stream *iface, void *buf, size_t len)
+{
+ struct stream_proxy *This = impl_from_jxrlib_stream(iface);
+ ULONG count;
+
+ TRACE("iface %p, buf %p, len %Ix.\n", iface, buf, len);
+
+ if (FAILED(IStream_Read(This->stream, buf, len, &count)) || count < len) return WMP_errFileIO;
+ return WMP_errSuccess;
+}
+
+static JXR_ERR CDECL stream_Write(struct jxrlib_stream *iface, const void *buf, size_t len)
+{
+ struct stream_proxy *This = impl_from_jxrlib_stream(iface);
+ ULONG count;
+
+ TRACE("iface %p, buf %p, len %Ix.\n", iface, buf, len);
+
+ if (FAILED(IStream_Write(This->stream, buf, len, &count)) || count < len) return WMP_errFileIO;
+ return WMP_errSuccess;
+}
+
+static JXR_ERR CDECL stream_SetPos(struct jxrlib_stream *iface, size_t pos)
+{
+ struct stream_proxy *This = impl_from_jxrlib_stream(iface);
+ LARGE_INTEGER move;
+
+ TRACE("iface %p, pos %Ix.\n", iface, pos);
+
+ move.QuadPart = pos;
+ if (FAILED(IStream_Seek(This->stream, move, STREAM_SEEK_SET, NULL))) return WMP_errFileIO;
+ return WMP_errSuccess;
+}
+
+static JXR_ERR CDECL stream_GetPos(struct jxrlib_stream *iface, size_t *pos)
+{
+ struct stream_proxy *This = impl_from_jxrlib_stream(iface);
+ ULARGE_INTEGER curr;
+ LARGE_INTEGER move;
+
+ TRACE("iface %p, pos %p.\n", iface, pos);
+
+ move.QuadPart = 0;
+ if (FAILED(IStream_Seek(This->stream, move, STREAM_SEEK_CUR, &curr))) return WMP_errFileIO;
+ *pos = curr.QuadPart;
+
+ return WMP_errSuccess;
+}
+
+static HRESULT jxrlib_stream_create(IStream *stream, struct jxrlib_stream **out)
+{
+ struct stream_proxy *This;
+ LARGE_INTEGER seek;
+ HRESULT hr;
+
+ seek.QuadPart = 0;
+ if (FAILED(hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL))) return hr;
+ if (!(This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)))) return E_OUTOFMEMORY;
+
+ This->stream_iface.Read = &stream_Read;
+ This->stream_iface.Write = &stream_Write;
+ This->stream_iface.SetPos = &stream_SetPos;
+ This->stream_iface.GetPos = &stream_GetPos;
+ This->stream = stream;
+ IStream_AddRef(stream);
+
+ *out = &This->stream_iface;
+ return S_OK;
+}
+
+static void jxrlib_stream_release(struct jxrlib_stream *iface)
+{
+ struct stream_proxy *This = impl_from_jxrlib_stream(iface);
+ IStream_Release(This->stream);
+ HeapFree(GetProcessHeap(), 0, This);
+}
+
+struct wmp_decoder_frame
+{
+ IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
+ LONG ref;
+ WICPixelFormatGUID format;
+ UINT bpp;
+ UINT stride;
+ WICRect rect;
+ float resx, resy;
+ void *image_data;
+};
+
+static inline struct wmp_decoder_frame *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
+{
+ return CONTAINING_RECORD(iface, struct wmp_decoder_frame, IWICBitmapFrameDecode_iface);
+}
+
+static HRESULT WINAPI wmp_decoder_frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, void **out)
+{
+ struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface);
+
+ TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+ if (!out) return E_INVALIDARG;
+
+ *out = NULL;
+ if (!IsEqualIID(&IID_IUnknown, iid) &&
+ !IsEqualIID(&IID_IWICBitmapSource, iid) &&
+ !IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
+ return E_NOINTERFACE;
+
+ *out = &This->IWICBitmapFrameDecode_iface;
+ IUnknown_AddRef((IUnknown *)*out);
+ return S_OK;
+}
+
+static ULONG WINAPI wmp_decoder_frame_AddRef(IWICBitmapFrameDecode *iface)
+{
+ struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+ TRACE("iface %p -> ref %u.\n", iface, ref);
+ return ref;
+}
+
+static ULONG WINAPI wmp_decoder_frame_Release(IWICBitmapFrameDecode *iface)
+{
+ struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+ TRACE("iface %p -> ref %u.\n", iface, ref);
+
+ if (ref == 0)
+ {
+ HeapFree(GetProcessHeap(), 0, This->image_data);
+ HeapFree(GetProcessHeap(), 0, This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI wmp_decoder_frame_GetSize(IWICBitmapFrameDecode *iface, UINT *width, UINT *height)
+{
+ struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface);
+ TRACE("iface %p, width %p, height %p.\n", iface, width, height);
+ *width = This->rect.Width;
+ *height = This->rect.Height;
+ return S_OK;
+}
+
+static HRESULT WINAPI wmp_decoder_frame_GetPixelFormat(IWICBitmapFrameDecode *iface, WICPixelFormatGUID *format)
+{
+ struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface);
+ TRACE("iface %p, format %p.\n", iface, format);
+ *format = This->format;
+ return S_OK;
+}
+
+static HRESULT WINAPI wmp_decoder_frame_GetResolution(IWICBitmapFrameDecode *iface, double *dpix, double *dpiy)
+{
+ struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface);
+ TRACE("iface %p, dpix %p, dpiy %p.\n", iface, dpix, dpiy);
+ *dpix = This->resx;
+ *dpiy = This->resy;
+ return S_OK;
+}
+
+static HRESULT WINAPI wmp_decoder_frame_CopyPalette(IWICBitmapFrameDecode *iface, IWICPalette *palette)
+{
+ TRACE("iface %p, palette %p.\n", iface, palette);
+ return WINCODEC_ERR_PALETTEUNAVAILABLE;
+}
+
+static HRESULT WINAPI wmp_decoder_frame_CopyPixels(IWICBitmapFrameDecode *iface, const WICRect *rect,
+ UINT stride, UINT bufsize, BYTE *buffer)
+{
+ struct wmp_decoder_frame *This = impl_from_IWICBitmapFrameDecode(iface);
+ TRACE("iface %p, rect %p, stride %u, bufsize %u, buffer %p.\n", iface, debug_wic_rect(rect),
+ stride, bufsize, buffer);
+ return copy_pixels(This->bpp, This->image_data, This->rect.Width, This->rect.Height,
+ This->stride, rect, stride, bufsize, buffer);
+}
+
+static HRESULT WINAPI wmp_decoder_frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
+ IWICMetadataQueryReader **reader)
+{
+ FIXME("iface %p, reader %p, stub!\n", iface, reader);
+ if (!reader) return E_INVALIDARG;
+ *reader = NULL;
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI wmp_decoder_frame_GetColorContexts(IWICBitmapFrameDecode *iface, UINT maxcount,
+ IWICColorContext **contexts, UINT *count)
+{
+ FIXME("iface %p, maxcount %u, contexts %p, count %p, stub\n", iface, maxcount, contexts, count);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI wmp_decoder_frame_GetThumbnail(IWICBitmapFrameDecode *iface, IWICBitmapSource **thumbnail)
+{
+ FIXME("iface %p, thumbnail %p, stub!\n", iface, thumbnail);
+ return WINCODEC_ERR_CODECNOTHUMBNAIL;
+}
+
+static const IWICBitmapFrameDecodeVtbl wmp_decoder_frame_vtbl =
+{
+ /* IUnknown methods */
+ wmp_decoder_frame_QueryInterface,
+ wmp_decoder_frame_AddRef,
+ wmp_decoder_frame_Release,
+ /* IWICBitmapSource methods */
+ wmp_decoder_frame_GetSize,
+ wmp_decoder_frame_GetPixelFormat,
+ wmp_decoder_frame_GetResolution,
+ wmp_decoder_frame_CopyPalette,
+ wmp_decoder_frame_CopyPixels,
+ /* IWICBitmapFrameDecode methods */
+ wmp_decoder_frame_GetMetadataQueryReader,
+ wmp_decoder_frame_GetColorContexts,
+ wmp_decoder_frame_GetThumbnail
+};
+
+static HRESULT wmp_decoder_frame_create(IStream *stream, UINT frame, IWICBitmapFrameDecode **out)
+{
+ struct wmp_decoder_frame *This = NULL;
+ struct jxrlib_decoder *jxrlib_decoder = NULL;
+ struct jxrlib_stream *jxrlib_stream = NULL;
+ HRESULT hr;
+
+ TRACE("stream %p, frame %u, out %p.\n", stream, frame, out);
+
+ *out = NULL;
+ if (FAILED(hr = jxrlib_stream_create(stream, &jxrlib_stream))) goto failed;
+ if (FAILED(hr = jxrlib_funcs->decoder_create(&jxrlib_decoder))) goto failed;
+
+ hr = E_FAIL;
+ if (jxrlib_decoder->Initialize(jxrlib_decoder, jxrlib_stream)) goto failed;
+ if (jxrlib_decoder->SelectFrame(jxrlib_decoder, frame)) goto failed;
+
+ hr = E_OUTOFMEMORY;
+ if (!(This = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wmp_decoder_frame)))) goto failed;
+ This->IWICBitmapFrameDecode_iface.lpVtbl = &wmp_decoder_frame_vtbl;
+ This->ref = 1;
+
+ hr = E_FAIL;
+ if (jxrlib_decoder->GetPixelFormat(jxrlib_decoder, &This->format)) goto failed;
+ if (jxrlib_decoder->GetSize(jxrlib_decoder, &This->rect.Width, &This->rect.Height)) goto failed;
+ if (jxrlib_decoder->GetResolution(jxrlib_decoder, &This->resx, &This->resy)) goto failed;
+
+ if (!(This->bpp = pixel_format_get_bpp(&This->format))) goto failed;
+ This->stride = (This->rect.Width * This->bpp + 7) / 8;
+ if (!(This->image_data = HeapAlloc(GetProcessHeap(), 0, This->rect.Height * This->stride))) goto failed;
+ if (jxrlib_decoder->Copy(jxrlib_decoder, &This->rect, This->image_data, This->stride)) goto failed;
+
+ *out = &This->IWICBitmapFrameDecode_iface;
+ return S_OK;
+
+failed:
+ if (This && This->image_data) HeapFree(GetProcessHeap(), 0, This->image_data);
+ if (This) HeapFree(GetProcessHeap(), 0, This);
+ if (jxrlib_decoder) jxrlib_decoder->Release(&jxrlib_decoder);
+ if (jxrlib_stream) jxrlib_stream_release(jxrlib_stream);
+ return hr;
+}
+
struct wmp_decoder
{
IWICBitmapDecoder IWICBitmapDecoder_iface;
+ IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
LONG ref;
IStream *stream;
+ UINT frame_count;
+ IWICBitmapFrameDecode *frame;
CRITICAL_SECTION lock;
};
@@ -87,6 +416,7 @@ static ULONG WINAPI wmp_decoder_Release(IWICBitmapDecoder *iface)
{
This->lock.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->lock);
+ if (This->frame) IWICBitmapFrameDecode_Release(This->frame);
if (This->stream) IStream_Release(This->stream);
HeapFree(GetProcessHeap(), 0, This);
}
@@ -103,7 +433,8 @@ static HRESULT WINAPI wmp_decoder_QueryCapability(IWICBitmapDecoder *iface, IStr
static HRESULT WINAPI wmp_decoder_Initialize(IWICBitmapDecoder *iface, IStream *stream, WICDecodeOptions options)
{
struct wmp_decoder *This = impl_from_IWICBitmapDecoder(iface);
- LARGE_INTEGER seek;
+ struct jxrlib_decoder *jxrlib_decoder = NULL;
+ struct jxrlib_stream *jxrlib_stream = NULL;
HRESULT hr;
TRACE("iface %p, stream %p, options %u.\n", iface, stream, options);
@@ -113,8 +444,13 @@ static HRESULT WINAPI wmp_decoder_Initialize(IWICBitmapDecoder *iface, IStream *
if (This->stream) hr = WINCODEC_ERR_WRONGSTATE;
else
{
- seek.QuadPart = 0;
- if (FAILED(hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL))) goto done;
+ if (FAILED(hr = jxrlib_stream_create(stream, &jxrlib_stream))) goto done;
+ if (FAILED(hr = jxrlib_funcs->decoder_create(&jxrlib_decoder))) goto done;
+
+ hr = E_FAIL;
+ if (jxrlib_decoder->Initialize(jxrlib_decoder, jxrlib_stream)) goto done;
+ if (jxrlib_decoder->GetFrameCount(jxrlib_decoder, &This->frame_count)) goto done;
+ if (This->frame_count > 1) FIXME("multi frame JPEG-XR not implemented\n");
IStream_AddRef(stream);
This->stream = stream;
@@ -122,6 +458,8 @@ static HRESULT WINAPI wmp_decoder_Initialize(IWICBitmapDecoder *iface, IStream *
}
done:
+ if (jxrlib_decoder) jxrlib_decoder->Release(&jxrlib_decoder);
+ if (jxrlib_stream) jxrlib_stream_release(jxrlib_stream);
LeaveCriticalSection(&This->lock);
return hr;
}
@@ -175,16 +513,31 @@ static HRESULT WINAPI wmp_decoder_GetFrameCount(IWICBitmapDecoder *iface, UINT *
{
TRACE("iface %p, count %p.\n", iface, count);
if (!count) return E_INVALIDARG;
- *count = 0;
- return E_NOTIMPL;
+ *count = 1;
+ return S_OK;
}
static HRESULT WINAPI wmp_decoder_GetFrame(IWICBitmapDecoder *iface, UINT index, IWICBitmapFrameDecode **frame)
{
+ struct wmp_decoder *This = impl_from_IWICBitmapDecoder(iface);
+ HRESULT hr;
+
TRACE("iface %p, index %u, frame %p.\n", iface, index, frame);
+
if (!frame) return E_INVALIDARG;
- *frame = NULL;
- return E_NOTIMPL;
+
+ EnterCriticalSection(&This->lock);
+ if (!This->stream) hr = WINCODEC_ERR_WRONGSTATE;
+ else if (index >= This->frame_count) hr = E_INVALIDARG;
+ else if (index >= 1) hr = E_NOTIMPL; /* FIXME: Add support for multiple frames */
+ else if (This->frame) hr = S_OK;
+ else hr = wmp_decoder_frame_create(This->stream, index, &This->frame);
+
+ if (This->frame) IWICBitmapFrameDecode_AddRef(This->frame);
+ *frame = This->frame;
+ LeaveCriticalSection(&This->lock);
+
+ return hr;
}
static const IWICBitmapDecoderVtbl wmp_decoder_vtbl =
@@ -218,8 +571,10 @@ static HRESULT CDECL wmp_decoder_create(IUnknown *outer, IUnknown **out)
if (!This) return E_OUTOFMEMORY;
This->IWICBitmapDecoder_iface.lpVtbl = &wmp_decoder_vtbl;
+ This->IWICBitmapFrameDecode_iface.lpVtbl = &wmp_decoder_frame_vtbl;
This->ref = 1;
This->stream = NULL;
+ This->frame = NULL;
InitializeCriticalSection(&This->lock);
This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wmp_decoder.lock");
diff --git a/dlls/wmphoto/wmphoto_private.h b/dlls/wmphoto/wmphoto_private.h
index dce7f018039..3949983cc07 100644
--- a/dlls/wmphoto/wmphoto_private.h
+++ b/dlls/wmphoto/wmphoto_private.h
@@ -23,9 +23,37 @@
#include "windef.h"
#include "winbase.h"
+#include "wincodecsdk.h"
+
+typedef long JXR_ERR;
+
+#define WMP_errSuccess 0
+#define WMP_errFail -1
+#define WMP_errFileIO -102
+
+struct jxrlib_stream
+{
+ JXR_ERR (CDECL *Read)(struct jxrlib_stream *iface, void *buf, size_t len);
+ JXR_ERR (CDECL *Write)(struct jxrlib_stream *iface, const void *buf, size_t len);
+ JXR_ERR (CDECL *SetPos)(struct jxrlib_stream *iface, size_t pos);
+ JXR_ERR (CDECL *GetPos)(struct jxrlib_stream *iface, size_t *pos);
+};
+
+struct jxrlib_decoder
+{
+ JXR_ERR (CDECL *Initialize)(struct jxrlib_decoder *iface, struct jxrlib_stream *stream);
+ JXR_ERR (CDECL *GetPixelFormat)(struct jxrlib_decoder *iface, GUID *guid);
+ JXR_ERR (CDECL *GetSize)(struct jxrlib_decoder *iface, INT32 *width, INT32 *height);
+ JXR_ERR (CDECL *GetResolution)(struct jxrlib_decoder *iface, FLOAT *resx, FLOAT *resy);
+ JXR_ERR (CDECL *Copy)(struct jxrlib_decoder *iface, const WICRect *rect, UINT8 *buffer, UINT32 stride);
+ JXR_ERR (CDECL *GetFrameCount)(struct jxrlib_decoder *iface, UINT32 *count);
+ JXR_ERR (CDECL *SelectFrame)(struct jxrlib_decoder *iface, UINT32 index);
+ JXR_ERR (CDECL *Release)(struct jxrlib_decoder **iface);
+};
struct jxrlib_funcs
{
+ HRESULT (CDECL *decoder_create)(struct jxrlib_decoder **out);
};
#endif /* WMPHOTO_PRIVATE_H */
--
2.28.0
More information about the wine-devel
mailing list