#include "basisthumbprovider.h" #include #include "basisu_transcoder.cpp" #include "helpers.h" #pragma comment(lib, "Shlwapi.lib") using namespace basist; BasisThumbProvider::BasisThumbProvider() : count(1), stream(NULL) { dprintf("BasisThumbProvider ctor"); basisu_transcoder_init(); } BasisThumbProvider::~BasisThumbProvider() { dprintf("BasisThumbProvider **dtor**"); if (stream) { stream->Release(); stream = NULL; } } IFACEMETHODIMP BasisThumbProvider::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(BasisThumbProvider, IThumbnailProvider), QITABENT(BasisThumbProvider, IInitializeWithStream), {0}, }; return QISearch(this, qit, riid, ppv); } IFACEMETHODIMP_(ULONG) BasisThumbProvider::AddRef() { return InterlockedIncrement(&count); } IFACEMETHODIMP_(ULONG) BasisThumbProvider::Release() { LONG refs = InterlockedDecrement(&count); if (refs == 0) { delete this; } return refs; } IFACEMETHODIMP BasisThumbProvider::Initialize(IStream *pStream, DWORD grfMode) { dprintf("BasisThumbProvider::Initialize"); HRESULT hr = HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED); if (!stream) { hr = pStream->QueryInterface(&stream); } return hr; } // Note: thumbnails get written here: %LocalAppData%\Microsoft\Windows\Explorer IFACEMETHODIMP BasisThumbProvider::GetThumbnail(UINT cx, HBITMAP *phbmp, WTS_ALPHATYPE *pdwAlpha) { STATSTG stat; if (stream && SUCCEEDED(stream->Stat(&stat, STATFLAG_NONAME))) { if (void* data = malloc(static_cast(stat.cbSize.LowPart))) { ULONG size = 0; if (SUCCEEDED(stream->Read(data, static_cast(stat.cbSize.LowPart), &size))) { if (size == stat.cbSize.LowPart) { basisu_transcoder transcoder; if (transcoder.validate_header(data, size)) { dprintf("Requested %d bytes for %dx%d image", size, cx, cx); basisu_image_info info; if (transcoder.get_image_info(data, size, info, 0)) { uint32_t level = 0; uint32_t descW = 0, descH = 0, blocks; for (uint32_t n = 0; n < info.m_total_levels; n++) { if (transcoder.get_image_level_desc(data, size, 0, n, descW, descH, blocks)) { dprintf("mipmap level w: %d, h: %d (blocks: %d)", descW, descH, blocks); if (cx >= std::max(descW, descH)) { level = n; break; } } } basisu_file_info fileInfo; transcoder.get_file_info(data, size, fileInfo); if (transcoder.start_transcoding(data, size)) { uint32_t bytes = basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format::cTFRGBA32) * descW * descH; dprintf("Started transcode (%dx%d @ %d bytes)", descW, descH, bytes); if (void* rgbBuf = malloc(bytes)) { // Note: the API expects total pixels here instead of blocks for cTFRGBA32 if (transcoder.transcode_image_level(data, size, 0, level, rgbBuf, descW * descH, transcoder_texture_format::cTFRGBA32)) { dprintf("Decoded!!!!"); *phbmp = rgbToBitmap(static_cast(rgbBuf), descW, descH, fileInfo.m_y_flipped); } delete rgbBuf; } } } } } } free(data); } } return (*phbmp) ? S_OK : S_FALSE; } //********************************** Factory *********************************/ BasisThumbProviderFactory::BasisThumbProviderFactory() : count(1) {} BasisThumbProviderFactory::~BasisThumbProviderFactory() {} IFACEMETHODIMP BasisThumbProviderFactory::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(BasisThumbProviderFactory, IClassFactory), {0}, }; return QISearch(this, qit, riid, ppv); } IFACEMETHODIMP_(ULONG) BasisThumbProviderFactory::AddRef() { return InterlockedIncrement(&count); } IFACEMETHODIMP_(ULONG) BasisThumbProviderFactory::Release() { LONG refs = InterlockedDecrement(&count); if (refs == 0) { delete this; } return refs; } IFACEMETHODIMP BasisThumbProviderFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) { HRESULT hr = CLASS_E_NOAGGREGATION; if (pUnkOuter == NULL) { hr = E_OUTOFMEMORY; if (BasisThumbProvider* provider = new (std::nothrow) BasisThumbProvider()) { hr = provider->QueryInterface(riid, ppv); provider->Release(); } } return hr; } IFACEMETHODIMP BasisThumbProviderFactory::LockServer(BOOL fLock) { if (fLock) { InterlockedIncrement(&count); } else { InterlockedDecrement(&count); } return S_OK; }