Wine-Devel
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 4 participants
- 84544 discussions
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/sapi/token.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/sapi/token.c b/dlls/sapi/token.c
index b4a318b4ade..04fa3a25d6a 100644
--- a/dlls/sapi/token.c
+++ b/dlls/sapi/token.c
@@ -372,28 +372,28 @@ static HRESULT WINAPI token_category_EnumValues( ISpObjectTokenCategory *iface,
static HRESULT parse_cat_id( const WCHAR *str, HKEY *root, const WCHAR **sub_key )
{
- static const WCHAR HKLM[] = {'H','K','E','Y','_','L','O','C','A','L','_','M','A','C','H','I','N','E','\\'};
- static const WCHAR HKCU[] = {'H','K','E','Y','_','C','U','R','R','E','N','T','_','U','S','E','R','\\'};
struct table
{
const WCHAR *name;
- int size;
+ unsigned int len;
HKEY key;
} table[] =
{
- { HKLM, sizeof(HKLM), HKEY_LOCAL_MACHINE },
- { HKCU, sizeof(HKCU), HKEY_CURRENT_USER },
+#define X(s) s, ARRAY_SIZE(s) - 1
+ { X(L"HKEY_LOCAL_MACHINE\\"), HKEY_LOCAL_MACHINE },
+ { X(L"HKEY_CURRENT_USER\\"), HKEY_CURRENT_USER },
{ NULL }
+#undef X
};
struct table *ptr;
int len = lstrlenW( str );
for (ptr = table; ptr->name; ptr++)
{
- if (len >= ptr->size / sizeof(ptr->name[0]) && !memcmp( str, ptr->name, ptr->size ))
+ if (len >= ptr->len && !wcsncmp( str, ptr->name, ptr->len ))
{
*root = ptr->key;
- *sub_key = str + ptr->size / sizeof(ptr->name[0]);
+ *sub_key = str + ptr->len;
return S_OK;
}
}
--
2.26.2
1
0
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/sapi/tests/token.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/dlls/sapi/tests/token.c b/dlls/sapi/tests/token.c
index 1ca49398ad1..47196d42dc7 100644
--- a/dlls/sapi/tests/token.c
+++ b/dlls/sapi/tests/token.c
@@ -54,7 +54,6 @@ static void test_token_category(void)
ISpObjectTokenCategory *cat;
IEnumSpObjectTokens *enum_tokens;
HRESULT hr;
- WCHAR bogus[] = {'b','o','g','u','s',0};
ULONG count;
hr = CoCreateInstance( &CLSID_SpObjectTokenCategory, NULL, CLSCTX_INPROC_SERVER,
@@ -64,7 +63,7 @@ static void test_token_category(void)
hr = ISpObjectTokenCategory_EnumTokens( cat, NULL, NULL, &enum_tokens );
ok( hr == SPERR_UNINITIALIZED, "got %08x\n", hr );
- hr = ISpObjectTokenCategory_SetId( cat, bogus, FALSE );
+ hr = ISpObjectTokenCategory_SetId( cat, L"bogus", FALSE );
ok( hr == SPERR_INVALID_REGISTRY_KEY, "got %08x\n", hr );
hr = ISpObjectTokenCategory_SetId( cat, SPCAT_VOICES, FALSE );
--
2.26.2
1
0
[PATCH] mf/evr: Initialize variables which are checked conditionally.
by Biswapriyo Nath Oct. 27, 2020
by Biswapriyo Nath Oct. 27, 2020
Oct. 27, 2020
3
4
Oct. 27, 2020
Fixes crash on start in Nier Automata after switching
kernel32 to PE.
Signed-off-by: Paul Gofman <pgofman(a)codeweavers.com>
---
The game calls GetProcAddress from its (probably DRM related) code
with unaligned stack. Previously in ELF build all the stdcall functions
had stack force aligned by gcc, but mingw build doesn't have that.
dlls/kernel32/module.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/dlls/kernel32/module.c b/dlls/kernel32/module.c
index 12100c1fe23..9b3a3952307 100644
--- a/dlls/kernel32/module.c
+++ b/dlls/kernel32/module.c
@@ -320,18 +320,18 @@ __ASM_GLOBAL_FUNC( get_proc_address_wrapper,
"movq %rsp,%rbp\n\t"
__ASM_SEH(".seh_setframe %rbp,0\n\t")
__ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
- "subq $0x40,%rsp\n\t"
- __ASM_SEH(".seh_stackalloc 0x40\n\t")
__ASM_SEH(".seh_endprologue\n\t")
- "movaps %xmm0,-0x10(%rbp)\n\t"
- "movaps %xmm1,-0x20(%rbp)\n\t"
- "movaps %xmm2,-0x30(%rbp)\n\t"
- "movaps %xmm3,-0x40(%rbp)\n\t"
+ "subq $0x60,%rsp\n\t"
+ "andq $~15,%rsp\n\t"
+ "movaps %xmm0,0x20(%rsp)\n\t"
+ "movaps %xmm1,0x30(%rsp)\n\t"
+ "movaps %xmm2,0x40(%rsp)\n\t"
+ "movaps %xmm3,0x50(%rsp)\n\t"
"call " __ASM_NAME("get_proc_address") "\n\t"
- "movaps -0x40(%rbp), %xmm3\n\t"
- "movaps -0x30(%rbp), %xmm2\n\t"
- "movaps -0x20(%rbp), %xmm1\n\t"
- "movaps -0x10(%rbp), %xmm0\n\t"
+ "movaps 0x50(%rsp), %xmm3\n\t"
+ "movaps 0x40(%rsp), %xmm2\n\t"
+ "movaps 0x30(%rsp), %xmm1\n\t"
+ "movaps 0x20(%rsp), %xmm0\n\t"
"leaq 0(%rbp),%rsp\n\t"
__ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
"popq %rbp\n\t"
--
2.26.2
2
4
[PATCH] shdocvw: There's no need to load ieframe.dll again, it's delayimported
by Michael Stefaniuc Oct. 27, 2020
by Michael Stefaniuc Oct. 27, 2020
Oct. 27, 2020
Signed-off-by: Michael Stefaniuc <mstefani(a)winehq.org>
---
dlls/shdocvw/shdocvw_main.c | 22 ++--------------------
1 file changed, 2 insertions(+), 20 deletions(-)
diff --git a/dlls/shdocvw/shdocvw_main.c b/dlls/shdocvw/shdocvw_main.c
index ac3913dd239..e8487f8b747 100644
--- a/dlls/shdocvw/shdocvw_main.c
+++ b/dlls/shdocvw/shdocvw_main.c
@@ -39,30 +39,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
LONG SHDOCVW_refCount = 0;
static HMODULE SHDOCVW_hshell32 = 0;
-static HINSTANCE ieframe_instance;
-
-static HINSTANCE get_ieframe_instance(void)
-{
- static const WCHAR ieframe_dllW[] = {'i','e','f','r','a','m','e','.','d','l','l',0};
-
- if(!ieframe_instance)
- ieframe_instance = LoadLibraryW(ieframe_dllW);
-
- return ieframe_instance;
-}
static HRESULT get_ieframe_object(REFCLSID rclsid, REFIID riid, void **ppv)
{
- HINSTANCE ieframe_instance;
-
static HRESULT (WINAPI *ieframe_DllGetClassObject)(REFCLSID,REFIID,void**);
if(!ieframe_DllGetClassObject) {
- ieframe_instance = get_ieframe_instance();
- if(!ieframe_instance)
- return CLASS_E_CLASSNOTAVAILABLE;
-
- ieframe_DllGetClassObject = (void*)GetProcAddress(ieframe_instance, "DllGetClassObject");
+ ieframe_DllGetClassObject = (void*)GetProcAddress(GetModuleHandleW(L"ieframe.dll"), "DllGetClassObject");
if(!ieframe_DllGetClassObject)
return CLASS_E_CLASSNOTAVAILABLE;
}
@@ -119,7 +102,7 @@ DWORD WINAPI IEWinMain(LPSTR szCommandLine, int nShowWindow)
TRACE("%s %d\n", debugstr_a(szCommandLine), nShowWindow);
- pIEWinMain = (void*)GetProcAddress(get_ieframe_instance(), MAKEINTRESOURCEA(101));
+ pIEWinMain = (void*)GetProcAddress(GetModuleHandleW(L"ieframe.dll"), MAKEINTRESOURCEA(101));
if(!pIEWinMain)
ExitProcess(1);
@@ -149,7 +132,6 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad)
case DLL_PROCESS_DETACH:
if (fImpLoad) break;
if (SHDOCVW_hshell32) FreeLibrary(SHDOCVW_hshell32);
- if (ieframe_instance) FreeLibrary(ieframe_instance);
break;
}
return TRUE;
--
2.26.2
1
0
[PATCH v2 3/5] mfreadwrite: Abort ReadSample when unable to request any samples.
by Derek Lesho Oct. 27, 2020
by Derek Lesho Oct. 27, 2020
Oct. 27, 2020
Signed-off-by: Derek Lesho <dlesho(a)codeweavers.com>
---
v2: Add tests, results here: https://testbot.winehq.org/JobDetails.pl?Key=81074
---
dlls/mfreadwrite/reader.c | 14 +++++++++++---
dlls/mfreadwrite/tests/mfplat.c | 26 ++++++++++++++++++++++++++
2 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c
index 96a82b798ab..7dcae5a1cfa 100644
--- a/dlls/mfreadwrite/reader.c
+++ b/dlls/mfreadwrite/reader.c
@@ -439,7 +439,8 @@ static HRESULT source_reader_new_stream_handler(struct source_reader *reader, IM
}
if (reader->streams[i].requests)
- source_reader_request_sample(reader, &reader->streams[i]);
+ if (FAILED(source_reader_request_sample(reader, &reader->streams[i])))
+ WakeAllConditionVariable(&reader->sample_event);
}
break;
}
@@ -1780,10 +1781,17 @@ static HRESULT source_reader_read_sample(struct source_reader *reader, DWORD ind
stream->requests++;
if (FAILED(hr = source_reader_request_sample(reader, stream)))
WARN("Failed to request a sample, hr %#x.\n", hr);
+ if (stream->stream && !(stream->flags & STREAM_FLAG_SAMPLE_REQUESTED))
+ {
+ *actual_index = index;
+ *stream_flags = MF_SOURCE_READERF_ERROR;
+ *timestamp = 0;
+ break;
+ }
SleepConditionVariableCS(&reader->sample_event, &reader->cs, INFINITE);
}
-
- source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
+ if (SUCCEEDED(hr))
+ source_reader_get_read_result(reader, stream, flags, &hr, actual_index, stream_flags,
timestamp, sample);
}
}
diff --git a/dlls/mfreadwrite/tests/mfplat.c b/dlls/mfreadwrite/tests/mfplat.c
index cfe68cb6736..0e5053f905f 100644
--- a/dlls/mfreadwrite/tests/mfplat.c
+++ b/dlls/mfreadwrite/tests/mfplat.c
@@ -158,6 +158,8 @@ static HRESULT WINAPI test_media_stream_GetStreamDescriptor(IMFMediaStream *ifac
return S_OK;
}
+static BOOL fail_request_sample;
+
static HRESULT WINAPI test_media_stream_RequestSample(IMFMediaStream *iface, IUnknown *token)
{
struct test_media_stream *stream = impl_from_IMFMediaStream(iface);
@@ -165,6 +167,9 @@ static HRESULT WINAPI test_media_stream_RequestSample(IMFMediaStream *iface, IUn
IMFSample *sample;
HRESULT hr;
+ if (fail_request_sample)
+ return E_NOTIMPL;
+
hr = MFCreateSample(&sample);
ok(hr == S_OK, "Failed to create a sample, hr %#x.\n", hr);
hr = IMFSample_SetSampleTime(sample, 123);
@@ -977,6 +982,27 @@ static void test_source_reader_from_media_source(void)
ok(hr == MF_E_NOTACCEPTING, "Unexpected hr %#x.\n", hr);
IMFSourceReader_Release(reader);
+ IMFMediaSource_Release(source);
+
+ /* RequestSample failure. */
+ source = create_test_source();
+ ok(!!source, "Failed to create test source.\n");
+
+ fail_request_sample = TRUE;
+
+ hr = MFCreateSourceReaderFromMediaSource(source, NULL, &reader);
+ ok(hr == S_OK, "Failed to create source reader, hr %#x.\n", hr);
+
+ hr = IMFSourceReader_SetStreamSelection(reader, 0, TRUE);
+ ok(hr == S_OK, "Failed to select a stream, hr %#x.\n", hr);
+
+ hr = IMFSourceReader_ReadSample(reader, 0, 0, &actual_index, &stream_flags, ×tamp, &sample);
+ ok(hr == E_NOTIMPL, "Unexpected ReadSample result, hr %#x.\n", hr);
+
+ IMFSourceReader_Release(reader);
+ IMFMediaSource_Release(source);
+
+ fail_request_sample = FALSE;
}
START_TEST(mfplat)
--
2.28.0
1
0
Oct. 27, 2020
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfplat/buffer.c | 44 ++++++++++++++++++++++++++++++++++++++
dlls/mfplat/tests/mfplat.c | 13 +++++++++++
2 files changed, 57 insertions(+)
diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c
index a3311bc10f1..5e969e14ec9 100644
--- a/dlls/mfplat/buffer.c
+++ b/dlls/mfplat/buffer.c
@@ -31,6 +31,7 @@ struct memory_buffer
{
IMFMediaBuffer IMFMediaBuffer_iface;
IMF2DBuffer2 IMF2DBuffer2_iface;
+ IMFGetService IMFGetService_iface;
LONG refcount;
BYTE *data;
@@ -88,6 +89,11 @@ static struct memory_buffer *impl_from_IMF2DBuffer2(IMF2DBuffer2 *iface)
return CONTAINING_RECORD(iface, struct memory_buffer, IMF2DBuffer2_iface);
}
+static struct memory_buffer *impl_from_IMFGetService(IMFGetService *iface)
+{
+ return CONTAINING_RECORD(iface, struct memory_buffer, IMFGetService_iface);
+}
+
static inline struct sample *impl_from_IMFSample(IMFSample *iface)
{
return CONTAINING_RECORD(iface, struct sample, IMFSample_iface);
@@ -240,6 +246,10 @@ static HRESULT WINAPI memory_1d_2d_buffer_QueryInterface(IMFMediaBuffer *iface,
{
*out = &buffer->IMF2DBuffer2_iface;
}
+ else if (IsEqualIID(riid, &IID_IMFGetService))
+ {
+ *out = &buffer->IMFGetService_iface;
+ }
else
{
WARN("Unsupported interface %s.\n", debugstr_guid(riid));
@@ -511,6 +521,39 @@ static const IMF2DBuffer2Vtbl memory_2d_buffer_vtbl =
memory_2d_buffer_Copy2DTo,
};
+static HRESULT WINAPI memory_2d_buffer_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
+{
+ struct memory_buffer *buffer = impl_from_IMFGetService(iface);
+ return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj);
+}
+
+static ULONG WINAPI memory_2d_buffer_gs_AddRef(IMFGetService *iface)
+{
+ struct memory_buffer *buffer = impl_from_IMFGetService(iface);
+ return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface);
+}
+
+static ULONG WINAPI memory_2d_buffer_gs_Release(IMFGetService *iface)
+{
+ struct memory_buffer *buffer = impl_from_IMFGetService(iface);
+ return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface);
+}
+
+static HRESULT WINAPI memory_2d_buffer_gs_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
+
+ return E_NOTIMPL;
+}
+
+static const IMFGetServiceVtbl memory_2d_buffer_gs_vtbl =
+{
+ memory_2d_buffer_gs_QueryInterface,
+ memory_2d_buffer_gs_AddRef,
+ memory_2d_buffer_gs_Release,
+ memory_2d_buffer_gs_GetService,
+};
+
static HRESULT memory_buffer_init(struct memory_buffer *buffer, DWORD max_length, DWORD alignment,
const IMFMediaBufferVtbl *vtbl)
{
@@ -620,6 +663,7 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo
}
object->IMF2DBuffer2_iface.lpVtbl = &memory_2d_buffer_vtbl;
+ object->IMFGetService_iface.lpVtbl = &memory_2d_buffer_gs_vtbl;
object->_2d.plane_size = plane_size;
object->_2d.width = stride;
object->_2d.height = height;
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 971469ec574..906454851a8 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -1818,6 +1818,7 @@ static void test_system_memory_buffer(void)
HRESULT hr;
DWORD length, max;
BYTE *data, *data2;
+ IUnknown *unk;
hr = MFCreateMemoryBuffer(1024, NULL);
ok(hr == E_INVALIDARG || hr == E_POINTER, "got 0x%08x\n", hr);
@@ -1836,6 +1837,9 @@ static void test_system_memory_buffer(void)
hr = MFCreateMemoryBuffer(1024, &buffer);
ok(hr == S_OK, "got 0x%08x\n", hr);
+ hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&unk);
+ ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
+
hr = IMFMediaBuffer_GetMaxLength(buffer, NULL);
ok(hr == E_INVALIDARG || hr == E_POINTER, "got 0x%08x\n", hr);
@@ -5155,6 +5159,7 @@ static void test_MFCreate2DMediaBuffer(void)
IMF2DBuffer *_2dbuffer;
IMFMediaBuffer *buffer;
int i, pitch, pitch2;
+ IUnknown *unk;
HRESULT hr;
BOOL ret;
@@ -5177,6 +5182,10 @@ static void test_MFCreate2DMediaBuffer(void)
hr = pMFCreate2DMediaBuffer(2, 3, MAKEFOURCC('N','V','1','2'), FALSE, &buffer);
ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr);
+ hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&unk);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ IUnknown_Release(unk);
+
/* Full backing buffer size, with 64 bytes per row alignment. */
hr = IMFMediaBuffer_GetMaxLength(buffer, &max_length);
ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr);
@@ -5405,6 +5414,7 @@ static void test_MFCreateMediaBufferFromMediaType(void)
HRESULT hr;
IMFMediaType *media_type;
unsigned int i;
+ IUnknown *unk;
if (!pMFCreateMediaBufferFromMediaType)
{
@@ -5437,6 +5447,9 @@ static void test_MFCreateMediaBufferFromMediaType(void)
if (FAILED(hr))
break;
+ hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&unk);
+ ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
+
hr = IMFMediaBuffer_GetMaxLength(buffer, &length);
ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr);
ok(ptr->buffer_length == length, "%d: unexpected buffer length %u, expected %u.\n", i, length, ptr->buffer_length);
--
2.28.0
2
2
Signed-off-by: Esme Povirk <esme(a)codeweavers.com>
---
dlls/windowscodecs/Makefile.in | 1 +
dlls/windowscodecs/decoder.c | 76 +-
dlls/windowscodecs/libtiff.c | 1187 ++++++++++++++++++++
dlls/windowscodecs/main.c | 32 +-
dlls/windowscodecs/tiffformat.c | 1428 +-----------------------
dlls/windowscodecs/unix_iface.c | 1 +
dlls/windowscodecs/unix_lib.c | 8 +
dlls/windowscodecs/wincodecs_common.h | 19 +
dlls/windowscodecs/wincodecs_private.h | 7 +
9 files changed, 1312 insertions(+), 1447 deletions(-)
create mode 100644 dlls/windowscodecs/libtiff.c
diff --git a/dlls/windowscodecs/Makefile.in b/dlls/windowscodecs/Makefile.in
index 2472ef57d63..2dd6a78e147 100644
--- a/dlls/windowscodecs/Makefile.in
+++ b/dlls/windowscodecs/Makefile.in
@@ -23,6 +23,7 @@ C_SRCS = \
info.c \
jpegformat.c \
libpng.c \
+ libtiff.c \
main.c \
metadatahandler.c \
metadataquery.c \
diff --git a/dlls/windowscodecs/decoder.c b/dlls/windowscodecs/decoder.c
index 106aad4b92b..b51ca0a8def 100644
--- a/dlls/windowscodecs/decoder.c
+++ b/dlls/windowscodecs/decoder.c
@@ -216,9 +216,11 @@ static HRESULT WINAPI CommonDecoder_GetFrameCount(IWICBitmapDecoder *iface,
CommonDecoder *This = impl_from_IWICBitmapDecoder(iface);
if (!pCount) return E_INVALIDARG;
- if (!This->stream) return WINCODEC_ERR_WRONGSTATE;
+ if (This->stream)
+ *pCount = This->file_info.frame_count;
+ else
+ *pCount = 0;
- *pCount = This->file_info.frame_count;
return S_OK;
}
@@ -606,23 +608,69 @@ static HRESULT WINAPI CommonDecoderFrame_Block_GetReaderByIndex(IWICMetadataBloc
if (SUCCEEDED(hr))
{
- ULARGE_INTEGER offset, length;
+ if (This->metadata_blocks[nIndex].options & DECODER_BLOCK_FULL_STREAM)
+ {
+ LARGE_INTEGER offset;
+ offset.QuadPart = This->metadata_blocks[nIndex].offset;
- offset.QuadPart = This->metadata_blocks[nIndex].offset;
- length.QuadPart = This->metadata_blocks[nIndex].length;
- hr = IWICStream_InitializeFromIStreamRegion(stream, This->parent->stream,
- offset, length);
+ hr = IWICStream_InitializeFromIStream(stream, This->parent->stream);
- if (SUCCEEDED(hr))
- hr = ImagingFactory_CreateInstance(&IID_IWICComponentFactory, (void**)&factory);
+ if (SUCCEEDED(hr))
+ hr = IWICStream_Seek(stream, offset, STREAM_SEEK_SET, NULL);
+ }
+ else
+ {
+ ULARGE_INTEGER offset, length;
- if (SUCCEEDED(hr))
+ offset.QuadPart = This->metadata_blocks[nIndex].offset;
+ length.QuadPart = This->metadata_blocks[nIndex].length;
+
+ hr = IWICStream_InitializeFromIStreamRegion(stream, This->parent->stream,
+ offset, length);
+ }
+
+ if (This->metadata_blocks[nIndex].options & DECODER_BLOCK_READER_CLSID)
{
- hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
- &This->parent->decoder_info.block_format, NULL, This->metadata_blocks[nIndex].options,
- (IStream*)stream, ppIMetadataReader);
+ IWICMetadataReader *reader;
+ IWICPersistStream *persist;
+ if (SUCCEEDED(hr))
+ {
+ hr = create_instance(&This->metadata_blocks[nIndex].reader_clsid,
+ &IID_IWICMetadataReader, (void**)&reader);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist);
- IWICComponentFactory_Release(factory);
+ if (SUCCEEDED(hr))
+ {
+ hr = IWICPersistStream_LoadEx(persist, (IStream*)stream, NULL,
+ This->metadata_blocks[nIndex].options & DECODER_BLOCK_OPTION_MASK);
+
+ IWICPersistStream_Release(persist);
+ }
+
+ if (SUCCEEDED(hr))
+ *ppIMetadataReader = reader;
+ else
+ IWICMetadataReader_Release(reader);
+ }
+ }
+ else
+ {
+ if (SUCCEEDED(hr))
+ hr = ImagingFactory_CreateInstance(&IID_IWICComponentFactory, (void**)&factory);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
+ &This->parent->decoder_info.block_format, NULL,
+ This->metadata_blocks[nIndex].options & DECODER_BLOCK_OPTION_MASK,
+ (IStream*)stream, ppIMetadataReader);
+
+ IWICComponentFactory_Release(factory);
+ }
}
IWICStream_Release(stream);
diff --git a/dlls/windowscodecs/libtiff.c b/dlls/windowscodecs/libtiff.c
new file mode 100644
index 00000000000..27f89679766
--- /dev/null
+++ b/dlls/windowscodecs/libtiff.c
@@ -0,0 +1,1187 @@
+/*
+ * Copyright 2010 Vincent Povirk for CodeWeavers
+ * Copyright 2016 Dmitry Timoshkov
+ *
+ * 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 <stdarg.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_TIFFIO_H
+#include <tiffio.h>
+#endif
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winternl.h"
+#include "winbase.h"
+#include "objbase.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+#ifdef SONAME_LIBTIFF
+
+/* Workaround for broken libtiff 4.x headers on some 64-bit hosts which
+ * define TIFF_UINT64_T/toff_t as 32-bit for 32-bit builds, while they
+ * are supposed to be always 64-bit.
+ * TIFF_UINT64_T doesn't exist in libtiff 3.x, it was introduced in 4.x.
+ */
+#ifdef TIFF_UINT64_T
+# undef toff_t
+# define toff_t UINT64
+#endif
+
+static CRITICAL_SECTION init_tiff_cs;
+static CRITICAL_SECTION_DEBUG init_tiff_cs_debug =
+{
+ 0, 0, &init_tiff_cs,
+ { &init_tiff_cs_debug.ProcessLocksList,
+ &init_tiff_cs_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": init_tiff_cs") }
+};
+static CRITICAL_SECTION init_tiff_cs = { &init_tiff_cs_debug, -1, 0, 0, 0, 0 };
+
+static void *libtiff_handle;
+#define MAKE_FUNCPTR(f) static typeof(f) * p##f
+MAKE_FUNCPTR(TIFFClientOpen);
+MAKE_FUNCPTR(TIFFClose);
+MAKE_FUNCPTR(TIFFCurrentDirOffset);
+MAKE_FUNCPTR(TIFFGetField);
+MAKE_FUNCPTR(TIFFIsByteSwapped);
+MAKE_FUNCPTR(TIFFNumberOfDirectories);
+MAKE_FUNCPTR(TIFFReadDirectory);
+MAKE_FUNCPTR(TIFFReadEncodedStrip);
+MAKE_FUNCPTR(TIFFReadEncodedTile);
+MAKE_FUNCPTR(TIFFSetDirectory);
+MAKE_FUNCPTR(TIFFSetField);
+MAKE_FUNCPTR(TIFFWriteDirectory);
+MAKE_FUNCPTR(TIFFWriteScanline);
+#undef MAKE_FUNCPTR
+
+static void *load_libtiff(void)
+{
+ void *result;
+
+ RtlEnterCriticalSection(&init_tiff_cs);
+
+ if (!libtiff_handle &&
+ (libtiff_handle = dlopen(SONAME_LIBTIFF, RTLD_NOW)) != NULL)
+ {
+ void * (*pTIFFSetWarningHandler)(void *);
+ void * (*pTIFFSetWarningHandlerExt)(void *);
+
+#define LOAD_FUNCPTR(f) \
+ if((p##f = dlsym(libtiff_handle, #f)) == NULL) { \
+ ERR("failed to load symbol %s\n", #f); \
+ libtiff_handle = NULL; \
+ RtlLeaveCriticalSection(&init_tiff_cs); \
+ return NULL; \
+ }
+ LOAD_FUNCPTR(TIFFClientOpen);
+ LOAD_FUNCPTR(TIFFClose);
+ LOAD_FUNCPTR(TIFFCurrentDirOffset);
+ LOAD_FUNCPTR(TIFFGetField);
+ LOAD_FUNCPTR(TIFFIsByteSwapped);
+ LOAD_FUNCPTR(TIFFNumberOfDirectories);
+ LOAD_FUNCPTR(TIFFReadDirectory);
+ LOAD_FUNCPTR(TIFFReadEncodedStrip);
+ LOAD_FUNCPTR(TIFFReadEncodedTile);
+ LOAD_FUNCPTR(TIFFSetDirectory);
+ LOAD_FUNCPTR(TIFFSetField);
+ LOAD_FUNCPTR(TIFFWriteDirectory);
+ LOAD_FUNCPTR(TIFFWriteScanline);
+#undef LOAD_FUNCPTR
+
+ if ((pTIFFSetWarningHandler = dlsym(libtiff_handle, "TIFFSetWarningHandler")))
+ pTIFFSetWarningHandler(NULL);
+ if ((pTIFFSetWarningHandlerExt = dlsym(libtiff_handle, "TIFFSetWarningHandlerExt")))
+ pTIFFSetWarningHandlerExt(NULL);
+ }
+
+ result = libtiff_handle;
+
+ RtlLeaveCriticalSection(&init_tiff_cs);
+ return result;
+}
+
+static tsize_t tiff_stream_read(thandle_t client_data, tdata_t data, tsize_t size)
+{
+ IStream *stream = (IStream*)client_data;
+ ULONG bytes_read;
+ HRESULT hr;
+
+ hr = stream_read(stream, data, size, &bytes_read);
+ if (FAILED(hr)) bytes_read = 0;
+ return bytes_read;
+}
+
+static tsize_t tiff_stream_write(thandle_t client_data, tdata_t data, tsize_t size)
+{
+ FIXME("stub\n");
+ return 0;
+}
+
+static toff_t tiff_stream_seek(thandle_t client_data, toff_t offset, int whence)
+{
+ IStream *stream = (IStream*)client_data;
+ DWORD origin;
+ ULONGLONG new_position;
+ HRESULT hr;
+
+ switch (whence)
+ {
+ case SEEK_SET:
+ origin = STREAM_SEEK_SET;
+ break;
+ case SEEK_CUR:
+ origin = STREAM_SEEK_CUR;
+ break;
+ case SEEK_END:
+ origin = STREAM_SEEK_END;
+ break;
+ default:
+ ERR("unknown whence value %i\n", whence);
+ return -1;
+ }
+
+ hr = stream_seek(stream, offset, origin, &new_position);
+ if (SUCCEEDED(hr)) return new_position;
+ else return -1;
+}
+
+static int tiff_stream_close(thandle_t client_data)
+{
+ /* Caller is responsible for releasing the stream object. */
+ return 0;
+}
+
+static toff_t tiff_stream_size(thandle_t client_data)
+{
+ IStream *stream = (IStream*)client_data;
+ ULONGLONG size;
+ HRESULT hr;
+
+ hr = stream_getsize(stream, &size);
+
+ if (SUCCEEDED(hr)) return size;
+ else return -1;
+}
+
+static int tiff_stream_map(thandle_t client_data, tdata_t *addr, toff_t *size)
+{
+ /* Cannot mmap streams */
+ return 0;
+}
+
+static void tiff_stream_unmap(thandle_t client_data, tdata_t addr, toff_t size)
+{
+ /* No need to ever do this, since we can't map things. */
+}
+
+static TIFF* tiff_open_stream(IStream *stream, const char *mode)
+{
+ stream_seek(stream, 0, STREAM_SEEK_SET, NULL);
+
+ return pTIFFClientOpen("<IStream object>", mode, stream, tiff_stream_read,
+ tiff_stream_write, (void *)tiff_stream_seek, tiff_stream_close,
+ (void *)tiff_stream_size, (void *)tiff_stream_map, (void *)tiff_stream_unmap);
+}
+
+typedef struct {
+ struct decoder_frame frame;
+ int bps;
+ int samples;
+ int source_bpp;
+ int planar;
+ int indexed;
+ int reverse_bgr;
+ int invert_grayscale;
+ UINT tile_width, tile_height;
+ UINT tile_stride;
+ UINT tile_size;
+ int tiled;
+ UINT tiles_across;
+} tiff_decode_info;
+
+struct tiff_decoder
+{
+ struct decoder decoder;
+ IStream *stream;
+ TIFF *tiff;
+ DWORD frame_count;
+ DWORD cached_frame;
+ tiff_decode_info cached_decode_info;
+ INT cached_tile_x, cached_tile_y;
+ BYTE *cached_tile;
+};
+
+static inline struct tiff_decoder *impl_from_decoder(struct decoder* iface)
+{
+ return CONTAINING_RECORD(iface, struct tiff_decoder, decoder);
+}
+
+static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info)
+{
+ uint16 photometric, bps, samples, planar;
+ uint16 extra_sample_count, extra_sample, *extra_samples;
+ uint16 *red, *green, *blue;
+ UINT resolution_unit;
+ float xres=0.0, yres=0.0;
+ int ret, i;
+ const BYTE *profile;
+ UINT len;
+
+ decode_info->indexed = 0;
+ decode_info->reverse_bgr = 0;
+ decode_info->invert_grayscale = 0;
+ decode_info->tiled = 0;
+ decode_info->source_bpp = 0;
+
+ ret = pTIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
+ if (!ret)
+ {
+ WARN("missing PhotometricInterpretation tag\n");
+ return E_FAIL;
+ }
+
+ ret = pTIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bps);
+ if (!ret) bps = 1;
+ decode_info->bps = bps;
+
+ ret = pTIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samples);
+ if (!ret) samples = 1;
+ decode_info->samples = samples;
+
+ if (samples == 1)
+ planar = 1;
+ else
+ {
+ ret = pTIFFGetField(tiff, TIFFTAG_PLANARCONFIG, &planar);
+ if (!ret) planar = 1;
+ if (planar != 1)
+ {
+ FIXME("unhandled planar configuration %u\n", planar);
+ return E_FAIL;
+ }
+ }
+ decode_info->planar = planar;
+
+ TRACE("planar %u, photometric %u, samples %u, bps %u\n", planar, photometric, samples, bps);
+
+ switch(photometric)
+ {
+ case 0: /* WhiteIsZero */
+ decode_info->invert_grayscale = 1;
+ /* fall through */
+ case 1: /* BlackIsZero */
+ if (samples == 2)
+ {
+ ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
+ if (!ret)
+ {
+ extra_sample_count = 1;
+ extra_sample = 0;
+ extra_samples = &extra_sample;
+ }
+ }
+ else if (samples != 1)
+ {
+ FIXME("unhandled %dbpp sample count %u\n", bps, samples);
+ return E_FAIL;
+ }
+
+ decode_info->frame.bpp = bps * samples;
+ decode_info->source_bpp = decode_info->frame.bpp;
+ switch (bps)
+ {
+ case 1:
+ if (samples != 1)
+ {
+ FIXME("unhandled 1bpp sample count %u\n", samples);
+ return E_FAIL;
+ }
+ decode_info->frame.pixel_format = GUID_WICPixelFormatBlackWhite;
+ break;
+ case 4:
+ if (samples != 1)
+ {
+ FIXME("unhandled 4bpp grayscale sample count %u\n", samples);
+ return E_FAIL;
+ }
+ decode_info->frame.pixel_format = GUID_WICPixelFormat4bppGray;
+ break;
+ case 8:
+ if (samples == 1)
+ decode_info->frame.pixel_format = GUID_WICPixelFormat8bppGray;
+ else
+ {
+ decode_info->frame.bpp = 32;
+
+ switch(extra_samples[0])
+ {
+ case 1: /* Associated (pre-multiplied) alpha data */
+ decode_info->frame.pixel_format = GUID_WICPixelFormat32bppPBGRA;
+ break;
+ case 0: /* Unspecified data */
+ case 2: /* Unassociated alpha data */
+ decode_info->frame.pixel_format = GUID_WICPixelFormat32bppBGRA;
+ break;
+ default:
+ FIXME("unhandled extra sample type %u\n", extra_samples[0]);
+ return E_FAIL;
+ }
+ }
+ break;
+ case 16:
+ if (samples != 1)
+ {
+ FIXME("unhandled 16bpp grayscale sample count %u\n", samples);
+ return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+ }
+ decode_info->frame.pixel_format = GUID_WICPixelFormat16bppGray;
+ break;
+ case 32:
+ if (samples != 1)
+ {
+ FIXME("unhandled 32bpp grayscale sample count %u\n", samples);
+ return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+ }
+ decode_info->frame.pixel_format = GUID_WICPixelFormat32bppGrayFloat;
+ break;
+ default:
+ WARN("unhandled greyscale bit count %u\n", bps);
+ return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+ }
+ break;
+ case 2: /* RGB */
+ if (samples == 4)
+ {
+ ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
+ if (!ret)
+ {
+ extra_sample_count = 1;
+ extra_sample = 0;
+ extra_samples = &extra_sample;
+ }
+ }
+ else if (samples != 3)
+ {
+ FIXME("unhandled RGB sample count %u\n", samples);
+ return E_FAIL;
+ }
+
+ decode_info->frame.bpp = max(bps, 8) * samples;
+ decode_info->source_bpp = bps * samples;
+ switch(bps)
+ {
+ case 1:
+ case 4:
+ case 8:
+ decode_info->reverse_bgr = 1;
+ if (samples == 3)
+ decode_info->frame.pixel_format = GUID_WICPixelFormat24bppBGR;
+ else
+ switch(extra_samples[0])
+ {
+ case 1: /* Associated (pre-multiplied) alpha data */
+ decode_info->frame.pixel_format = GUID_WICPixelFormat32bppPBGRA;
+ break;
+ case 0: /* Unspecified data */
+ case 2: /* Unassociated alpha data */
+ decode_info->frame.pixel_format = GUID_WICPixelFormat32bppBGRA;
+ break;
+ default:
+ FIXME("unhandled extra sample type %i\n", extra_samples[0]);
+ return E_FAIL;
+ }
+ break;
+ case 16:
+ if (samples == 3)
+ decode_info->frame.pixel_format = GUID_WICPixelFormat48bppRGB;
+ else
+ switch(extra_samples[0])
+ {
+ case 1: /* Associated (pre-multiplied) alpha data */
+ decode_info->frame.pixel_format = GUID_WICPixelFormat64bppPRGBA;
+ break;
+ case 0: /* Unspecified data */
+ case 2: /* Unassociated alpha data */
+ decode_info->frame.pixel_format = GUID_WICPixelFormat64bppRGBA;
+ break;
+ default:
+ FIXME("unhandled extra sample type %i\n", extra_samples[0]);
+ return E_FAIL;
+ }
+ break;
+ case 32:
+ if (samples == 3)
+ decode_info->frame.pixel_format = GUID_WICPixelFormat96bppRGBFloat;
+ else
+ switch(extra_samples[0])
+ {
+ case 1: /* Associated (pre-multiplied) alpha data */
+ decode_info->frame.pixel_format = GUID_WICPixelFormat128bppPRGBAFloat;
+ break;
+ case 0: /* Unspecified data */
+ case 2: /* Unassociated alpha data */
+ decode_info->frame.pixel_format = GUID_WICPixelFormat128bppRGBAFloat;
+ break;
+ default:
+ FIXME("unhandled extra sample type %i\n", extra_samples[0]);
+ return E_FAIL;
+ }
+ break;
+ default:
+ WARN("unhandled RGB bit count %u\n", bps);
+ return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+ }
+ break;
+ case 3: /* RGB Palette */
+ if (samples != 1)
+ {
+ FIXME("unhandled indexed sample count %u\n", samples);
+ return E_FAIL;
+ }
+
+ decode_info->indexed = 1;
+ decode_info->frame.bpp = bps;
+ switch (bps)
+ {
+ case 1:
+ decode_info->frame.pixel_format = GUID_WICPixelFormat1bppIndexed;
+ break;
+ case 2:
+ decode_info->frame.pixel_format = GUID_WICPixelFormat2bppIndexed;
+ break;
+ case 4:
+ decode_info->frame.pixel_format = GUID_WICPixelFormat4bppIndexed;
+ break;
+ case 8:
+ decode_info->frame.pixel_format = GUID_WICPixelFormat8bppIndexed;
+ break;
+ default:
+ FIXME("unhandled indexed bit count %u\n", bps);
+ return E_NOTIMPL;
+ }
+ break;
+
+ case 5: /* Separated */
+ if (samples != 4)
+ {
+ FIXME("unhandled Separated sample count %u\n", samples);
+ return E_FAIL;
+ }
+
+ decode_info->frame.bpp = bps * samples;
+ switch(bps)
+ {
+ case 8:
+ decode_info->frame.pixel_format = GUID_WICPixelFormat32bppCMYK;
+ break;
+ case 16:
+ decode_info->frame.pixel_format = GUID_WICPixelFormat64bppCMYK;
+ break;
+
+ default:
+ WARN("unhandled Separated bit count %u\n", bps);
+ return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+ }
+ break;
+
+ case 4: /* Transparency mask */
+ case 6: /* YCbCr */
+ case 8: /* CIELab */
+ default:
+ FIXME("unhandled PhotometricInterpretation %u\n", photometric);
+ return E_FAIL;
+ }
+
+ ret = pTIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &decode_info->frame.width);
+ if (!ret)
+ {
+ WARN("missing image width\n");
+ return E_FAIL;
+ }
+
+ ret = pTIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &decode_info->frame.height);
+ if (!ret)
+ {
+ WARN("missing image length\n");
+ return E_FAIL;
+ }
+
+ if ((ret = pTIFFGetField(tiff, TIFFTAG_TILEWIDTH, &decode_info->tile_width)))
+ {
+ decode_info->tiled = 1;
+
+ ret = pTIFFGetField(tiff, TIFFTAG_TILELENGTH, &decode_info->tile_height);
+ if (!ret)
+ {
+ WARN("missing tile height\n");
+ return E_FAIL;
+ }
+
+ decode_info->tile_stride = ((decode_info->frame.bpp * decode_info->tile_width + 7)/8);
+ decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
+ decode_info->tiles_across = (decode_info->frame.width + decode_info->tile_width - 1) / decode_info->tile_width;
+ }
+ else if ((ret = pTIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &decode_info->tile_height)))
+ {
+ if (decode_info->tile_height > decode_info->frame.height)
+ decode_info->tile_height = decode_info->frame.height;
+ decode_info->tile_width = decode_info->frame.width;
+ decode_info->tile_stride = ((decode_info->frame.bpp * decode_info->tile_width + 7)/8);
+ decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
+ }
+ else
+ {
+ /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
+ decode_info->tile_height = decode_info->frame.height;
+ decode_info->tile_width = decode_info->frame.width;
+ decode_info->tile_stride = ((decode_info->frame.bpp * decode_info->tile_width + 7)/8);
+ decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
+ }
+
+ resolution_unit = 0;
+ pTIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resolution_unit);
+
+ ret = pTIFFGetField(tiff, TIFFTAG_XRESOLUTION, &xres);
+ if (!ret)
+ {
+ WARN("missing X resolution\n");
+ }
+ /* Emulate the behavior of current libtiff versions (libtiff commit a39f6131)
+ * yielding 0 instead of INFINITY for IFD_RATIONAL fields with denominator 0. */
+ if (!isfinite(xres))
+ {
+ xres = 0.0;
+ }
+
+ ret = pTIFFGetField(tiff, TIFFTAG_YRESOLUTION, &yres);
+ if (!ret)
+ {
+ WARN("missing Y resolution\n");
+ }
+ if (!isfinite(yres))
+ {
+ yres = 0.0;
+ }
+
+ if (xres == 0.0 || yres == 0.0)
+ {
+ decode_info->frame.dpix = decode_info->frame.dpiy = 96.0;
+ }
+ else
+ {
+ switch (resolution_unit)
+ {
+ default:
+ FIXME("unknown resolution unit %i\n", resolution_unit);
+ /* fall through */
+ case 0: /* Not set */
+ case 1: /* Relative measurements */
+ case 2: /* Inch */
+ decode_info->frame.dpix = xres;
+ decode_info->frame.dpiy = yres;
+ break;
+ case 3: /* Centimeter */
+ decode_info->frame.dpix = xres * 2.54;
+ decode_info->frame.dpiy = yres * 2.54;
+ break;
+ }
+ }
+
+ if (decode_info->indexed &&
+ pTIFFGetField(tiff, TIFFTAG_COLORMAP, &red, &green, &blue))
+ {
+ decode_info->frame.num_colors = 1 << decode_info->bps;
+ for (i=0; i<decode_info->frame.num_colors; i++)
+ {
+ decode_info->frame.palette[i] = 0xff000000 |
+ ((red[i]<<8) & 0xff0000) |
+ (green[i] & 0xff00) |
+ ((blue[i]>>8) & 0xff);
+ }
+ }
+ else
+ {
+ decode_info->frame.num_colors = 0;
+ }
+
+ if (pTIFFGetField(tiff, TIFFTAG_ICCPROFILE, &len, &profile))
+ decode_info->frame.num_color_contexts = 1;
+ else
+ decode_info->frame.num_color_contexts = 0;
+
+ return S_OK;
+}
+
+static HRESULT CDECL tiff_decoder_initialize(struct decoder* iface, IStream *stream, struct decoder_stat *st)
+{
+ struct tiff_decoder *This = impl_from_decoder(iface);
+ HRESULT hr;
+
+ This->tiff = tiff_open_stream(stream, "r");
+ if (!This->tiff)
+ return E_FAIL;
+
+ This->frame_count = pTIFFNumberOfDirectories(This->tiff);
+ This->cached_frame = 0;
+ hr = tiff_get_decode_info(This->tiff, &This->cached_decode_info);
+ if (FAILED(hr))
+ goto fail;
+
+ st->frame_count = This->frame_count;
+ st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
+ WICBitmapDecoderCapabilityCanDecodeSomeImages |
+ WICBitmapDecoderCapabilityCanEnumerateMetadata;
+ return S_OK;
+
+fail:
+ pTIFFClose(This->tiff);
+ This->tiff = NULL;
+ return hr;
+}
+
+static HRESULT tiff_decoder_select_frame(struct tiff_decoder* This, DWORD frame)
+{
+ HRESULT hr;
+ UINT prev_tile_size;
+ int res;
+
+ if (frame >= This->frame_count)
+ return E_INVALIDARG;
+
+ if (This->cached_frame == frame)
+ return S_OK;
+
+ prev_tile_size = This->cached_tile ? This->cached_decode_info.tile_size : 0;
+
+ res = pTIFFSetDirectory(This->tiff, frame);
+ if (!res)
+ return E_INVALIDARG;
+
+ hr = tiff_get_decode_info(This->tiff, &This->cached_decode_info);
+
+ This->cached_tile_x = -1;
+
+ if (SUCCEEDED(hr))
+ {
+ This->cached_frame = frame;
+ if (This->cached_decode_info.tile_size > prev_tile_size)
+ {
+ free(This->cached_tile);
+ This->cached_tile = NULL;
+ }
+ }
+ else
+ {
+ /* Set an invalid value to ensure we'll refresh cached_decode_info before using it. */
+ This->cached_frame = This->frame_count;
+ free(This->cached_tile);
+ This->cached_tile = NULL;
+ }
+
+ return hr;
+}
+
+static HRESULT CDECL tiff_decoder_get_frame_info(struct decoder* iface, UINT frame, struct decoder_frame *info)
+{
+ struct tiff_decoder *This = impl_from_decoder(iface);
+ HRESULT hr;
+
+ hr = tiff_decoder_select_frame(This, frame);
+ if (SUCCEEDED(hr))
+ {
+ *info = This->cached_decode_info.frame;
+ }
+
+ return hr;
+}
+
+static HRESULT tiff_decoder_read_tile(struct tiff_decoder *This, UINT tile_x, UINT tile_y)
+{
+ tsize_t ret;
+ int swap_bytes;
+ tiff_decode_info *info = &This->cached_decode_info;
+
+ swap_bytes = pTIFFIsByteSwapped(This->tiff);
+
+ if (info->tiled)
+ ret = pTIFFReadEncodedTile(This->tiff, tile_x + tile_y * info->tiles_across, This->cached_tile, info->tile_size);
+ else
+ ret = pTIFFReadEncodedStrip(This->tiff, tile_y, This->cached_tile, info->tile_size);
+
+ if (ret == -1)
+ return E_FAIL;
+
+ /* 3bps RGB */
+ if (info->source_bpp == 3 && info->samples == 3 && info->frame.bpp == 24)
+ {
+ BYTE *srcdata, *src, *dst;
+ DWORD x, y, count, width_bytes = (info->tile_width * 3 + 7) / 8;
+
+ count = width_bytes * info->tile_height;
+
+ srcdata = malloc(count);
+ if (!srcdata) return E_OUTOFMEMORY;
+ memcpy(srcdata, This->cached_tile, count);
+
+ for (y = 0; y < info->tile_height; y++)
+ {
+ src = srcdata + y * width_bytes;
+ dst = This->cached_tile + y * info->tile_width * 3;
+
+ for (x = 0; x < info->tile_width; x += 8)
+ {
+ dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */
+ dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */
+ dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */
+ if (x + 1 < info->tile_width)
+ {
+ dst[5] = (src[0] & 0x10) ? 0xff : 0; /* R */
+ dst[4] = (src[0] & 0x08) ? 0xff : 0; /* G */
+ dst[3] = (src[0] & 0x04) ? 0xff : 0; /* B */
+ }
+ if (x + 2 < info->tile_width)
+ {
+ dst[8] = (src[0] & 0x02) ? 0xff : 0; /* R */
+ dst[7] = (src[0] & 0x01) ? 0xff : 0; /* G */
+ dst[6] = (src[1] & 0x80) ? 0xff : 0; /* B */
+ }
+ if (x + 3 < info->tile_width)
+ {
+ dst[11] = (src[1] & 0x40) ? 0xff : 0; /* R */
+ dst[10] = (src[1] & 0x20) ? 0xff : 0; /* G */
+ dst[9] = (src[1] & 0x10) ? 0xff : 0; /* B */
+ }
+ if (x + 4 < info->tile_width)
+ {
+ dst[14] = (src[1] & 0x08) ? 0xff : 0; /* R */
+ dst[13] = (src[1] & 0x04) ? 0xff : 0; /* G */
+ dst[12] = (src[1] & 0x02) ? 0xff : 0; /* B */
+ }
+ if (x + 5 < info->tile_width)
+ {
+ dst[17] = (src[1] & 0x01) ? 0xff : 0; /* R */
+ dst[16] = (src[2] & 0x80) ? 0xff : 0; /* G */
+ dst[15] = (src[2] & 0x40) ? 0xff : 0; /* B */
+ }
+ if (x + 6 < info->tile_width)
+ {
+ dst[20] = (src[2] & 0x20) ? 0xff : 0; /* R */
+ dst[19] = (src[2] & 0x10) ? 0xff : 0; /* G */
+ dst[18] = (src[2] & 0x08) ? 0xff : 0; /* B */
+ }
+ if (x + 7 < info->tile_width)
+ {
+ dst[23] = (src[2] & 0x04) ? 0xff : 0; /* R */
+ dst[22] = (src[2] & 0x02) ? 0xff : 0; /* G */
+ dst[21] = (src[2] & 0x01) ? 0xff : 0; /* B */
+ }
+ src += 3;
+ dst += 24;
+ }
+ }
+
+ free(srcdata);
+ }
+ /* 12bps RGB */
+ else if (info->source_bpp == 12 && info->samples == 3 && info->frame.bpp == 24)
+ {
+ BYTE *srcdata, *src, *dst;
+ DWORD x, y, count, width_bytes = (info->tile_width * 12 + 7) / 8;
+
+ count = width_bytes * info->tile_height;
+
+ srcdata = malloc(count);
+ if (!srcdata) return E_OUTOFMEMORY;
+ memcpy(srcdata, This->cached_tile, count);
+
+ for (y = 0; y < info->tile_height; y++)
+ {
+ src = srcdata + y * width_bytes;
+ dst = This->cached_tile + y * info->tile_width * 3;
+
+ for (x = 0; x < info->tile_width; x += 2)
+ {
+ dst[0] = ((src[1] & 0xf0) >> 4) * 17; /* B */
+ dst[1] = (src[0] & 0x0f) * 17; /* G */
+ dst[2] = ((src[0] & 0xf0) >> 4) * 17; /* R */
+ if (x + 1 < info->tile_width)
+ {
+ dst[5] = (src[1] & 0x0f) * 17; /* B */
+ dst[4] = ((src[2] & 0xf0) >> 4) * 17; /* G */
+ dst[3] = (src[2] & 0x0f) * 17; /* R */
+ }
+ src += 3;
+ dst += 6;
+ }
+ }
+
+ free(srcdata);
+ }
+ /* 4bps RGBA */
+ else if (info->source_bpp == 4 && info->samples == 4 && info->frame.bpp == 32)
+ {
+ BYTE *srcdata, *src, *dst;
+ DWORD x, y, count, width_bytes = (info->tile_width * 3 + 7) / 8;
+
+ count = width_bytes * info->tile_height;
+
+ srcdata = malloc(count);
+ if (!srcdata) return E_OUTOFMEMORY;
+ memcpy(srcdata, This->cached_tile, count);
+
+ for (y = 0; y < info->tile_height; y++)
+ {
+ src = srcdata + y * width_bytes;
+ dst = This->cached_tile + y * info->tile_width * 4;
+
+ /* 1 source byte expands to 2 BGRA samples */
+
+ for (x = 0; x < info->tile_width; x += 2)
+ {
+ dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */
+ dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */
+ dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */
+ dst[3] = (src[0] & 0x10) ? 0xff : 0; /* A */
+ if (x + 1 < info->tile_width)
+ {
+ dst[4] = (src[0] & 0x02) ? 0xff : 0; /* B */
+ dst[5] = (src[0] & 0x04) ? 0xff : 0; /* G */
+ dst[6] = (src[0] & 0x08) ? 0xff : 0; /* R */
+ dst[7] = (src[0] & 0x01) ? 0xff : 0; /* A */
+ }
+ src++;
+ dst += 8;
+ }
+ }
+
+ free(srcdata);
+ }
+ /* 16bps RGBA */
+ else if (info->source_bpp == 16 && info->samples == 4 && info->frame.bpp == 32)
+ {
+ BYTE *srcdata, *src, *dst;
+ DWORD x, y, count, width_bytes = (info->tile_width * 12 + 7) / 8;
+
+ count = width_bytes * info->tile_height;
+
+ srcdata = malloc(count);
+ if (!srcdata) return E_OUTOFMEMORY;
+ memcpy(srcdata, This->cached_tile, count);
+
+ for (y = 0; y < info->tile_height; y++)
+ {
+ src = srcdata + y * width_bytes;
+ dst = This->cached_tile + y * info->tile_width * 4;
+
+ for (x = 0; x < info->tile_width; x++)
+ {
+ dst[0] = ((src[1] & 0xf0) >> 4) * 17; /* B */
+ dst[1] = (src[0] & 0x0f) * 17; /* G */
+ dst[2] = ((src[0] & 0xf0) >> 4) * 17; /* R */
+ dst[3] = (src[1] & 0x0f) * 17; /* A */
+ src += 2;
+ dst += 4;
+ }
+ }
+
+ free(srcdata);
+ }
+ /* 8bpp grayscale with extra alpha */
+ else if (info->source_bpp == 16 && info->samples == 2 && info->frame.bpp == 32)
+ {
+ BYTE *src;
+ DWORD *dst, count = info->tile_width * info->tile_height;
+
+ src = This->cached_tile + info->tile_width * info->tile_height * 2 - 2;
+ dst = (DWORD *)(This->cached_tile + info->tile_size - 4);
+
+ while (count--)
+ {
+ *dst-- = src[0] | (src[0] << 8) | (src[0] << 16) | (src[1] << 24);
+ src -= 2;
+ }
+ }
+
+ if (info->reverse_bgr)
+ {
+ if (info->bps == 8)
+ {
+ UINT sample_count = info->samples;
+
+ reverse_bgr8(sample_count, This->cached_tile, info->tile_width,
+ info->tile_height, info->tile_width * sample_count);
+ }
+ }
+
+ if (swap_bytes && info->bps > 8)
+ {
+ UINT row, i, samples_per_row;
+ BYTE *sample, temp;
+
+ samples_per_row = info->tile_width * info->samples;
+
+ switch(info->bps)
+ {
+ case 16:
+ for (row=0; row<info->tile_height; row++)
+ {
+ sample = This->cached_tile + row * info->tile_stride;
+ for (i=0; i<samples_per_row; i++)
+ {
+ temp = sample[1];
+ sample[1] = sample[0];
+ sample[0] = temp;
+ sample += 2;
+ }
+ }
+ break;
+ default:
+ ERR("unhandled bps for byte swap %u\n", info->bps);
+ return E_FAIL;
+ }
+ }
+
+ if (info->invert_grayscale)
+ {
+ BYTE *byte, *end;
+
+ if (info->samples != 1)
+ {
+ ERR("cannot invert grayscale image with %u samples\n", info->samples);
+ return E_FAIL;
+ }
+
+ end = This->cached_tile+info->tile_size;
+
+ for (byte = This->cached_tile; byte != end; byte++)
+ *byte = ~(*byte);
+ }
+
+ This->cached_tile_x = tile_x;
+ This->cached_tile_y = tile_y;
+
+ return S_OK;
+}
+
+static HRESULT CDECL tiff_decoder_copy_pixels(struct decoder* iface, UINT frame,
+ const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer)
+{
+ struct tiff_decoder *This = impl_from_decoder(iface);
+ HRESULT hr;
+ UINT min_tile_x, max_tile_x, min_tile_y, max_tile_y;
+ UINT tile_x, tile_y;
+ BYTE *dst_tilepos;
+ WICRect rc;
+ tiff_decode_info *info = &This->cached_decode_info;
+
+ hr = tiff_decoder_select_frame(This, frame);
+ if (FAILED(hr))
+ return hr;
+
+ if (!This->cached_tile)
+ {
+ This->cached_tile = malloc(info->tile_size);
+ if (!This->cached_tile)
+ return E_OUTOFMEMORY;
+ }
+
+ min_tile_x = prc->X / info->tile_width;
+ min_tile_y = prc->Y / info->tile_height;
+ max_tile_x = (prc->X+prc->Width-1) / info->tile_width;
+ max_tile_y = (prc->Y+prc->Height-1) / info->tile_height;
+
+ for (tile_x=min_tile_x; tile_x <= max_tile_x; tile_x++)
+ {
+ for (tile_y=min_tile_y; tile_y <= max_tile_y; tile_y++)
+ {
+ if (tile_x != This->cached_tile_x || tile_y != This->cached_tile_y)
+ {
+ hr = tiff_decoder_read_tile(This, tile_x, tile_y);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (prc->X < tile_x * info->tile_width)
+ rc.X = 0;
+ else
+ rc.X = prc->X - tile_x * info->tile_width;
+
+ if (prc->Y < tile_y * info->tile_height)
+ rc.Y = 0;
+ else
+ rc.Y = prc->Y - tile_y * info->tile_height;
+
+ if (prc->X+prc->Width > (tile_x+1) * info->tile_width)
+ rc.Width = info->tile_width - rc.X;
+ else if (prc->X < tile_x * info->tile_width)
+ rc.Width = prc->Width + prc->X - tile_x * info->tile_width;
+ else
+ rc.Width = prc->Width;
+
+ if (prc->Y+prc->Height > (tile_y+1) * info->tile_height)
+ rc.Height = info->tile_height - rc.Y;
+ else if (prc->Y < tile_y * info->tile_height)
+ rc.Height = prc->Height + prc->Y - tile_y * info->tile_height;
+ else
+ rc.Height = prc->Height;
+
+ dst_tilepos = buffer + (stride * ((rc.Y + tile_y * info->tile_height) - prc->Y)) +
+ ((info->frame.bpp * ((rc.X + tile_x * info->tile_width) - prc->X) + 7) / 8);
+
+ hr = copy_pixels(info->frame.bpp, This->cached_tile,
+ info->tile_width, info->tile_height, info->tile_stride,
+ &rc, stride, buffersize, dst_tilepos);
+ }
+
+ if (FAILED(hr))
+ {
+ TRACE("<-- 0x%x\n", hr);
+ return hr;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+static HRESULT CDECL tiff_decoder_get_color_context(struct decoder *iface,
+ UINT frame, UINT num, BYTE **data, DWORD *datasize)
+{
+ struct tiff_decoder *This = impl_from_decoder(iface);
+ const BYTE *profile;
+ UINT len;
+ HRESULT hr;
+
+ hr = tiff_decoder_select_frame(This, frame);
+ if (FAILED(hr))
+ return hr;
+
+ if (!pTIFFGetField(This->tiff, TIFFTAG_ICCPROFILE, &len, &profile))
+ {
+ return E_UNEXPECTED;
+ }
+
+ *datasize = len;
+ *data = RtlAllocateHeap(GetProcessHeap(), 0, len);
+ if (!*data)
+ return E_OUTOFMEMORY;
+
+ memcpy(*data, profile, len);
+
+ return S_OK;
+}
+
+static HRESULT CDECL tiff_decoder_get_metadata_blocks(struct decoder *iface,
+ UINT frame, UINT *count, struct decoder_block **blocks)
+{
+ struct tiff_decoder *This = impl_from_decoder(iface);
+ HRESULT hr;
+ BOOL byte_swapped;
+ struct decoder_block result;
+
+ hr = tiff_decoder_select_frame(This, frame);
+ if (FAILED(hr))
+ return hr;
+
+ *count = 1;
+
+ result.offset = pTIFFCurrentDirOffset(This->tiff);
+ result.length = 0;
+
+ byte_swapped = pTIFFIsByteSwapped(This->tiff);
+#ifdef WORDS_BIGENDIAN
+ result.options = byte_swapped ? WICPersistOptionLittleEndian : WICPersistOptionBigEndian;
+#else
+ result.options = byte_swapped ? WICPersistOptionBigEndian : WICPersistOptionLittleEndian;
+#endif
+ result.options |= WICPersistOptionNoCacheStream|DECODER_BLOCK_FULL_STREAM|DECODER_BLOCK_READER_CLSID;
+ result.reader_clsid = CLSID_WICIfdMetadataReader;
+
+ *blocks = malloc(sizeof(**blocks));
+ **blocks = result;
+
+ return S_OK;
+}
+
+static void CDECL tiff_decoder_destroy(struct decoder* iface)
+{
+ struct tiff_decoder *This = impl_from_decoder(iface);
+ if (This->tiff) pTIFFClose(This->tiff);
+ free(This->cached_tile);
+ RtlFreeHeap(GetProcessHeap(), 0, This);
+}
+
+static const struct decoder_funcs tiff_decoder_vtable = {
+ tiff_decoder_initialize,
+ tiff_decoder_get_frame_info,
+ tiff_decoder_copy_pixels,
+ tiff_decoder_get_metadata_blocks,
+ tiff_decoder_get_color_context,
+ tiff_decoder_destroy
+};
+
+HRESULT CDECL tiff_decoder_create(struct decoder_info *info, struct decoder **result)
+{
+ struct tiff_decoder *This;
+
+ if (!load_libtiff())
+ {
+ ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF);
+ return E_FAIL;
+ }
+
+ This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));
+ if (!This) return E_OUTOFMEMORY;
+
+ This->decoder.vtable = &tiff_decoder_vtable;
+ This->tiff = NULL;
+ This->cached_tile = NULL;
+ This->cached_tile_x = -1;
+ *result = &This->decoder;
+
+ info->container_format = GUID_ContainerFormatTiff;
+ info->block_format = GUID_ContainerFormatTiff;
+ info->clsid = CLSID_WICTiffDecoder;
+
+ return S_OK;
+}
+
+#else /* !SONAME_LIBTIFF */
+
+HRESULT CDECL tiff_decoder_create(struct decoder_info *info, struct decoder **result)
+{
+ ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
+ return E_FAIL;
+}
+
+#endif
diff --git a/dlls/windowscodecs/main.c b/dlls/windowscodecs/main.c
index 1b5057b1b95..7976b96a393 100644
--- a/dlls/windowscodecs/main.c
+++ b/dlls/windowscodecs/main.c
@@ -191,6 +191,19 @@ HRESULT write_source(IWICBitmapFrameEncode *iface,
return hr;
}
+HRESULT CDECL stream_getsize(IStream *stream, ULONGLONG *size)
+{
+ STATSTG statstg;
+ HRESULT hr;
+
+ hr = IStream_Stat(stream, &statstg, STATFLAG_NONAME);
+
+ if (SUCCEEDED(hr))
+ *size = statstg.cbSize.QuadPart;
+
+ return hr;
+}
+
HRESULT CDECL stream_read(IStream *stream, void *buffer, ULONG read, ULONG *bytes_read)
{
return IStream_Read(stream, buffer, read, bytes_read);
@@ -210,25 +223,6 @@ HRESULT CDECL stream_seek(IStream *stream, LONGLONG ofs, DWORD origin, ULONGLONG
return hr;
}
-void reverse_bgr8(UINT bytesperpixel, LPBYTE bits, UINT width, UINT height, INT stride)
-{
- UINT x, y;
- BYTE *pixel, temp;
-
- for (y=0; y<height; y++)
- {
- pixel = bits + stride * y;
-
- for (x=0; x<width; x++)
- {
- temp = pixel[2];
- pixel[2] = pixel[0];
- pixel[0] = temp;
- pixel += bytesperpixel;
- }
- }
-}
-
HRESULT get_pixelformat_bpp(const GUID *pixelformat, UINT *bpp)
{
HRESULT hr;
diff --git a/dlls/windowscodecs/tiffformat.c b/dlls/windowscodecs/tiffformat.c
index 19cb0cf9286..b2478380334 100644
--- a/dlls/windowscodecs/tiffformat.c
+++ b/dlls/windowscodecs/tiffformat.c
@@ -221,1414 +221,6 @@ static TIFF* tiff_open_stream(IStream *stream, const char *mode)
(void *)tiff_stream_size, (void *)tiff_stream_map, (void *)tiff_stream_unmap);
}
-typedef struct {
- IWICBitmapDecoder IWICBitmapDecoder_iface;
- LONG ref;
- IStream *stream;
- CRITICAL_SECTION lock; /* Must be held when tiff is used or initialized is set */
- TIFF *tiff;
- BOOL initialized;
-} TiffDecoder;
-
-typedef struct {
- const WICPixelFormatGUID *format;
- int bps;
- int samples;
- int bpp, source_bpp;
- int planar;
- int indexed;
- int reverse_bgr;
- int invert_grayscale;
- UINT width, height;
- UINT tile_width, tile_height;
- UINT tile_stride;
- UINT tile_size;
- int tiled;
- UINT tiles_across;
- UINT resolution_unit;
- float xres, yres;
-} tiff_decode_info;
-
-typedef struct {
- IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
- IWICMetadataBlockReader IWICMetadataBlockReader_iface;
- LONG ref;
- TiffDecoder *parent;
- UINT index;
- tiff_decode_info decode_info;
- INT cached_tile_x, cached_tile_y;
- BYTE *cached_tile;
-} TiffFrameDecode;
-
-static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl;
-static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl;
-
-static inline TiffDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
-{
- return CONTAINING_RECORD(iface, TiffDecoder, IWICBitmapDecoder_iface);
-}
-
-static inline TiffFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
-{
- return CONTAINING_RECORD(iface, TiffFrameDecode, IWICBitmapFrameDecode_iface);
-}
-
-static inline TiffFrameDecode *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
-{
- return CONTAINING_RECORD(iface, TiffFrameDecode, IWICMetadataBlockReader_iface);
-}
-
-static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info)
-{
- uint16 photometric, bps, samples, planar;
- uint16 extra_sample_count, extra_sample, *extra_samples;
- int ret;
-
- decode_info->indexed = 0;
- decode_info->reverse_bgr = 0;
- decode_info->invert_grayscale = 0;
- decode_info->tiled = 0;
- decode_info->source_bpp = 0;
-
- ret = pTIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric);
- if (!ret)
- {
- WARN("missing PhotometricInterpretation tag\n");
- return E_FAIL;
- }
-
- ret = pTIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bps);
- if (!ret) bps = 1;
- decode_info->bps = bps;
-
- ret = pTIFFGetField(tiff, TIFFTAG_SAMPLESPERPIXEL, &samples);
- if (!ret) samples = 1;
- decode_info->samples = samples;
-
- if (samples == 1)
- planar = 1;
- else
- {
- ret = pTIFFGetField(tiff, TIFFTAG_PLANARCONFIG, &planar);
- if (!ret) planar = 1;
- if (planar != 1)
- {
- FIXME("unhandled planar configuration %u\n", planar);
- return E_FAIL;
- }
- }
- decode_info->planar = planar;
-
- TRACE("planar %u, photometric %u, samples %u, bps %u\n", planar, photometric, samples, bps);
-
- switch(photometric)
- {
- case 0: /* WhiteIsZero */
- decode_info->invert_grayscale = 1;
- /* fall through */
- case 1: /* BlackIsZero */
- if (samples == 2)
- {
- ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
- if (!ret)
- {
- extra_sample_count = 1;
- extra_sample = 0;
- extra_samples = &extra_sample;
- }
- }
- else if (samples != 1)
- {
- FIXME("unhandled %dbpp sample count %u\n", bps, samples);
- return E_FAIL;
- }
-
- decode_info->bpp = bps * samples;
- decode_info->source_bpp = decode_info->bpp;
- switch (bps)
- {
- case 1:
- if (samples != 1)
- {
- FIXME("unhandled 1bpp sample count %u\n", samples);
- return E_FAIL;
- }
- decode_info->format = &GUID_WICPixelFormatBlackWhite;
- break;
- case 4:
- if (samples != 1)
- {
- FIXME("unhandled 4bpp grayscale sample count %u\n", samples);
- return E_FAIL;
- }
- decode_info->format = &GUID_WICPixelFormat4bppGray;
- break;
- case 8:
- if (samples == 1)
- decode_info->format = &GUID_WICPixelFormat8bppGray;
- else
- {
- decode_info->bpp = 32;
-
- switch(extra_samples[0])
- {
- case 1: /* Associated (pre-multiplied) alpha data */
- decode_info->format = &GUID_WICPixelFormat32bppPBGRA;
- break;
- case 0: /* Unspecified data */
- case 2: /* Unassociated alpha data */
- decode_info->format = &GUID_WICPixelFormat32bppBGRA;
- break;
- default:
- FIXME("unhandled extra sample type %u\n", extra_samples[0]);
- return E_FAIL;
- }
- }
- break;
- case 16:
- if (samples != 1)
- {
- FIXME("unhandled 16bpp grayscale sample count %u\n", samples);
- return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
- }
- decode_info->format = &GUID_WICPixelFormat16bppGray;
- break;
- case 32:
- if (samples != 1)
- {
- FIXME("unhandled 32bpp grayscale sample count %u\n", samples);
- return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
- }
- decode_info->format = &GUID_WICPixelFormat32bppGrayFloat;
- break;
- default:
- WARN("unhandled greyscale bit count %u\n", bps);
- return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
- }
- break;
- case 2: /* RGB */
- if (samples == 4)
- {
- ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples);
- if (!ret)
- {
- extra_sample_count = 1;
- extra_sample = 0;
- extra_samples = &extra_sample;
- }
- }
- else if (samples != 3)
- {
- FIXME("unhandled RGB sample count %u\n", samples);
- return E_FAIL;
- }
-
- decode_info->bpp = max(bps, 8) * samples;
- decode_info->source_bpp = bps * samples;
- switch(bps)
- {
- case 1:
- case 4:
- case 8:
- decode_info->reverse_bgr = 1;
- if (samples == 3)
- decode_info->format = &GUID_WICPixelFormat24bppBGR;
- else
- switch(extra_samples[0])
- {
- case 1: /* Associated (pre-multiplied) alpha data */
- decode_info->format = &GUID_WICPixelFormat32bppPBGRA;
- break;
- case 0: /* Unspecified data */
- case 2: /* Unassociated alpha data */
- decode_info->format = &GUID_WICPixelFormat32bppBGRA;
- break;
- default:
- FIXME("unhandled extra sample type %i\n", extra_samples[0]);
- return E_FAIL;
- }
- break;
- case 16:
- if (samples == 3)
- decode_info->format = &GUID_WICPixelFormat48bppRGB;
- else
- switch(extra_samples[0])
- {
- case 1: /* Associated (pre-multiplied) alpha data */
- decode_info->format = &GUID_WICPixelFormat64bppPRGBA;
- break;
- case 0: /* Unspecified data */
- case 2: /* Unassociated alpha data */
- decode_info->format = &GUID_WICPixelFormat64bppRGBA;
- break;
- default:
- FIXME("unhandled extra sample type %i\n", extra_samples[0]);
- return E_FAIL;
- }
- break;
- case 32:
- if (samples == 3)
- decode_info->format = &GUID_WICPixelFormat96bppRGBFloat;
- else
- switch(extra_samples[0])
- {
- case 1: /* Associated (pre-multiplied) alpha data */
- decode_info->format = &GUID_WICPixelFormat128bppPRGBAFloat;
- break;
- case 0: /* Unspecified data */
- case 2: /* Unassociated alpha data */
- decode_info->format = &GUID_WICPixelFormat128bppRGBAFloat;
- break;
- default:
- FIXME("unhandled extra sample type %i\n", extra_samples[0]);
- return E_FAIL;
- }
- break;
- default:
- WARN("unhandled RGB bit count %u\n", bps);
- return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
- }
- break;
- case 3: /* RGB Palette */
- if (samples != 1)
- {
- FIXME("unhandled indexed sample count %u\n", samples);
- return E_FAIL;
- }
-
- decode_info->indexed = 1;
- decode_info->bpp = bps;
- switch (bps)
- {
- case 1:
- decode_info->format = &GUID_WICPixelFormat1bppIndexed;
- break;
- case 2:
- decode_info->format = &GUID_WICPixelFormat2bppIndexed;
- break;
- case 4:
- decode_info->format = &GUID_WICPixelFormat4bppIndexed;
- break;
- case 8:
- decode_info->format = &GUID_WICPixelFormat8bppIndexed;
- break;
- default:
- FIXME("unhandled indexed bit count %u\n", bps);
- return E_NOTIMPL;
- }
- break;
-
- case 5: /* Separated */
- if (samples != 4)
- {
- FIXME("unhandled Separated sample count %u\n", samples);
- return E_FAIL;
- }
-
- decode_info->bpp = bps * samples;
- switch(bps)
- {
- case 8:
- decode_info->format = &GUID_WICPixelFormat32bppCMYK;
- break;
- case 16:
- decode_info->format = &GUID_WICPixelFormat64bppCMYK;
- break;
-
- default:
- WARN("unhandled Separated bit count %u\n", bps);
- return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
- }
- break;
-
- case 4: /* Transparency mask */
- case 6: /* YCbCr */
- case 8: /* CIELab */
- default:
- FIXME("unhandled PhotometricInterpretation %u\n", photometric);
- return E_FAIL;
- }
-
- ret = pTIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &decode_info->width);
- if (!ret)
- {
- WARN("missing image width\n");
- return E_FAIL;
- }
-
- ret = pTIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &decode_info->height);
- if (!ret)
- {
- WARN("missing image length\n");
- return E_FAIL;
- }
-
- if ((ret = pTIFFGetField(tiff, TIFFTAG_TILEWIDTH, &decode_info->tile_width)))
- {
- decode_info->tiled = 1;
-
- ret = pTIFFGetField(tiff, TIFFTAG_TILELENGTH, &decode_info->tile_height);
- if (!ret)
- {
- WARN("missing tile height\n");
- return E_FAIL;
- }
-
- decode_info->tile_stride = ((decode_info->bpp * decode_info->tile_width + 7)/8);
- decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
- decode_info->tiles_across = (decode_info->width + decode_info->tile_width - 1) / decode_info->tile_width;
- }
- else if ((ret = pTIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &decode_info->tile_height)))
- {
- if (decode_info->tile_height > decode_info->height)
- decode_info->tile_height = decode_info->height;
- decode_info->tile_width = decode_info->width;
- decode_info->tile_stride = ((decode_info->bpp * decode_info->tile_width + 7)/8);
- decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
- }
- else
- {
- /* Some broken TIFF files have a single strip and lack the RowsPerStrip tag */
- decode_info->tile_height = decode_info->height;
- decode_info->tile_width = decode_info->width;
- decode_info->tile_stride = ((decode_info->bpp * decode_info->tile_width + 7)/8);
- decode_info->tile_size = decode_info->tile_height * decode_info->tile_stride;
- }
-
- decode_info->resolution_unit = 0;
- pTIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &decode_info->resolution_unit);
-
- ret = pTIFFGetField(tiff, TIFFTAG_XRESOLUTION, &decode_info->xres);
- if (!ret)
- {
- WARN("missing X resolution\n");
- }
- /* Emulate the behavior of current libtiff versions (libtiff commit a39f6131)
- * yielding 0 instead of INFINITY for IFD_RATIONAL fields with denominator 0. */
- if (!isfinite(decode_info->xres))
- {
- decode_info->xres = 0.0;
- }
-
- ret = pTIFFGetField(tiff, TIFFTAG_YRESOLUTION, &decode_info->yres);
- if (!ret)
- {
- WARN("missing Y resolution\n");
- }
- if (!isfinite(decode_info->yres))
- {
- decode_info->yres = 0.0;
- }
-
- return S_OK;
-}
-
-static HRESULT WINAPI TiffDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
- void **ppv)
-{
- TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
- TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
-
- if (!ppv) return E_INVALIDARG;
-
- if (IsEqualIID(&IID_IUnknown, iid) ||
- IsEqualIID(&IID_IWICBitmapDecoder, iid))
- {
- *ppv = &This->IWICBitmapDecoder_iface;
- }
- else
- {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
- IUnknown_AddRef((IUnknown*)*ppv);
- return S_OK;
-}
-
-static ULONG WINAPI TiffDecoder_AddRef(IWICBitmapDecoder *iface)
-{
- TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
- ULONG ref = InterlockedIncrement(&This->ref);
-
- TRACE("(%p) refcount=%u\n", iface, ref);
-
- return ref;
-}
-
-static ULONG WINAPI TiffDecoder_Release(IWICBitmapDecoder *iface)
-{
- TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
- ULONG ref = InterlockedDecrement(&This->ref);
-
- TRACE("(%p) refcount=%u\n", iface, ref);
-
- if (ref == 0)
- {
- if (This->tiff) pTIFFClose(This->tiff);
- if (This->stream) IStream_Release(This->stream);
- This->lock.DebugInfo->Spare[0] = 0;
- DeleteCriticalSection(&This->lock);
- HeapFree(GetProcessHeap(), 0, This);
- }
-
- return ref;
-}
-
-static HRESULT WINAPI TiffDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
- DWORD *capability)
-{
- HRESULT hr;
-
- TRACE("(%p,%p,%p)\n", iface, stream, capability);
-
- if (!stream || !capability) return E_INVALIDARG;
-
- hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
- if (hr != S_OK) return hr;
-
- *capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
- WICBitmapDecoderCapabilityCanDecodeSomeImages |
- WICBitmapDecoderCapabilityCanEnumerateMetadata;
- return S_OK;
-}
-
-static HRESULT WINAPI TiffDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
- WICDecodeOptions cacheOptions)
-{
- TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
- TIFF *tiff;
- tiff_decode_info decode_info;
- HRESULT hr=S_OK;
-
- TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
-
- EnterCriticalSection(&This->lock);
-
- if (This->initialized)
- {
- hr = WINCODEC_ERR_WRONGSTATE;
- goto exit;
- }
-
- tiff = tiff_open_stream(pIStream, "r");
- if (!tiff)
- {
- hr = E_FAIL;
- goto exit;
- }
-
- /* make sure that TIFF format is supported */
- hr = tiff_get_decode_info(tiff, &decode_info);
- if (hr != S_OK)
- {
- pTIFFClose(tiff);
- goto exit;
- }
-
- This->tiff = tiff;
- This->stream = pIStream;
- IStream_AddRef(pIStream);
- This->initialized = TRUE;
-
-exit:
- LeaveCriticalSection(&This->lock);
- return hr;
-}
-
-static HRESULT WINAPI TiffDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
- GUID *pguidContainerFormat)
-{
- if (!pguidContainerFormat) return E_INVALIDARG;
-
- memcpy(pguidContainerFormat, &GUID_ContainerFormatTiff, sizeof(GUID));
- return S_OK;
-}
-
-static HRESULT WINAPI TiffDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
- IWICBitmapDecoderInfo **ppIDecoderInfo)
-{
- TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
-
- return get_decoder_info(&CLSID_WICTiffDecoder, ppIDecoderInfo);
-}
-
-static HRESULT WINAPI TiffDecoder_CopyPalette(IWICBitmapDecoder *iface,
- IWICPalette *palette)
-{
- TRACE("(%p,%p)\n", iface, palette);
- return WINCODEC_ERR_PALETTEUNAVAILABLE;
-}
-
-static HRESULT WINAPI TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
- IWICMetadataQueryReader **ppIMetadataQueryReader)
-{
- TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
-
- if (!ppIMetadataQueryReader) return E_INVALIDARG;
-
- *ppIMetadataQueryReader = NULL;
- return WINCODEC_ERR_UNSUPPORTEDOPERATION;
-}
-
-static HRESULT WINAPI TiffDecoder_GetPreview(IWICBitmapDecoder *iface,
- IWICBitmapSource **ppIBitmapSource)
-{
- TRACE("(%p,%p)\n", iface, ppIBitmapSource);
-
- if (!ppIBitmapSource) return E_INVALIDARG;
-
- *ppIBitmapSource = NULL;
- return WINCODEC_ERR_UNSUPPORTEDOPERATION;
-}
-
-static HRESULT WINAPI TiffDecoder_GetColorContexts(IWICBitmapDecoder *iface,
- UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
-{
- FIXME("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
- return WINCODEC_ERR_UNSUPPORTEDOPERATION;
-}
-
-static HRESULT WINAPI TiffDecoder_GetThumbnail(IWICBitmapDecoder *iface,
- IWICBitmapSource **ppIThumbnail)
-{
- TRACE("(%p,%p)\n", iface, ppIThumbnail);
-
- if (!ppIThumbnail) return E_INVALIDARG;
-
- *ppIThumbnail = NULL;
- return WINCODEC_ERR_CODECNOTHUMBNAIL;
-}
-
-static HRESULT WINAPI TiffDecoder_GetFrameCount(IWICBitmapDecoder *iface,
- UINT *pCount)
-{
- TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
-
- if (!pCount) return E_INVALIDARG;
-
- EnterCriticalSection(&This->lock);
- *pCount = This->tiff ? pTIFFNumberOfDirectories(This->tiff) : 0;
- LeaveCriticalSection(&This->lock);
-
- TRACE("(%p) <-- %i\n", iface, *pCount);
-
- return S_OK;
-}
-
-static HRESULT WINAPI TiffDecoder_GetFrame(IWICBitmapDecoder *iface,
- UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
-{
- TiffDecoder *This = impl_from_IWICBitmapDecoder(iface);
- TiffFrameDecode *result;
- int res;
- tiff_decode_info decode_info;
- HRESULT hr;
-
- TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
-
- if (!This->tiff)
- return WINCODEC_ERR_FRAMEMISSING;
-
- EnterCriticalSection(&This->lock);
- res = pTIFFSetDirectory(This->tiff, index);
- if (!res) hr = E_INVALIDARG;
- else hr = tiff_get_decode_info(This->tiff, &decode_info);
- LeaveCriticalSection(&This->lock);
-
- if (SUCCEEDED(hr))
- {
- result = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffFrameDecode));
-
- if (result)
- {
- result->IWICBitmapFrameDecode_iface.lpVtbl = &TiffFrameDecode_Vtbl;
- result->IWICMetadataBlockReader_iface.lpVtbl = &TiffFrameDecode_BlockVtbl;
- result->ref = 1;
- result->parent = This;
- IWICBitmapDecoder_AddRef(iface);
- result->index = index;
- result->decode_info = decode_info;
- result->cached_tile_x = -1;
- result->cached_tile = HeapAlloc(GetProcessHeap(), 0, decode_info.tile_size);
-
- if (result->cached_tile)
- *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
- else
- {
- hr = E_OUTOFMEMORY;
- IWICBitmapFrameDecode_Release(&result->IWICBitmapFrameDecode_iface);
- }
- }
- else hr = E_OUTOFMEMORY;
- }
-
- if (FAILED(hr)) *ppIBitmapFrame = NULL;
-
- return hr;
-}
-
-static const IWICBitmapDecoderVtbl TiffDecoder_Vtbl = {
- TiffDecoder_QueryInterface,
- TiffDecoder_AddRef,
- TiffDecoder_Release,
- TiffDecoder_QueryCapability,
- TiffDecoder_Initialize,
- TiffDecoder_GetContainerFormat,
- TiffDecoder_GetDecoderInfo,
- TiffDecoder_CopyPalette,
- TiffDecoder_GetMetadataQueryReader,
- TiffDecoder_GetPreview,
- TiffDecoder_GetColorContexts,
- TiffDecoder_GetThumbnail,
- TiffDecoder_GetFrameCount,
- TiffDecoder_GetFrame
-};
-
-static HRESULT WINAPI TiffFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
- void **ppv)
-{
- TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
- TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
-
- if (!ppv) return E_INVALIDARG;
-
- if (IsEqualIID(&IID_IUnknown, iid) ||
- IsEqualIID(&IID_IWICBitmapSource, iid) ||
- IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
- {
- *ppv = &This->IWICBitmapFrameDecode_iface;
- }
- else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
- {
- *ppv = &This->IWICMetadataBlockReader_iface;
- }
- else
- {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
- IUnknown_AddRef((IUnknown*)*ppv);
- return S_OK;
-}
-
-static ULONG WINAPI TiffFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
-{
- TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
- ULONG ref = InterlockedIncrement(&This->ref);
-
- TRACE("(%p) refcount=%u\n", iface, ref);
-
- return ref;
-}
-
-static ULONG WINAPI TiffFrameDecode_Release(IWICBitmapFrameDecode *iface)
-{
- TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
- ULONG ref = InterlockedDecrement(&This->ref);
-
- TRACE("(%p) refcount=%u\n", iface, ref);
-
- if (ref == 0)
- {
- IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface);
- HeapFree(GetProcessHeap(), 0, This->cached_tile);
- HeapFree(GetProcessHeap(), 0, This);
- }
-
- return ref;
-}
-
-static HRESULT WINAPI TiffFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
- UINT *puiWidth, UINT *puiHeight)
-{
- TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
-
- *puiWidth = This->decode_info.width;
- *puiHeight = This->decode_info.height;
-
- TRACE("(%p) <-- %ux%u\n", iface, *puiWidth, *puiHeight);
-
- return S_OK;
-}
-
-static HRESULT WINAPI TiffFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
- WICPixelFormatGUID *pPixelFormat)
-{
- TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
-
- memcpy(pPixelFormat, This->decode_info.format, sizeof(GUID));
-
- TRACE("(%p) <-- %s\n", This, debugstr_guid(This->decode_info.format));
-
- return S_OK;
-}
-
-static HRESULT WINAPI TiffFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
- double *pDpiX, double *pDpiY)
-{
- TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
-
- if (This->decode_info.xres == 0 || This->decode_info.yres == 0)
- {
- *pDpiX = *pDpiY = 96.0;
- }
- else
- {
- switch (This->decode_info.resolution_unit)
- {
- default:
- FIXME("unknown resolution unit %i\n", This->decode_info.resolution_unit);
- /* fall through */
- case 0: /* Not set */
- case 1: /* Relative measurements */
- case 2: /* Inch */
- *pDpiX = This->decode_info.xres;
- *pDpiY = This->decode_info.yres;
- break;
- case 3: /* Centimeter */
- *pDpiX = This->decode_info.xres * 2.54;
- *pDpiY = This->decode_info.yres * 2.54;
- break;
- }
- }
-
- TRACE("(%p) <-- %f,%f unit=%i\n", iface, *pDpiX, *pDpiY, This->decode_info.resolution_unit);
-
- return S_OK;
-}
-
-static HRESULT WINAPI TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
- IWICPalette *pIPalette)
-{
- TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
- uint16 *red, *green, *blue;
- WICColor colors[256];
- int color_count, ret, i;
-
- TRACE("(%p,%p)\n", iface, pIPalette);
-
- color_count = 1<<This->decode_info.bps;
-
- EnterCriticalSection(&This->parent->lock);
- ret = pTIFFGetField(This->parent->tiff, TIFFTAG_COLORMAP, &red, &green, &blue);
- LeaveCriticalSection(&This->parent->lock);
-
- if (!ret)
- {
- WARN("Couldn't read color map\n");
- return WINCODEC_ERR_PALETTEUNAVAILABLE;
- }
-
- for (i=0; i<color_count; i++)
- {
- colors[i] = 0xff000000 |
- ((red[i]<<8) & 0xff0000) |
- (green[i] & 0xff00) |
- ((blue[i]>>8) & 0xff);
- }
-
- return IWICPalette_InitializeCustom(pIPalette, colors, color_count);
-}
-
-static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT tile_y)
-{
- tsize_t ret;
- int swap_bytes;
-
- swap_bytes = pTIFFIsByteSwapped(This->parent->tiff);
-
- ret = pTIFFSetDirectory(This->parent->tiff, This->index);
- if (ret == -1)
- return E_FAIL;
-
- if (This->decode_info.tiled)
- ret = pTIFFReadEncodedTile(This->parent->tiff, tile_x + tile_y * This->decode_info.tiles_across, This->cached_tile, This->decode_info.tile_size);
- else
- ret = pTIFFReadEncodedStrip(This->parent->tiff, tile_y, This->cached_tile, This->decode_info.tile_size);
-
- if (ret == -1)
- return E_FAIL;
-
- /* 3bps RGB */
- if (This->decode_info.source_bpp == 3 && This->decode_info.samples == 3 && This->decode_info.bpp == 24)
- {
- BYTE *srcdata, *src, *dst;
- DWORD x, y, count, width_bytes = (This->decode_info.tile_width * 3 + 7) / 8;
-
- count = width_bytes * This->decode_info.tile_height;
-
- srcdata = HeapAlloc(GetProcessHeap(), 0, count);
- if (!srcdata) return E_OUTOFMEMORY;
- memcpy(srcdata, This->cached_tile, count);
-
- for (y = 0; y < This->decode_info.tile_height; y++)
- {
- src = srcdata + y * width_bytes;
- dst = This->cached_tile + y * This->decode_info.tile_width * 3;
-
- for (x = 0; x < This->decode_info.tile_width; x += 8)
- {
- dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */
- dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */
- dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */
- if (x + 1 < This->decode_info.tile_width)
- {
- dst[5] = (src[0] & 0x10) ? 0xff : 0; /* R */
- dst[4] = (src[0] & 0x08) ? 0xff : 0; /* G */
- dst[3] = (src[0] & 0x04) ? 0xff : 0; /* B */
- }
- if (x + 2 < This->decode_info.tile_width)
- {
- dst[8] = (src[0] & 0x02) ? 0xff : 0; /* R */
- dst[7] = (src[0] & 0x01) ? 0xff : 0; /* G */
- dst[6] = (src[1] & 0x80) ? 0xff : 0; /* B */
- }
- if (x + 3 < This->decode_info.tile_width)
- {
- dst[11] = (src[1] & 0x40) ? 0xff : 0; /* R */
- dst[10] = (src[1] & 0x20) ? 0xff : 0; /* G */
- dst[9] = (src[1] & 0x10) ? 0xff : 0; /* B */
- }
- if (x + 4 < This->decode_info.tile_width)
- {
- dst[14] = (src[1] & 0x08) ? 0xff : 0; /* R */
- dst[13] = (src[1] & 0x04) ? 0xff : 0; /* G */
- dst[12] = (src[1] & 0x02) ? 0xff : 0; /* B */
- }
- if (x + 5 < This->decode_info.tile_width)
- {
- dst[17] = (src[1] & 0x01) ? 0xff : 0; /* R */
- dst[16] = (src[2] & 0x80) ? 0xff : 0; /* G */
- dst[15] = (src[2] & 0x40) ? 0xff : 0; /* B */
- }
- if (x + 6 < This->decode_info.tile_width)
- {
- dst[20] = (src[2] & 0x20) ? 0xff : 0; /* R */
- dst[19] = (src[2] & 0x10) ? 0xff : 0; /* G */
- dst[18] = (src[2] & 0x08) ? 0xff : 0; /* B */
- }
- if (x + 7 < This->decode_info.tile_width)
- {
- dst[23] = (src[2] & 0x04) ? 0xff : 0; /* R */
- dst[22] = (src[2] & 0x02) ? 0xff : 0; /* G */
- dst[21] = (src[2] & 0x01) ? 0xff : 0; /* B */
- }
- src += 3;
- dst += 24;
- }
- }
-
- HeapFree(GetProcessHeap(), 0, srcdata);
- }
- /* 12bps RGB */
- else if (This->decode_info.source_bpp == 12 && This->decode_info.samples == 3 && This->decode_info.bpp == 24)
- {
- BYTE *srcdata, *src, *dst;
- DWORD x, y, count, width_bytes = (This->decode_info.tile_width * 12 + 7) / 8;
-
- count = width_bytes * This->decode_info.tile_height;
-
- srcdata = HeapAlloc(GetProcessHeap(), 0, count);
- if (!srcdata) return E_OUTOFMEMORY;
- memcpy(srcdata, This->cached_tile, count);
-
- for (y = 0; y < This->decode_info.tile_height; y++)
- {
- src = srcdata + y * width_bytes;
- dst = This->cached_tile + y * This->decode_info.tile_width * 3;
-
- for (x = 0; x < This->decode_info.tile_width; x += 2)
- {
- dst[0] = ((src[1] & 0xf0) >> 4) * 17; /* B */
- dst[1] = (src[0] & 0x0f) * 17; /* G */
- dst[2] = ((src[0] & 0xf0) >> 4) * 17; /* R */
- if (x + 1 < This->decode_info.tile_width)
- {
- dst[5] = (src[1] & 0x0f) * 17; /* B */
- dst[4] = ((src[2] & 0xf0) >> 4) * 17; /* G */
- dst[3] = (src[2] & 0x0f) * 17; /* R */
- }
- src += 3;
- dst += 6;
- }
- }
-
- HeapFree(GetProcessHeap(), 0, srcdata);
- }
- /* 4bps RGBA */
- else if (This->decode_info.source_bpp == 4 && This->decode_info.samples == 4 && This->decode_info.bpp == 32)
- {
- BYTE *srcdata, *src, *dst;
- DWORD x, y, count, width_bytes = (This->decode_info.tile_width * 3 + 7) / 8;
-
- count = width_bytes * This->decode_info.tile_height;
-
- srcdata = HeapAlloc(GetProcessHeap(), 0, count);
- if (!srcdata) return E_OUTOFMEMORY;
- memcpy(srcdata, This->cached_tile, count);
-
- for (y = 0; y < This->decode_info.tile_height; y++)
- {
- src = srcdata + y * width_bytes;
- dst = This->cached_tile + y * This->decode_info.tile_width * 4;
-
- /* 1 source byte expands to 2 BGRA samples */
-
- for (x = 0; x < This->decode_info.tile_width; x += 2)
- {
- dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */
- dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */
- dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */
- dst[3] = (src[0] & 0x10) ? 0xff : 0; /* A */
- if (x + 1 < This->decode_info.tile_width)
- {
- dst[4] = (src[0] & 0x02) ? 0xff : 0; /* B */
- dst[5] = (src[0] & 0x04) ? 0xff : 0; /* G */
- dst[6] = (src[0] & 0x08) ? 0xff : 0; /* R */
- dst[7] = (src[0] & 0x01) ? 0xff : 0; /* A */
- }
- src++;
- dst += 8;
- }
- }
-
- HeapFree(GetProcessHeap(), 0, srcdata);
- }
- /* 16bps RGBA */
- else if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 4 && This->decode_info.bpp == 32)
- {
- BYTE *srcdata, *src, *dst;
- DWORD x, y, count, width_bytes = (This->decode_info.tile_width * 12 + 7) / 8;
-
- count = width_bytes * This->decode_info.tile_height;
-
- srcdata = HeapAlloc(GetProcessHeap(), 0, count);
- if (!srcdata) return E_OUTOFMEMORY;
- memcpy(srcdata, This->cached_tile, count);
-
- for (y = 0; y < This->decode_info.tile_height; y++)
- {
- src = srcdata + y * width_bytes;
- dst = This->cached_tile + y * This->decode_info.tile_width * 4;
-
- for (x = 0; x < This->decode_info.tile_width; x++)
- {
- dst[0] = ((src[1] & 0xf0) >> 4) * 17; /* B */
- dst[1] = (src[0] & 0x0f) * 17; /* G */
- dst[2] = ((src[0] & 0xf0) >> 4) * 17; /* R */
- dst[3] = (src[1] & 0x0f) * 17; /* A */
- src += 2;
- dst += 4;
- }
- }
-
- HeapFree(GetProcessHeap(), 0, srcdata);
- }
- /* 8bpp grayscale with extra alpha */
- else if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 2 && This->decode_info.bpp == 32)
- {
- BYTE *src;
- DWORD *dst, count = This->decode_info.tile_width * This->decode_info.tile_height;
-
- src = This->cached_tile + This->decode_info.tile_width * This->decode_info.tile_height * 2 - 2;
- dst = (DWORD *)(This->cached_tile + This->decode_info.tile_size - 4);
-
- while (count--)
- {
- *dst-- = src[0] | (src[0] << 8) | (src[0] << 16) | (src[1] << 24);
- src -= 2;
- }
- }
-
- if (This->decode_info.reverse_bgr)
- {
- if (This->decode_info.bps == 8)
- {
- UINT sample_count = This->decode_info.samples;
-
- reverse_bgr8(sample_count, This->cached_tile, This->decode_info.tile_width,
- This->decode_info.tile_height, This->decode_info.tile_width * sample_count);
- }
- }
-
- if (swap_bytes && This->decode_info.bps > 8)
- {
- UINT row, i, samples_per_row;
- BYTE *sample, temp;
-
- samples_per_row = This->decode_info.tile_width * This->decode_info.samples;
-
- switch(This->decode_info.bps)
- {
- case 16:
- for (row=0; row<This->decode_info.tile_height; row++)
- {
- sample = This->cached_tile + row * This->decode_info.tile_stride;
- for (i=0; i<samples_per_row; i++)
- {
- temp = sample[1];
- sample[1] = sample[0];
- sample[0] = temp;
- sample += 2;
- }
- }
- break;
- default:
- ERR("unhandled bps for byte swap %u\n", This->decode_info.bps);
- return E_FAIL;
- }
- }
-
- if (This->decode_info.invert_grayscale)
- {
- BYTE *byte, *end;
-
- if (This->decode_info.samples != 1)
- {
- ERR("cannot invert grayscale image with %u samples\n", This->decode_info.samples);
- return E_FAIL;
- }
-
- end = This->cached_tile+This->decode_info.tile_size;
-
- for (byte = This->cached_tile; byte != end; byte++)
- *byte = ~(*byte);
- }
-
- This->cached_tile_x = tile_x;
- This->cached_tile_y = tile_y;
-
- return S_OK;
-}
-
-static HRESULT WINAPI TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
- const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
-{
- TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
- UINT min_tile_x, max_tile_x, min_tile_y, max_tile_y;
- UINT tile_x, tile_y;
- WICRect rc;
- HRESULT hr=S_OK;
- BYTE *dst_tilepos;
- UINT bytesperrow;
- WICRect rect;
-
- TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
-
- if (!prc)
- {
- rect.X = 0;
- rect.Y = 0;
- rect.Width = This->decode_info.width;
- rect.Height = This->decode_info.height;
- prc = ▭
- }
- else
- {
- if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->decode_info.width ||
- prc->Y+prc->Height > This->decode_info.height)
- return E_INVALIDARG;
- }
-
- bytesperrow = ((This->decode_info.bpp * prc->Width)+7)/8;
-
- if (cbStride < bytesperrow)
- return E_INVALIDARG;
-
- if ((cbStride * (prc->Height-1)) + bytesperrow > cbBufferSize)
- return E_INVALIDARG;
-
- min_tile_x = prc->X / This->decode_info.tile_width;
- min_tile_y = prc->Y / This->decode_info.tile_height;
- max_tile_x = (prc->X+prc->Width-1) / This->decode_info.tile_width;
- max_tile_y = (prc->Y+prc->Height-1) / This->decode_info.tile_height;
-
- EnterCriticalSection(&This->parent->lock);
-
- for (tile_x=min_tile_x; tile_x <= max_tile_x; tile_x++)
- {
- for (tile_y=min_tile_y; tile_y <= max_tile_y; tile_y++)
- {
- if (tile_x != This->cached_tile_x || tile_y != This->cached_tile_y)
- {
- hr = TiffFrameDecode_ReadTile(This, tile_x, tile_y);
- }
-
- if (SUCCEEDED(hr))
- {
- if (prc->X < tile_x * This->decode_info.tile_width)
- rc.X = 0;
- else
- rc.X = prc->X - tile_x * This->decode_info.tile_width;
-
- if (prc->Y < tile_y * This->decode_info.tile_height)
- rc.Y = 0;
- else
- rc.Y = prc->Y - tile_y * This->decode_info.tile_height;
-
- if (prc->X+prc->Width > (tile_x+1) * This->decode_info.tile_width)
- rc.Width = This->decode_info.tile_width - rc.X;
- else if (prc->X < tile_x * This->decode_info.tile_width)
- rc.Width = prc->Width + prc->X - tile_x * This->decode_info.tile_width;
- else
- rc.Width = prc->Width;
-
- if (prc->Y+prc->Height > (tile_y+1) * This->decode_info.tile_height)
- rc.Height = This->decode_info.tile_height - rc.Y;
- else if (prc->Y < tile_y * This->decode_info.tile_height)
- rc.Height = prc->Height + prc->Y - tile_y * This->decode_info.tile_height;
- else
- rc.Height = prc->Height;
-
- dst_tilepos = pbBuffer + (cbStride * ((rc.Y + tile_y * This->decode_info.tile_height) - prc->Y)) +
- ((This->decode_info.bpp * ((rc.X + tile_x * This->decode_info.tile_width) - prc->X) + 7) / 8);
-
- hr = copy_pixels(This->decode_info.bpp, This->cached_tile,
- This->decode_info.tile_width, This->decode_info.tile_height, This->decode_info.tile_stride,
- &rc, cbStride, cbBufferSize, dst_tilepos);
- }
-
- if (FAILED(hr))
- {
- LeaveCriticalSection(&This->parent->lock);
- TRACE("<-- 0x%x\n", hr);
- return hr;
- }
- }
- }
-
- LeaveCriticalSection(&This->parent->lock);
-
- return S_OK;
-}
-
-static HRESULT WINAPI TiffFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
- IWICMetadataQueryReader **ppIMetadataQueryReader)
-{
- TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
-
- TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
-
- if (!ppIMetadataQueryReader)
- return E_INVALIDARG;
-
- return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
-}
-
-static HRESULT WINAPI TiffFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
- UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
-{
- TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
- const BYTE *profile;
- UINT len;
- HRESULT hr;
-
- TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
-
- EnterCriticalSection(&This->parent->lock);
-
- if (pTIFFGetField(This->parent->tiff, TIFFTAG_ICCPROFILE, &len, &profile))
- {
- if (cCount && ppIColorContexts)
- {
- hr = IWICColorContext_InitializeFromMemory(*ppIColorContexts, profile, len);
- if (FAILED(hr))
- {
- LeaveCriticalSection(&This->parent->lock);
- return hr;
- }
- }
- *pcActualCount = 1;
- }
- else
- *pcActualCount = 0;
-
- LeaveCriticalSection(&This->parent->lock);
-
- return S_OK;
-}
-
-static HRESULT WINAPI TiffFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
- IWICBitmapSource **ppIThumbnail)
-{
- TRACE("(%p,%p)\n", iface, ppIThumbnail);
-
- if (!ppIThumbnail) return E_INVALIDARG;
-
- *ppIThumbnail = NULL;
- return WINCODEC_ERR_CODECNOTHUMBNAIL;
-}
-
-static const IWICBitmapFrameDecodeVtbl TiffFrameDecode_Vtbl = {
- TiffFrameDecode_QueryInterface,
- TiffFrameDecode_AddRef,
- TiffFrameDecode_Release,
- TiffFrameDecode_GetSize,
- TiffFrameDecode_GetPixelFormat,
- TiffFrameDecode_GetResolution,
- TiffFrameDecode_CopyPalette,
- TiffFrameDecode_CopyPixels,
- TiffFrameDecode_GetMetadataQueryReader,
- TiffFrameDecode_GetColorContexts,
- TiffFrameDecode_GetThumbnail
-};
-
-static HRESULT WINAPI TiffFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface,
- REFIID iid, void **ppv)
-{
- TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface);
- return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
-}
-
-static ULONG WINAPI TiffFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface)
-{
- TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface);
- return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
-}
-
-static ULONG WINAPI TiffFrameDecode_Block_Release(IWICMetadataBlockReader *iface)
-{
- TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface);
- return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
-}
-
-static HRESULT WINAPI TiffFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
- GUID *guid)
-{
- TRACE("(%p,%p)\n", iface, guid);
-
- if (!guid) return E_INVALIDARG;
-
- *guid = GUID_ContainerFormatTiff;
- return S_OK;
-}
-
-static HRESULT WINAPI TiffFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface,
- UINT *count)
-{
- TRACE("%p,%p\n", iface, count);
-
- if (!count) return E_INVALIDARG;
-
- *count = 1;
- return S_OK;
-}
-
-static HRESULT create_metadata_reader(TiffFrameDecode *This, IWICMetadataReader **reader)
-{
- HRESULT hr;
- LARGE_INTEGER dir_offset;
- IWICMetadataReader *metadata_reader;
- IWICPersistStream *persist;
-
- /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
-
- hr = IfdMetadataReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader);
- if (FAILED(hr)) return hr;
-
- hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
- if (FAILED(hr))
- {
- IWICMetadataReader_Release(metadata_reader);
- return hr;
- }
-
- EnterCriticalSection(&This->parent->lock);
-
- dir_offset.QuadPart = pTIFFCurrentDirOffset(This->parent->tiff);
- hr = IStream_Seek(This->parent->stream, dir_offset, STREAM_SEEK_SET, NULL);
- if (SUCCEEDED(hr))
- {
- BOOL byte_swapped = pTIFFIsByteSwapped(This->parent->tiff);
-#ifdef WORDS_BIGENDIAN
- DWORD persist_options = byte_swapped ? WICPersistOptionLittleEndian : WICPersistOptionBigEndian;
-#else
- DWORD persist_options = byte_swapped ? WICPersistOptionBigEndian : WICPersistOptionLittleEndian;
-#endif
- persist_options |= WICPersistOptionNoCacheStream;
- hr = IWICPersistStream_LoadEx(persist, This->parent->stream, NULL, persist_options);
- if (FAILED(hr))
- ERR("IWICPersistStream_LoadEx error %#x\n", hr);
- }
-
- LeaveCriticalSection(&This->parent->lock);
-
- IWICPersistStream_Release(persist);
-
- if (FAILED(hr))
- {
- IWICMetadataReader_Release(metadata_reader);
- return hr;
- }
-
- *reader = metadata_reader;
- return S_OK;
-}
-
-static HRESULT WINAPI TiffFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
- UINT index, IWICMetadataReader **reader)
-{
- TiffFrameDecode *This = impl_from_IWICMetadataBlockReader(iface);
-
- TRACE("(%p,%u,%p)\n", iface, index, reader);
-
- if (!reader || index != 0) return E_INVALIDARG;
-
- return create_metadata_reader(This, reader);
-}
-
-static HRESULT WINAPI TiffFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface,
- IEnumUnknown **enum_metadata)
-{
- FIXME("(%p,%p): stub\n", iface, enum_metadata);
- return E_NOTIMPL;
-}
-
-static const IWICMetadataBlockReaderVtbl TiffFrameDecode_BlockVtbl =
-{
- TiffFrameDecode_Block_QueryInterface,
- TiffFrameDecode_Block_AddRef,
- TiffFrameDecode_Block_Release,
- TiffFrameDecode_Block_GetContainerFormat,
- TiffFrameDecode_Block_GetCount,
- TiffFrameDecode_Block_GetReaderByIndex,
- TiffFrameDecode_Block_GetEnumerator
-};
-
-HRESULT TiffDecoder_CreateInstance(REFIID iid, void** ppv)
-{
- HRESULT ret;
- TiffDecoder *This;
-
- TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
-
- *ppv = NULL;
-
- if (!load_libtiff())
- {
- ERR("Failed reading TIFF because unable to load %s\n",SONAME_LIBTIFF);
- return E_FAIL;
- }
-
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(TiffDecoder));
- if (!This) return E_OUTOFMEMORY;
-
- This->IWICBitmapDecoder_iface.lpVtbl = &TiffDecoder_Vtbl;
- This->ref = 1;
- This->stream = NULL;
- InitializeCriticalSection(&This->lock);
- This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TiffDecoder.lock");
- This->tiff = NULL;
- This->initialized = FALSE;
-
- ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
- IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
-
- return ret;
-}
-
struct tiff_encode_format {
const WICPixelFormatGUID *guid;
int photometric;
@@ -2386,12 +978,6 @@ HRESULT TiffEncoder_CreateInstance(REFIID iid, void** ppv)
#else /* !SONAME_LIBTIFF */
-HRESULT TiffDecoder_CreateInstance(REFIID iid, void** ppv)
-{
- ERR("Trying to load TIFF picture, but Wine was compiled without TIFF support.\n");
- return E_FAIL;
-}
-
HRESULT TiffEncoder_CreateInstance(REFIID iid, void** ppv)
{
ERR("Trying to save TIFF picture, but Wine was compiled without TIFF support.\n");
@@ -2399,3 +985,17 @@ HRESULT TiffEncoder_CreateInstance(REFIID iid, void** ppv)
}
#endif
+
+HRESULT TiffDecoder_CreateInstance(REFIID iid, void** ppv)
+{
+ HRESULT hr;
+ struct decoder *decoder;
+ struct decoder_info decoder_info;
+
+ hr = get_unix_decoder(&CLSID_WICTiffDecoder, &decoder_info, &decoder);
+
+ if (SUCCEEDED(hr))
+ hr = CommonDecoder_CreateInstance(decoder, &decoder_info, iid, ppv);
+
+ return hr;
+}
diff --git a/dlls/windowscodecs/unix_iface.c b/dlls/windowscodecs/unix_iface.c
index e376ea45841..5ed995e7642 100644
--- a/dlls/windowscodecs/unix_iface.c
+++ b/dlls/windowscodecs/unix_iface.c
@@ -40,6 +40,7 @@ static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
static const struct unix_funcs *unix_funcs;
static const struct win32_funcs win32_funcs = {
+ stream_getsize,
stream_read,
stream_seek
};
diff --git a/dlls/windowscodecs/unix_lib.c b/dlls/windowscodecs/unix_lib.c
index 04cbe053a0e..ca2b38ef990 100644
--- a/dlls/windowscodecs/unix_lib.c
+++ b/dlls/windowscodecs/unix_lib.c
@@ -47,6 +47,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
static const struct win32_funcs *win32_funcs;
+HRESULT CDECL stream_getsize(IStream *stream, ULONGLONG *size)
+{
+ return win32_funcs->stream_getsize(stream, size);
+}
+
HRESULT CDECL stream_read(IStream *stream, void *buffer, ULONG read, ULONG *bytes_read)
{
return win32_funcs->stream_read(stream, buffer, read, bytes_read);
@@ -62,6 +67,9 @@ HRESULT CDECL decoder_create(const CLSID *decoder_clsid, struct decoder_info *in
if (IsEqualGUID(decoder_clsid, &CLSID_WICPngDecoder))
return png_decoder_create(info, result);
+ if (IsEqualGUID(decoder_clsid, &CLSID_WICTiffDecoder))
+ return tiff_decoder_create(info, result);
+
return E_NOTIMPL;
}
diff --git a/dlls/windowscodecs/wincodecs_common.h b/dlls/windowscodecs/wincodecs_common.h
index 07e6dcaf44a..b7572d69df4 100644
--- a/dlls/windowscodecs/wincodecs_common.h
+++ b/dlls/windowscodecs/wincodecs_common.h
@@ -158,3 +158,22 @@ HRESULT read_png_chunk(IStream *stream, BYTE *type, BYTE **data, ULONG *data_siz
return S_OK;
}
+
+void reverse_bgr8(UINT bytesperpixel, LPBYTE bits, UINT width, UINT height, INT stride)
+{
+ UINT x, y;
+ BYTE *pixel, temp;
+
+ for (y=0; y<height; y++)
+ {
+ pixel = bits + stride * y;
+
+ for (x=0; x<width; x++)
+ {
+ temp = pixel[2];
+ pixel[2] = pixel[0];
+ pixel[0] = temp;
+ pixel += bytesperpixel;
+ }
+ }
+}
diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h
index 64c813329cf..3d7a46f0f59 100644
--- a/dlls/windowscodecs/wincodecs_private.h
+++ b/dlls/windowscodecs/wincodecs_private.h
@@ -280,11 +280,15 @@ struct decoder_frame
WICColor palette[256];
};
+#define DECODER_BLOCK_OPTION_MASK 0x0001000F
+#define DECODER_BLOCK_FULL_STREAM 0x80000000
+#define DECODER_BLOCK_READER_CLSID 0x40000000
struct decoder_block
{
ULONGLONG offset;
ULONGLONG length;
DWORD options;
+ GUID reader_clsid;
};
struct decoder
@@ -305,11 +309,13 @@ struct decoder_funcs
void (CDECL *destroy)(struct decoder* This);
};
+HRESULT CDECL stream_getsize(IStream *stream, ULONGLONG *size);
HRESULT CDECL stream_read(IStream *stream, void *buffer, ULONG read, ULONG *bytes_read);
HRESULT CDECL stream_seek(IStream *stream, LONGLONG ofs, DWORD origin, ULONGLONG *new_position);
struct win32_funcs
{
+ HRESULT (CDECL *stream_getsize)(IStream *stream, ULONGLONG *size);
HRESULT (CDECL *stream_read)(IStream *stream, void *buffer, ULONG read, ULONG *bytes_read);
HRESULT (CDECL *stream_seek)(IStream *stream, LONGLONG ofs, DWORD origin, ULONGLONG *new_position);
};
@@ -326,6 +332,7 @@ HRESULT CDECL decoder_get_color_context(struct decoder* This, UINT frame, UINT n
void CDECL decoder_destroy(struct decoder *This);
HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **result);
+HRESULT CDECL tiff_decoder_create(struct decoder_info *info, struct decoder **result);
struct unix_funcs
{
--
2.17.1
1
0
[PATCH 1/7] qedit/tests: Add initial tests for bitmap grab mode with a custom filter.
by Gabriel Ivăncescu Oct. 27, 2020
by Gabriel Ivăncescu Oct. 27, 2020
Oct. 27, 2020
We fill the video pattern with something that varies between lines and
columns, to test it properly later (including the scaling algorithm).
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/qedit/tests/mediadet.c | 337 +++++++++++++++++++++++++++++++++++-
1 file changed, 333 insertions(+), 4 deletions(-)
diff --git a/dlls/qedit/tests/mediadet.c b/dlls/qedit/tests/mediadet.c
index dc83bb9..010b746 100644
--- a/dlls/qedit/tests/mediadet.c
+++ b/dlls/qedit/tests/mediadet.c
@@ -136,6 +136,11 @@ struct testfilter
struct strmbase_filter filter;
struct strmbase_source source;
IMediaSeeking IMediaSeeking_iface;
+
+ BOOL bitmap_grab_mode;
+ const GUID *time_format;
+ LONGLONG cur_pos;
+ HANDLE thread;
};
static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
@@ -158,10 +163,103 @@ static void testfilter_destroy(struct strmbase_filter *iface)
strmbase_filter_cleanup(&filter->filter);
}
+static DWORD WINAPI testfilter_frame_thread(void *arg)
+{
+ REFERENCE_TIME start_time, end_time;
+ struct testfilter *filter = arg;
+ IMemAllocator *allocator;
+ IMediaSample *sample;
+ unsigned i;
+ HRESULT hr;
+ DWORD fill;
+ BYTE *data;
+
+ hr = IMemInputPin_GetAllocator(filter->source.pMemInputPin, &allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ start_time = (filter->cur_pos == 0xdeadbeef) ? 0 : filter->cur_pos;
+ while (hr == S_OK)
+ {
+ hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
+ if (hr == VFW_E_NOT_COMMITTED)
+ {
+ IMemAllocator_Commit(allocator);
+ hr = IMemAllocator_GetBuffer(allocator, &sample, NULL, NULL, 0);
+ }
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaSample_GetPointer(sample, &data);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ fill = (start_time / 10000 & 0xffffff) ^ 0xccaabb;
+ for (i = 0; i < 640 * 480 * 3; i += 3)
+ {
+ data[i] = fill ^ i;
+ data[i + 1] = fill >> 8 ^ i;
+ data[i + 2] = fill >> 16 ^ i;
+ }
+
+ hr = IMediaSample_SetActualDataLength(sample, 640 * 480 * 3);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ end_time = start_time + 400000;
+ hr = IMediaSample_SetTime(sample, &start_time, &end_time);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ start_time = end_time;
+
+ if (winetest_debug > 1) trace("%04x: Sending frame.\n", GetCurrentThreadId());
+ hr = IMemInputPin_Receive(filter->source.pMemInputPin, sample);
+ if (winetest_debug > 1) trace("%04x: Returned %#x.\n", GetCurrentThreadId(), hr);
+
+ IMediaSample_Release(sample);
+ }
+
+ IMemAllocator_Release(allocator);
+ return hr;
+}
+
+static HRESULT testfilter_init_stream(struct strmbase_filter *iface)
+{
+ struct testfilter *filter = impl_from_strmbase_filter(iface);
+ HRESULT hr;
+
+ if (!filter->bitmap_grab_mode) return S_OK;
+
+ hr = BaseOutputPinImpl_Active(&filter->source);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ filter->thread = CreateThread(NULL, 0, testfilter_frame_thread, filter, 0, NULL);
+ ok(filter->thread != NULL, "Failed to create thread: %#x.\n", GetLastError());
+
+ return S_OK;
+}
+
+static HRESULT testfilter_cleanup_stream(struct strmbase_filter *iface)
+{
+ struct testfilter *filter = impl_from_strmbase_filter(iface);
+ HRESULT hr;
+
+ if (filter->thread)
+ {
+ WaitForSingleObject(filter->thread, INFINITE);
+ CloseHandle(filter->thread);
+ filter->thread = NULL;
+ }
+ if (!filter->bitmap_grab_mode)
+ return S_OK;
+
+ hr = BaseOutputPinImpl_Inactive(&filter->source);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ return S_OK;
+}
+
static const struct strmbase_filter_ops testfilter_ops =
{
.filter_get_pin = testfilter_get_pin,
.filter_destroy = testfilter_destroy,
+ .filter_init_stream = testfilter_init_stream,
+ .filter_cleanup_stream = testfilter_cleanup_stream
};
static inline struct testfilter *impl_from_strmbase_pin(struct strmbase_pin *iface)
@@ -175,7 +273,7 @@ static HRESULT testsource_get_media_type(struct strmbase_pin *iface, unsigned in
{
.bmiHeader.biSize = sizeof(BITMAPINFOHEADER),
.bmiHeader.biWidth = 640,
- .bmiHeader.biHeight = 480,
+ .bmiHeader.biHeight = -480,
.bmiHeader.biPlanes = 1,
.bmiHeader.biBitCount = 24,
.bmiHeader.biCompression = BI_RGB,
@@ -211,10 +309,37 @@ static HRESULT testsource_query_interface(struct strmbase_pin *iface, REFIID iid
return S_OK;
}
+static HRESULT WINAPI testsource_DecideBufferSize(struct strmbase_source *iface,
+ IMemAllocator *allocator, ALLOCATOR_PROPERTIES *requested)
+{
+ ALLOCATOR_PROPERTIES actual;
+
+ if (!requested->cbAlign)
+ requested->cbAlign = 1;
+
+ if (requested->cbBuffer < 640 * 480 * 3)
+ requested->cbBuffer = 640 * 480 * 3;
+
+ if (!requested->cBuffers)
+ requested->cBuffers = 1;
+
+ return IMemAllocator_SetProperties(allocator, requested, &actual);
+}
+
static HRESULT WINAPI testsource_DecideAllocator(struct strmbase_source *iface,
IMemInputPin *peer, IMemAllocator **allocator)
{
- return S_OK;
+ ALLOCATOR_PROPERTIES props = {0};
+ HRESULT hr;
+
+ hr = BaseOutputPinImpl_InitAllocator(iface, allocator);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ IMemInputPin_GetAllocatorRequirements(peer, &props);
+ hr = testsource_DecideBufferSize(iface, *allocator, &props);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ return IMemInputPin_NotifyAllocator(peer, *allocator, FALSE);
}
static const struct strmbase_source_ops testsource_ops =
@@ -222,6 +347,7 @@ static const struct strmbase_source_ops testsource_ops =
.base.pin_get_media_type = testsource_get_media_type,
.base.pin_query_interface = testsource_query_interface,
.pfnAttemptConnection = BaseOutputPinImpl_AttemptConnection,
+ .pfnDecideBufferSize = testsource_DecideBufferSize,
.pfnDecideAllocator = testsource_DecideAllocator,
};
@@ -250,6 +376,15 @@ static ULONG WINAPI testseek_Release(IMediaSeeking *iface)
static HRESULT WINAPI testseek_GetCapabilities(IMediaSeeking *iface, DWORD *caps)
{
+ struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+ if (filter->bitmap_grab_mode)
+ {
+ if (winetest_debug > 1) trace("IMediaSeeking_GetCapabilities()\n");
+ *caps = 0; /* Doesn't seem to have any effect, despite being called */
+ return S_OK;
+ }
+
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
}
@@ -262,6 +397,15 @@ static HRESULT WINAPI testseek_CheckCapabilities(IMediaSeeking *iface, DWORD *ca
static HRESULT WINAPI testseek_IsFormatSupported(IMediaSeeking *iface, const GUID *format)
{
+ struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+ if (filter->bitmap_grab_mode)
+ {
+ if (winetest_debug > 1) trace("IMediaSeeking_IsFormatSupported(%s)\n", wine_dbgstr_guid(format));
+ ok(IsEqualGUID(format, &TIME_FORMAT_MEDIA_TIME), "Unexpected format %s.\n", wine_dbgstr_guid(format));
+ return S_OK;
+ }
+
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
}
@@ -274,12 +418,29 @@ static HRESULT WINAPI testseek_QueryPreferredFormat(IMediaSeeking *iface, GUID *
static HRESULT WINAPI testseek_GetTimeFormat(IMediaSeeking *iface, GUID *format)
{
+ struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+ if (filter->bitmap_grab_mode)
+ {
+ if (winetest_debug > 1) trace("IMediaSeeking_GetTimeFormat()\n");
+ *format = *filter->time_format;
+ return S_OK;
+ }
+
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
}
static HRESULT WINAPI testseek_IsUsingTimeFormat(IMediaSeeking *iface, const GUID *format)
{
+ struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+ if (filter->bitmap_grab_mode)
+ {
+ if (winetest_debug > 1) trace("IMediaSeeking_IsUsingTimeFormat(%s)\n", wine_dbgstr_guid(format));
+ return IsEqualGUID(format, filter->time_format) ? S_OK : S_FALSE;
+ }
+
ok(0, "Unexpected call.\n");
return E_NOTIMPL;
}
@@ -320,8 +481,35 @@ static HRESULT WINAPI testseek_ConvertTimeFormat(IMediaSeeking *iface, LONGLONG
static HRESULT WINAPI testseek_SetPositions(IMediaSeeking *iface, LONGLONG *current,
DWORD current_flags, LONGLONG *stop, DWORD stop_flags)
{
- ok(0, "Unexpected call.\n");
- return E_NOTIMPL;
+ struct testfilter *filter = impl_from_IMediaSeeking(iface);
+
+ if (winetest_debug > 1)
+ trace("IMediaSeeking_SetPositions(0x%s, 0x%08x, 0x%s, 0x%08x)\n",
+ wine_dbgstr_longlong(*current), current_flags, wine_dbgstr_longlong(*stop), stop_flags);
+
+ if (filter->bitmap_grab_mode)
+ {
+ ok(*stop == *current || !*stop, "Unexpected stop position: 0x%s.\n", wine_dbgstr_longlong(*stop));
+ ok(current_flags == (AM_SEEKING_AbsolutePositioning | AM_SEEKING_ReturnTime),
+ "Unexpected current_flags 0x%08x.\n", current_flags);
+ ok(stop_flags == AM_SEEKING_AbsolutePositioning || !stop_flags, "Unexpected stop_flags 0x%08x.\n", stop_flags);
+
+ if (filter->thread)
+ {
+ IPin_BeginFlush(filter->source.pin.peer);
+ WaitForSingleObject(filter->thread, INFINITE);
+ CloseHandle(filter->thread);
+ filter->cur_pos = *current;
+ IPin_EndFlush(filter->source.pin.peer);
+
+ filter->thread = CreateThread(NULL, 0, testfilter_frame_thread, filter, 0, NULL);
+ ok(filter->thread != NULL, "Failed to create thread: %#x.\n", GetLastError());
+ }
+ else
+ filter->cur_pos = *current;
+ }
+
+ return S_OK;
}
static HRESULT WINAPI testseek_GetPositions(IMediaSeeking *iface, LONGLONG *current, LONGLONG *stop)
@@ -386,6 +574,8 @@ static void testfilter_init(struct testfilter *filter)
strmbase_filter_init(&filter->filter, NULL, &clsid, &testfilter_ops);
strmbase_source_init(&filter->source, &filter->filter, L"", &testsource_ops);
filter->IMediaSeeking_iface.lpVtbl = &testseek_vtbl;
+ filter->cur_pos = 0xdeadbeef;
+ filter->time_format = &TIME_FORMAT_MEDIA_TIME;
}
static WCHAR test_avi_filename[MAX_PATH];
@@ -1117,6 +1307,144 @@ static void test_COM_sg_enumpins(void)
IBaseFilter_Release(bf);
}
+static void test_bitmap_grab_mode(void)
+{
+ static const GUID *time_formats[] =
+ {
+ &TIME_FORMAT_NONE,
+ &TIME_FORMAT_FRAME,
+ &TIME_FORMAT_SAMPLE,
+ &TIME_FORMAT_FIELD,
+ &TIME_FORMAT_BYTE,
+ &TIME_FORMAT_MEDIA_TIME
+ };
+ struct testfilter testfilter;
+ IMediaDet *detector;
+ AM_MEDIA_TYPE mt;
+ double duration;
+ IUnknown *unk;
+ unsigned i;
+ HRESULT hr;
+ LONG count;
+ ULONG ref;
+ GUID guid;
+ BSTR str;
+
+ hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMediaDet, (void **)&detector);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ /* EnterBitmapGrabMode only seeks once, and if SeekTime is non-negative */
+ testfilter_init(&testfilter);
+ testfilter.bitmap_grab_mode = TRUE;
+ hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaDet_EnterBitmapGrabMode(detector, -1.0);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(testfilter.cur_pos == 0xdeadbeef, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(testfilter.cur_pos == 0xdeadbeef, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+
+ ref = IMediaDet_Release(detector);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+
+ /* Time formats other than TIME_FORMAT_MEDIA_TIME return E_NOTIMPL */
+ for (i = 0; i < ARRAY_SIZE(time_formats); i++)
+ {
+ hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMediaDet, (void **)&detector);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ testfilter_init(&testfilter);
+ testfilter.bitmap_grab_mode = TRUE;
+ testfilter.time_format = time_formats[i];
+ hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 1337.0);
+ if (time_formats[i] == &TIME_FORMAT_MEDIA_TIME)
+ {
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(testfilter.cur_pos == 13370000000LL, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(testfilter.cur_pos == 13370000000LL, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+ }
+ else
+ ok(hr == E_NOTIMPL, "Got hr %#x.\n", hr);
+
+ ref = IMediaDet_Release(detector);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ }
+
+ hr = CoCreateInstance(&CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMediaDet, (void **)&detector);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ testfilter_init(&testfilter);
+ testfilter.bitmap_grab_mode = TRUE;
+ hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 0.0);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(testfilter.cur_pos == 0, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+ hr = IMediaDet_EnterBitmapGrabMode(detector, 1.0);
+ todo_wine ok(hr == S_OK, "Got hr %#x.\n", hr);
+ todo_wine ok(testfilter.cur_pos == 0, "Current position was set to 0x%s.\n", wine_dbgstr_longlong(testfilter.cur_pos));
+
+ /* These still work */
+ hr = IMediaDet_get_Filter(detector, &unk);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ IUnknown_Release(unk);
+ hr = IMediaDet_get_Filename(detector, &str);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ SysFreeString(str);
+ hr = IMediaDet_get_CurrentStream(detector, &count);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(count == 0, "Got stream %d.\n", count);
+
+ /* These don't work anymore */
+ hr = IMediaDet_get_OutputStreams(detector, &count);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IMediaDet_get_FrameRate(detector, &duration);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IMediaDet_get_StreamLength(detector, &duration);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IMediaDet_get_StreamMediaType(detector, &mt);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ if (SUCCEEDED(hr)) FreeMediaType(&mt);
+ hr = IMediaDet_get_StreamType(detector, &guid);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ hr = IMediaDet_get_StreamTypeB(detector, &str);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+ if (SUCCEEDED(hr)) SysFreeString(str);
+ hr = IMediaDet_put_CurrentStream(detector, 0);
+ todo_wine ok(hr == E_INVALIDARG, "Got hr %#x.\n", hr);
+
+ /* Changing filter resets bitmap grab mode */
+ testfilter.bitmap_grab_mode = FALSE;
+ hr = IMediaDet_put_Filter(detector, &testfilter.filter.IUnknown_inner);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ hr = IMediaDet_get_OutputStreams(detector, &count);
+ ok(hr == S_OK, "Got hr %#x.\n", hr);
+ ok(count == 1, "Got %d streams.\n", count);
+
+ ref = IMediaDet_Release(detector);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+ ref = IBaseFilter_Release(&testfilter.filter.IBaseFilter_iface);
+ ok(!ref, "Got outstanding refcount %d.\n", ref);
+}
+
START_TEST(mediadet)
{
IMediaDet *detector;
@@ -1145,6 +1473,7 @@ START_TEST(mediadet)
test_put_filter();
test_samplegrabber();
test_COM_sg_enumpins();
+ test_bitmap_grab_mode();
ret = DeleteFileW(test_avi_filename);
ok(ret, "Failed to delete file, error %u.\n", GetLastError());
--
2.21.0
2
23
Oct. 27, 2020
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com>
---
dlls/mfplat/buffer.c | 44 ++++++++++++++++++++++++++++++++++++++
dlls/mfplat/tests/mfplat.c | 13 +++++++++++
2 files changed, 57 insertions(+)
diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c
index a3311bc10f1..5e969e14ec9 100644
--- a/dlls/mfplat/buffer.c
+++ b/dlls/mfplat/buffer.c
@@ -31,6 +31,7 @@ struct memory_buffer
{
IMFMediaBuffer IMFMediaBuffer_iface;
IMF2DBuffer2 IMF2DBuffer2_iface;
+ IMFGetService IMFGetService_iface;
LONG refcount;
BYTE *data;
@@ -88,6 +89,11 @@ static struct memory_buffer *impl_from_IMF2DBuffer2(IMF2DBuffer2 *iface)
return CONTAINING_RECORD(iface, struct memory_buffer, IMF2DBuffer2_iface);
}
+static struct memory_buffer *impl_from_IMFGetService(IMFGetService *iface)
+{
+ return CONTAINING_RECORD(iface, struct memory_buffer, IMFGetService_iface);
+}
+
static inline struct sample *impl_from_IMFSample(IMFSample *iface)
{
return CONTAINING_RECORD(iface, struct sample, IMFSample_iface);
@@ -240,6 +246,10 @@ static HRESULT WINAPI memory_1d_2d_buffer_QueryInterface(IMFMediaBuffer *iface,
{
*out = &buffer->IMF2DBuffer2_iface;
}
+ else if (IsEqualIID(riid, &IID_IMFGetService))
+ {
+ *out = &buffer->IMFGetService_iface;
+ }
else
{
WARN("Unsupported interface %s.\n", debugstr_guid(riid));
@@ -511,6 +521,39 @@ static const IMF2DBuffer2Vtbl memory_2d_buffer_vtbl =
memory_2d_buffer_Copy2DTo,
};
+static HRESULT WINAPI memory_2d_buffer_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
+{
+ struct memory_buffer *buffer = impl_from_IMFGetService(iface);
+ return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj);
+}
+
+static ULONG WINAPI memory_2d_buffer_gs_AddRef(IMFGetService *iface)
+{
+ struct memory_buffer *buffer = impl_from_IMFGetService(iface);
+ return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface);
+}
+
+static ULONG WINAPI memory_2d_buffer_gs_Release(IMFGetService *iface)
+{
+ struct memory_buffer *buffer = impl_from_IMFGetService(iface);
+ return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface);
+}
+
+static HRESULT WINAPI memory_2d_buffer_gs_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
+{
+ TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
+
+ return E_NOTIMPL;
+}
+
+static const IMFGetServiceVtbl memory_2d_buffer_gs_vtbl =
+{
+ memory_2d_buffer_gs_QueryInterface,
+ memory_2d_buffer_gs_AddRef,
+ memory_2d_buffer_gs_Release,
+ memory_2d_buffer_gs_GetService,
+};
+
static HRESULT memory_buffer_init(struct memory_buffer *buffer, DWORD max_length, DWORD alignment,
const IMFMediaBufferVtbl *vtbl)
{
@@ -620,6 +663,7 @@ static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bo
}
object->IMF2DBuffer2_iface.lpVtbl = &memory_2d_buffer_vtbl;
+ object->IMFGetService_iface.lpVtbl = &memory_2d_buffer_gs_vtbl;
object->_2d.plane_size = plane_size;
object->_2d.width = stride;
object->_2d.height = height;
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 971469ec574..906454851a8 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -1818,6 +1818,7 @@ static void test_system_memory_buffer(void)
HRESULT hr;
DWORD length, max;
BYTE *data, *data2;
+ IUnknown *unk;
hr = MFCreateMemoryBuffer(1024, NULL);
ok(hr == E_INVALIDARG || hr == E_POINTER, "got 0x%08x\n", hr);
@@ -1836,6 +1837,9 @@ static void test_system_memory_buffer(void)
hr = MFCreateMemoryBuffer(1024, &buffer);
ok(hr == S_OK, "got 0x%08x\n", hr);
+ hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&unk);
+ ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
+
hr = IMFMediaBuffer_GetMaxLength(buffer, NULL);
ok(hr == E_INVALIDARG || hr == E_POINTER, "got 0x%08x\n", hr);
@@ -5155,6 +5159,7 @@ static void test_MFCreate2DMediaBuffer(void)
IMF2DBuffer *_2dbuffer;
IMFMediaBuffer *buffer;
int i, pitch, pitch2;
+ IUnknown *unk;
HRESULT hr;
BOOL ret;
@@ -5177,6 +5182,10 @@ static void test_MFCreate2DMediaBuffer(void)
hr = pMFCreate2DMediaBuffer(2, 3, MAKEFOURCC('N','V','1','2'), FALSE, &buffer);
ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr);
+ hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&unk);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ IUnknown_Release(unk);
+
/* Full backing buffer size, with 64 bytes per row alignment. */
hr = IMFMediaBuffer_GetMaxLength(buffer, &max_length);
ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr);
@@ -5405,6 +5414,7 @@ static void test_MFCreateMediaBufferFromMediaType(void)
HRESULT hr;
IMFMediaType *media_type;
unsigned int i;
+ IUnknown *unk;
if (!pMFCreateMediaBufferFromMediaType)
{
@@ -5437,6 +5447,9 @@ static void test_MFCreateMediaBufferFromMediaType(void)
if (FAILED(hr))
break;
+ hr = IMFMediaBuffer_QueryInterface(buffer, &IID_IMFGetService, (void **)&unk);
+ ok(hr == E_NOINTERFACE, "Unexpected hr %#x.\n", hr);
+
hr = IMFMediaBuffer_GetMaxLength(buffer, &length);
ok(hr == S_OK, "Failed to get length, hr %#x.\n", hr);
ok(ptr->buffer_length == length, "%d: unexpected buffer length %u, expected %u.\n", i, length, ptr->buffer_length);
--
2.28.0
2
3