Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 69 additions & 34 deletions src/tabs/viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ const std::initializer_list<FileSignature> supported_sdr_encode_formats =
FileSignature { L"image/bmp", { L".bmp" }, { 0x42, 0x4D } },
FileSignature { L"image/tiff", { L".tiff", L".tif" }, { 0x49, 0x49, 0x2A, 0x00 } }, // TIFF: little-endian
FileSignature { L"image/tiff", { L".tiff", L".tif" }, { 0x4D, 0x4D, 0x00, 0x2A } }, // TIFF: big-endian
FileSignature { L"image/avif", { L".avif" }, { 0x00, 0x00, 0x00, 0x20, 0x66, 0x74, 0x79, 0x70, 0x61, 0x76, 0x69, 0x66 } }, // ftypavif
//FileSignature { L"image/vnd-ms.dds", { L".dds" }, { 0x44, 0x44, 0x53, 0x20 } },
//FileSignature { L"image/x-targa", { L".tga" }, { 0x00, } }, // TGA has no real unique header identifier, so just use the file extension on those
};
Expand Down Expand Up @@ -1603,7 +1604,7 @@ LoadLibraryTexture (image_s& image)

SYSTEM_INFO si = { };
GetSystemInfo (&si);

#if _WIN64
avif_decoder->maxThreads =
std::min (64U, std::min ((UINT)si.dwNumberOfProcessors, (UINT)__popcnt64 (si.dwActiveProcessorMask)));
Expand All @@ -1626,17 +1627,26 @@ LoadLibraryTexture (image_s& image)
SK_avifRGBImageSetDefaults (&rgb, avif_decoder->image);

int bpc = rgb.depth;
bool is_hdr_image = (avif_decoder->image->depth > 8) ||
(avif_decoder->image->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084);

DXGI_FORMAT dxgi_format = is_hdr_image ? DXGI_FORMAT_R16G16B16A16_FLOAT :
DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;

if (avif_decoder->image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED)
{
//ideally try to retrieve primaries from icc here
}

rgb.depth = 16;
rgb.format = AVIF_RGB_FORMAT_RGBA;
rgb.depth = is_hdr_image ? 16 : 8;
rgb.format = is_hdr_image ? AVIF_RGB_FORMAT_RGBA : AVIF_RGB_FORMAT_BGRA;
#if _WIN64
rgb.maxThreads = std::min (64U, std::min ((UINT)si.dwNumberOfProcessors, (UINT)__popcnt64 (si.dwActiveProcessorMask)));
#else
rgb.maxThreads = std::min (32U, std::min ((UINT)si.dwNumberOfProcessors, (UINT)__popcnt (si.dwActiveProcessorMask)));
#endif
rgb.ignoreAlpha = true;
rgb.isFloat = true;
rgb.isFloat = is_hdr_image ? true : false;

SK_avifRGBImageAllocatePixels ( &rgb);
SK_avifImageYUVToRGB (avif_decoder->image, &rgb);
Expand All @@ -1646,21 +1656,21 @@ LoadLibraryTexture (image_s& image)

DirectX::ScratchImage temp_img;

if (SUCCEEDED (temp_img.Initialize2D (DXGI_FORMAT_R16G16B16A16_FLOAT, static_cast <size_t> (image.width),
static_cast <size_t> (image.height), 1, 1)))
if (SUCCEEDED (temp_img.Initialize2D (dxgi_format, static_cast <size_t> (image.width),
static_cast <size_t> (image.height), 1, 1)))
{
using namespace DirectX;

image.channels = 3;
image.bpc = bpc;

// XXX
image.light_info.isHDR = true;
image.is_hdr = true;
image.light_info.isHDR = is_hdr_image;
image.is_hdr = is_hdr_image;

succeeded = true;

meta.format = DXGI_FORMAT_R16G16B16A16_FLOAT;
meta.format = dxgi_format;
meta.width = static_cast <size_t> (image.width);
meta.height = static_cast <size_t> (image.height);
meta.depth = 1;
Expand All @@ -1677,13 +1687,13 @@ LoadLibraryTexture (image_s& image)

memcpy (pixels_buffer, rgb.pixels, rgb.rowBytes * rgb.height);

if (avif_decoder->image->transferCharacteristics != AVIF_TRANSFER_CHARACTERISTICS_PQ)
if (avif_decoder->image->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED)
{
ImGui::InsertNotification (
ImGui::InsertNotification(
{
ImGuiToastType::Error,
15000,
"Unsupported AVIF Transfer Characteristics: %d",
10000,
"Unspecified AVIF Transfer Characteristics: %d",
avif_decoder->image->transferCharacteristics
}
);
Expand Down Expand Up @@ -1779,36 +1789,55 @@ LoadLibraryTexture (image_s& image)
else if (avif_decoder->image->colorPrimaries == AVIF_COLOR_PRIMARIES_BT709 ||
avif_decoder->image->colorPrimaries == AVIF_COLOR_PRIMARIES_SRGB)
{
if ( SUCCEEDED ( TransformImage (*temp_img.GetImages (),
[&]( XMVECTOR* outPixels,
const XMVECTOR* inPixels,
size_t width,
size_t y)
if (avif_decoder->image->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_PQ ||
avif_decoder->image->transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084)
{
if ( SUCCEEDED ( TransformImage(*temp_img.GetImages (),
[&]( XMVECTOR* outPixels,
const XMVECTOR* inPixels,
size_t width,
size_t y)
{
UNREFERENCED_PARAMETER(y);

for (size_t j = 0; j < width; ++j)
{
UNREFERENCED_PARAMETER(y);
XMVECTOR v = inPixels[j];

for (size_t j = 0; j < width; ++j)
{
XMVECTOR v = inPixels [j];
v =
XMVectorScale(
SKIV_Image_PQToLinear(v), 125.0f
);

v =
XMVectorScale (
SKIV_Image_PQToLinear (v), 125.0f
);

outPixels [j] = v;
}
}, img )
)
outPixels[j] = v;
}
}, img)
)
)
{
temp_img.Release ();
}
}
else
{
std::swap(img, temp_img);
temp_img.Release ();
}
}

else
{
if (avif_decoder->image->colorPrimaries != AVIF_COLOR_PRIMARIES_BT2100 &&
if (avif_decoder->image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED) {
ImGui::InsertNotification(
{
ImGuiToastType::Error,
10000,
"Unspecified AVIF Color Primaries: %d",
avif_decoder->image->transferCharacteristics
}
);
}
else if (avif_decoder->image->colorPrimaries != AVIF_COLOR_PRIMARIES_BT2100 &&
avif_decoder->image->colorPrimaries != AVIF_COLOR_PRIMARIES_BT2020)
{
ImGui::InsertNotification (
Expand All @@ -1820,8 +1849,14 @@ LoadLibraryTexture (image_s& image)
}
);
}

if ( SUCCEEDED ( TransformImage (*temp_img.GetImages (),
//HDR 8-bpc is not handled correctly
if (bpc == 8 && avif_decoder->image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED) {
//for now treat it as SDR, but that's incorrect measure in long run
std::swap(img, temp_img);
temp_img.Release();
}
//everything that reached here is treated as HDR image
else if ( SUCCEEDED ( TransformImage (*temp_img.GetImages (),
[&]( XMVECTOR* outPixels,
const XMVECTOR* inPixels,
size_t width,
Expand Down
105 changes: 102 additions & 3 deletions src/utility/image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1677,6 +1677,8 @@
HRESULT
SKIV_Image_SaveToDisk_SDR (const DirectX::Image& image, const wchar_t* wszFileName, const bool force_sRGB)
{
static SKIF_RegistrySettings& _registry =
SKIF_RegistrySettings::GetInstance();
using namespace DirectX;

ScratchImage
Expand Down Expand Up @@ -1866,8 +1868,9 @@
bPrefer10bpcAs32bpp = is_hdr;
}

// AVIF technically works for SDR... do we want to support it?
// If we do, WIC won't help us, however.
else if (StrStrIW(wszExtension, L"avif")) {

}

else
{
Expand Down Expand Up @@ -2121,6 +2124,102 @@
final_sdr.GetImages ();
}

if (StrStrIW(wszExtension, L"avif"))
{
// Ensure the AVIF library functions are available
extern bool isAVIFEncoderAvailable(void);
if (!isAVIFEncoderAvailable())
return E_NOTIMPL;

uint32_t width = static_cast <uint32_t> (image.width);
uint32_t height = static_cast <uint32_t> (image.height);

// --- SDR Specific AVIF Settings ---
// use 8-bit depth for SDR
int bit_depth = 8;
// YUV 4:4:4 is highest quality
avifPixelFormat yuv_format = AVIF_PIXEL_FORMAT_YUV444;

avifResult rgbToYuvResult = AVIF_RESULT_NO_CONTENT;
avifResult addResult = AVIF_RESULT_NO_CONTENT;
avifResult encodeResult = AVIF_RESULT_NO_CONTENT;

avifRWData avifOutput = AVIF_DATA_EMPTY;
avifRGBImage rgb = { };
avifEncoder* encoder = nullptr;

avifImage* avif_image = SK_avifImageCreate(width, height, bit_depth, yuv_format);

if (avif_image != nullptr) {
// SDR Colorimetry (BT.709 / sRGB)
avif_image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
avif_image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
avif_image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
avif_image->yuvRange = AVIF_RANGE_FULL;

SK_avifRGBImageSetDefaults(&rgb, avif_image);
rgb.rowBytes = pOutputImage->rowPitch;

Check warning on line 2161 in src/utility/image.cpp

View workflow job for this annotation

GitHub Actions / Build

^ [D:\a\SKIV\SKIV\SKIV.vcxproj]

Check warning on line 2161 in src/utility/image.cpp

View workflow job for this annotation

GitHub Actions / Build

rgb.rowBytes = pOutputImage->rowPitch; [D:\a\SKIV\SKIV\SKIV.vcxproj]
rgb.depth = 8;
rgb.ignoreAlpha = false;

//maybe there's a better way to handle format
if (image.format == DXGI_FORMAT_R8G8B8A8_UNORM ||
image.format == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB)
rgb.format = AVIF_RGB_FORMAT_RGBA;
else
rgb.format = AVIF_RGB_FORMAT_BGRA;
rgb.pixels = (uint8_t*)pOutputImage->pixels;

// RGB data to YUV
rgbToYuvResult = SK_avifImageRGBToYUV(avif_image, &rgb);

if (rgbToYuvResult == AVIF_RESULT_OK) {
encoder = SK_avifEncoderCreate();
if (encoder != nullptr) {
SYSTEM_INFO si = { };
GetSystemInfo(&si);
// encoder settings
encoder->quality = _registry.avif.quality;
encoder->qualityAlpha = _registry.avif.quality;
encoder->speed = _registry.avif.speed;
encoder->timescale = 1;
encoder->minQuantizer = AVIF_QUANTIZER_BEST_QUALITY;
encoder->maxQuantizer = AVIF_QUANTIZER_WORST_QUALITY;
encoder->codecChoice = AVIF_CODEC_CHOICE_AUTO;
encoder->repetitionCount = AVIF_REPETITION_COUNT_INFINITE;
#ifdef _M_X64
encoder->maxThreads = std::min(64U, std::min((UINT)si.dwNumberOfProcessors, (UINT)__popcnt64(si.dwActiveProcessorMask)));
#endif
addResult = SK_avifEncoderAddImage(encoder, avif_image, 1, AVIF_ADD_IMAGE_FLAG_SINGLE);
encodeResult = SK_avifEncoderFinish(encoder, &avifOutput);
}
}
}


if (rgbToYuvResult != AVIF_RESULT_OK || addResult != AVIF_RESULT_OK || encodeResult != AVIF_RESULT_OK) {
// Optional: Add logging for error codes here
PLOG_ERROR << "avif conversion failed";
}

if (encodeResult == AVIF_RESULT_OK) {
// Write the encoded data to disk
FILE* fAVIF = _wfopen(wszImplicitFileName, L"wb");
if (fAVIF != nullptr) {
fwrite(avifOutput.data, 1, avifOutput.size, fAVIF);
fclose(fAVIF);
}
}

//cleanup
if (avif_image != nullptr) SK_avifImageDestroy(avif_image);
if (encoder != nullptr) SK_avifEncoderDestroy(encoder);

//SK_avifRGBImageFreePixels(&rgb);

return (encodeResult == AVIF_RESULT_OK) ? S_OK : E_FAIL;
}

///DirectX::TexMetadata orig_tex_metadata;
///CComPtr <IWICMetadataQueryReader> pQueryReader;
///
Expand Down Expand Up @@ -2904,7 +3003,7 @@
avif_image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
break;
default:
return false;
return E_UNEXPECTED;
}

SK_avifRGBImageSetDefaults (&rgb, avif_image);
Expand Down
Loading