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 ---
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 */