diff --git a/src/avif/img/Conversion.hpp b/src/avif/img/Conversion.hpp index c60a155..9a747d2 100644 --- a/src/avif/img/Conversion.hpp +++ b/src/avif/img/Conversion.hpp @@ -31,37 +31,35 @@ struct ChromaSampler { namespace detail { -template +template constexpr void calcYUV(uint16_t const ir, uint16_t const ig, uint16_t const ib, typename avif::img::color::YUV::Type* dstY, typename avif::img::color::YUV::Type* dstU, typename avif::img::color::YUV::Type* dstV) { using Quantizer = typename avif::img::color::Quantizer; using RGBSpec = typename avif::img::color::RGB; - auto converter = ConverterFactory::create(); float const r = static_cast(ir) / RGBSpec::max; float const g = static_cast(ig) / RGBSpec::max; float const b = static_cast(ib) / RGBSpec::max; if (isMonoYUV) { float y = 0; - converter.calcYUV(r,g,b, &y, nullptr, nullptr); + Converter::calcYUV(r,g,b, &y, nullptr, nullptr); *dstY = Quantizer::quantizeLuma(y); } else { float y = {}; float u = {}; float v = {}; - converter.calcYUV(r,g,b, &y, &u, &v); + Converter::calcYUV(r,g,b, &y, &u, &v); *dstY = Quantizer::quantizeLuma(y); *dstU = Quantizer::quantizeChroma(u); *dstV = Quantizer::quantizeChroma(v); } } -template +template constexpr std::tuple::Type, typename avif::img::color::RGB::Type, typename avif::img::color::RGB::Type> calcRGB(typename avif::img::color::YUV::Type const* srcY, typename avif::img::color::YUV::Type const* srcU, typename avif::img::color::YUV::Type const* srcV) { using avif::img::color::clamp; using Quantizer = typename avif::img::color::Quantizer; using RGBSpec = typename avif::img::color::RGB; using YUVSpec = typename avif::img::color::YUV; - auto converter = ConverterFactory::create(); using RGBType = typename RGBSpec::Type; @@ -69,7 +67,7 @@ constexpr std::tuple::Type, typename avi auto const u = isMonoYUV ? 0.0f : Quantizer::dequantizeChroma(*srcU); auto const v = isMonoYUV ? 0.0f : Quantizer::dequantizeChroma(*srcV); - auto const [r, g, b] = converter.calcRGB(y, u, v); + auto const [r, g, b] = Converter::calcRGB(y, u, v); auto const ir = static_cast(clamp(static_cast(std::round(r * RGBSpec::max)), 0, RGBSpec::max)); auto const ig = static_cast(clamp(static_cast(std::round(g * RGBSpec::max)), 0, RGBSpec::max)); @@ -78,7 +76,7 @@ constexpr std::tuple::Type, typename avi } // MonochromeYUV version -template +template void constexpr convertFromRGB(size_t width, size_t height, uint8_t bytesPerPixel, uint8_t const* src, size_t const stride, uint8_t* const dstY, size_t const strideY) { using avif::img::color::clamp; using RGBSpec = typename avif::img::color::RGB; @@ -95,12 +93,12 @@ void constexpr convertFromRGB(size_t width, size_t height, uint8_t bytesPerPixel for (size_t x = 0; x < width; ++x) { if(fromMonoRGB) { uint16_t const mono = reinterpret_cast(ptr)[0]; - calcYUV(mono, mono, mono, &ptrY[x], nullptr, nullptr); + calcYUV(mono, mono, mono, &ptrY[x], nullptr, nullptr); } else { uint16_t const r = reinterpret_cast(ptr)[0]; uint16_t const g = reinterpret_cast(ptr)[1]; uint16_t const b = reinterpret_cast(ptr)[2]; - calcYUV(r, g, b, &ptrY[x], nullptr, nullptr); + calcYUV(r, g, b, &ptrY[x], nullptr, nullptr); } ptr += bytesPerPixel; } @@ -109,7 +107,7 @@ void constexpr convertFromRGB(size_t width, size_t height, uint8_t bytesPerPixel } } -template +template void constexpr convertFromRGB(size_t width, size_t height, uint8_t bytesPerPixel, uint8_t const* src, size_t const stride, uint8_t* const dstY, size_t const strideY, uint8_t* const dstU, size_t const strideU, uint8_t* const dstV, size_t const strideV) { using avif::img::color::clamp; using RGBSpec = typename avif::img::color::RGB; @@ -133,12 +131,12 @@ void constexpr convertFromRGB(size_t width, size_t height, uint8_t bytesPerPixel for (size_t x = 0; x < width; ++x) { if(fromMonoRGB) { uint16_t const mono = reinterpret_cast(ptr)[0]; - calcYUV(mono, mono, mono, &ptrY[x], sampler.pixelInLine(ptrU, x), sampler.pixelInLine(ptrV, x)); + calcYUV(mono, mono, mono, &ptrY[x], sampler.pixelInLine(ptrU, x), sampler.pixelInLine(ptrV, x)); } else { uint16_t const r = reinterpret_cast(ptr)[0]; uint16_t const g = reinterpret_cast(ptr)[1]; uint16_t const b = reinterpret_cast(ptr)[2]; - calcYUV(r, g, b, &ptrY[x], sampler.pixelInLine(ptrU, x), sampler.pixelInLine(ptrV, x)); + calcYUV(r, g, b, &ptrY[x], sampler.pixelInLine(ptrU, x), sampler.pixelInLine(ptrV, x)); } ptr += bytesPerPixel; } @@ -150,7 +148,7 @@ void constexpr convertFromRGB(size_t width, size_t height, uint8_t bytesPerPixel } // MonochromeYUV version -template +template void constexpr convertFromYUV(size_t width, size_t height, uint8_t bytesPerPixel, uint8_t* dst, size_t stride, uint8_t const* srcY, size_t strideY) { using RGBSpec = typename avif::img::color::RGB; using YUVSpec = typename avif::img::color::YUV; @@ -166,12 +164,12 @@ void constexpr convertFromYUV(size_t width, size_t height, uint8_t bytesPerPixel for (size_t x = 0; x < width; ++x) { if(toMonoRGB) { RGBType& mono = reinterpret_cast(ptr)[0]; - std::tie(mono, mono, mono) = calcRGB(&ptrY[x], nullptr, nullptr); + std::tie(mono, mono, mono) = calcRGB(&ptrY[x], nullptr, nullptr); } else { RGBType& r = reinterpret_cast(ptr)[0]; RGBType& g = reinterpret_cast(ptr)[1]; RGBType& b = reinterpret_cast(ptr)[2]; - std::tie(r,g,b) = calcRGB(&ptrY[x], nullptr, nullptr); + std::tie(r,g,b) = calcRGB(&ptrY[x], nullptr, nullptr); } ptr += bytesPerPixel; } @@ -180,7 +178,7 @@ void constexpr convertFromYUV(size_t width, size_t height, uint8_t bytesPerPixel } } -template +template void constexpr convertFromYUV(size_t width, size_t height, uint8_t bytesPerPixel, uint8_t* dst, size_t stride, uint8_t const* srcY, size_t strideY, uint8_t const* srcU, size_t strideU, uint8_t const* srcV, size_t strideV) { using RGBSpec = typename avif::img::color::RGB; using YUVSpec = typename avif::img::color::YUV; @@ -202,12 +200,12 @@ void constexpr convertFromYUV(size_t width, size_t height, uint8_t bytesPerPixel for (size_t x = 0; x < width; ++x) { if(toMonoRGB) { RGBType& mono = reinterpret_cast(ptr)[0]; - std::tie(mono, mono, mono) = calcRGB(&ptrY[x], sampler.pixelInLine(ptrU, x), sampler.pixelInLine(ptrV, x)); + std::tie(mono, mono, mono) = calcRGB(&ptrY[x], sampler.pixelInLine(ptrU, x), sampler.pixelInLine(ptrV, x)); } else { RGBType& r = reinterpret_cast(ptr)[0]; RGBType& g = reinterpret_cast(ptr)[1]; RGBType& b = reinterpret_cast(ptr)[2]; - std::tie(r,g,b) = calcRGB(&ptrY[x], sampler.pixelInLine(ptrU, x), sampler.pixelInLine(ptrV, x)); + std::tie(r,g,b) = calcRGB(&ptrY[x], sampler.pixelInLine(ptrU, x), sampler.pixelInLine(ptrV, x)); } ptr += bytesPerPixel; } @@ -220,29 +218,29 @@ void constexpr convertFromYUV(size_t width, size_t height, uint8_t bytesPerPixel } -template +template struct FromRGB final { static void toI400(Image& src, uint8_t* dstY, size_t strideY) { - detail::convertFromRGB(src.width(), src.height(), src.bytesPerPixel(), src.data(), src.stride(), dstY, strideY); + detail::convertFromRGB(src.width(), src.height(), src.bytesPerPixel(), src.data(), src.stride(), dstY, strideY); } static void toI444(Image const& src, uint8_t* dstY, size_t strideY, uint8_t* dstU, size_t strideU, uint8_t* dstV, size_t strideV) { - detail::convertFromRGB(src.width(), src.height(), src.bytesPerPixel(), src.data(), src.stride(), dstY, strideY, dstU, strideU, dstV, strideV); + detail::convertFromRGB(src.width(), src.height(), src.bytesPerPixel(), src.data(), src.stride(), dstY, strideY, dstU, strideU, dstV, strideV); } static void toI422(Image const& src, uint8_t* dstY, size_t strideY, uint8_t* dstU, size_t strideU, uint8_t* dstV, size_t strideV){ - detail::convertFromRGB(src.width(), src.height(), src.bytesPerPixel(), src.data(), src.stride(), dstY, strideY, dstU, strideU, dstV, strideV); + detail::convertFromRGB(src.width(), src.height(), src.bytesPerPixel(), src.data(), src.stride(), dstY, strideY, dstU, strideU, dstV, strideV); } static void toI420(Image const& src, uint8_t* dstY, size_t strideY, uint8_t* dstU, size_t strideU, uint8_t* dstV, size_t strideV){ - detail::convertFromRGB(src.width(), src.height(), src.bytesPerPixel(), src.data(), src.stride(), dstY, strideY, dstU, strideU, dstV, strideV); + detail::convertFromRGB(src.width(), src.height(), src.bytesPerPixel(), src.data(), src.stride(), dstY, strideY, dstU, strideU, dstV, strideV); } }; -template +template struct FromAlpha final { static void toI400(Image& src, uint8_t* dstY, size_t strideY) { switch(src.pixelOrder()) { case avif::img::PixelOrder::MonoA: case avif::img::PixelOrder::RGBA: - detail::convertFromRGB(src.width(), src.height(), src.bytesPerPixel(), src.data() + (src.numComponents() - 1) * src.bytesPerComponent(), src.stride(), dstY, strideY); + detail::convertFromRGB(src.width(), src.height(), src.bytesPerPixel(), src.data() + (src.numComponents() - 1) * src.bytesPerComponent(), src.stride(), dstY, strideY); break; case avif::img::PixelOrder::Mono: throw std::domain_error("Cannot separate Alpha from Mono image."); @@ -252,28 +250,28 @@ struct FromAlpha final { } }; -template +template struct ToRGB final { static void fromI400(Image& dst, uint8_t* srcY, size_t strideY) { - detail::convertFromYUV(dst.width(), dst.height(), dst.bytesPerPixel(), dst.data(), dst.stride(), srcY, strideY); + detail::convertFromYUV(dst.width(), dst.height(), dst.bytesPerPixel(), dst.data(), dst.stride(), srcY, strideY); } static void fromI444(Image& dst, uint8_t* srcY, size_t strideY, uint8_t* srcU, size_t strideU, uint8_t* srcV, size_t strideV) { - detail::convertFromYUV(dst.width(), dst.height(), dst.bytesPerPixel(), dst.data(), dst.stride(), srcY, strideY, srcU, strideU, srcV, strideV); + detail::convertFromYUV(dst.width(), dst.height(), dst.bytesPerPixel(), dst.data(), dst.stride(), srcY, strideY, srcU, strideU, srcV, strideV); } static void fromI422(Image& dst, uint8_t* srcY, size_t strideY, uint8_t* srcU, size_t strideU, uint8_t* srcV, size_t strideV){ - detail::convertFromYUV(dst.width(), dst.height(), dst.bytesPerPixel(), dst.data(), dst.stride(), srcY, strideY, srcU, strideU, srcV, strideV); + detail::convertFromYUV(dst.width(), dst.height(), dst.bytesPerPixel(), dst.data(), dst.stride(), srcY, strideY, srcU, strideU, srcV, strideV); } static void fromI420(Image& dst, uint8_t* srcY, size_t strideY, uint8_t* srcU, size_t strideU, uint8_t* srcV, size_t strideV){ - detail::convertFromYUV(dst.width(), dst.height(), dst.bytesPerPixel(), dst.data(), dst.stride(), srcY, strideY, srcU, strideU, srcV, strideV); + detail::convertFromYUV(dst.width(), dst.height(), dst.bytesPerPixel(), dst.data(), dst.stride(), srcY, strideY, srcU, strideU, srcV, strideV); } }; -template +template struct ToAlpha final { static void fromI400(Image& dst, uint8_t* srcY, size_t strideY) { switch(dst.pixelOrder()) { case avif::img::PixelOrder::MonoA: case avif::img::PixelOrder::RGBA: - detail::convertFromYUV(dst.width(), dst.height(), dst.bytesPerPixel(), dst.data() + (dst.numComponents() - 1) * dst.bytesPerComponent(), dst.stride(), srcY, strideY); + detail::convertFromYUV(dst.width(), dst.height(), dst.bytesPerPixel(), dst.data() + (dst.numComponents() - 1) * dst.bytesPerComponent(), dst.stride(), srcY, strideY); break; case avif::img::PixelOrder::Mono: throw std::domain_error("Cannot store Alpha to Mono image."); diff --git a/src/avif/img/color/Matrix.hpp b/src/avif/img/color/Matrix.hpp index 4f09849..0e7c9cc 100644 --- a/src/avif/img/color/Matrix.hpp +++ b/src/avif/img/color/Matrix.hpp @@ -16,9 +16,7 @@ namespace avif::img::color { -class IdentityConverter final { -public: - constexpr IdentityConverter() = default; +struct IdentityConverter { static constexpr void calcYUV(float r, float g, float b, float* y, float* u, float* v) { *y = g; if(u) { @@ -36,25 +34,17 @@ class IdentityConverter final { // // This class corresponds to eq (38)-(40) // -class PrimariesConverter final { -public: - PrimariesConverter() = delete; - constexpr PrimariesConverter(float const Kr, float const Kb) - :Kr(Kr) - ,Kb(Kb) - ,Kg(1.0f - Kr -Kb) - ,Cb_B(2.0f * (1.0f - Kb)) - ,Cb_G(-2.0f * (1.0f - Kb) * Kb / Kg) - ,Cr_R(2.0f * (1.0f - Kr)) - ,Cr_G(-2.0f * (1.0f - Kr) * Kr / Kg) - { - - } - const float Kr; - const float Kb; - const float Kg; - - constexpr void calcYUV(float const r, float const g, float const b, float* y, float* u, float* v) const { +template +struct PrimariesConverter { + static constexpr float Kr = Self::Kr; + static constexpr float Kb = Self::Kb; + static constexpr float Kg = (1.0f - Kr -Kb); + static constexpr float Cb_B = (2.0f * (1.0f - Kb)); + static constexpr float Cb_G = (-2.0f * (1.0f - Kb) * Kb / Kg); + static constexpr float Cr_R = (2.0f * (1.0f - Kr)); + static constexpr float Cr_G = (-2.0f * (1.0f - Kr) * Kr / Kg); + + static constexpr void calcYUV(float const r, float const g, float const b, float* y, float* u, float* v) { *y = Kr * r + Kg * g + Kb * b; if (u) { *u = 0.5f * (b - *y) / (1.0f - Kb); @@ -64,183 +54,122 @@ class PrimariesConverter final { } } - [[nodiscard]] constexpr std::tuple calcRGB(float const y, float const u, float const v) const { + [[nodiscard]] static constexpr std::tuple calcRGB(float const y, float const u, float const v) { float const r = y + Cr_R * v; float const g = y + Cb_G * u + Cr_G * v; float const b = y + Cb_B * u; return std::make_tuple(r, g, b); } - -private: - const float Cb_B; - const float Cb_G; - - const float Cr_R; - const float Cr_G; }; -class ReservedConverter final { -public: - ReservedConverter() = delete; - explicit constexpr ReservedConverter(MatrixCoefficients mat) - :mat_(mat) { +template +struct ReservedConverter { + static void calcYUV(float /* r */, float /* g */, float /* b */, float* /* y */, float* /* u */, float* /* v */) { + throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} is reserved for future ues by ISO/IEC.", static_cast(mat))); } - void calcYUV(float /* r */, float /* g */, float /* b */, float* /* y */, float* /* u */, float* /* v */) const { - throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} is reserved for future ues by ISO/IEC.", static_cast(mat_))); - } - [[nodiscard]] std::tuple calcRGB(float /* y */, float /* u */, float /* v */) const { - throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} is reserved for future ues by ISO/IEC.", static_cast(mat_))); + [[nodiscard]] static std::tuple calcRGB(float /* y */, float /* u */, float /* v */) { + throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} is reserved for future ues by ISO/IEC.", static_cast(mat))); } - -private: - const MatrixCoefficients mat_; }; // Unspecified -class UnspecifiedConverter final { -public: - UnspecifiedConverter() = delete; - explicit constexpr UnspecifiedConverter(MatrixCoefficients mat) - :mat_(mat) { +template +struct UnspecifiedConverter { + static void calcYUV(float /* r */, float /* g */, float /* b */, float* /* y */, float* /* u */, float* /* v */) { + throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} means 'unspecified'.", static_cast(mat))); } - void calcYUV(float /* r */, float /* g */, float /* b */, float* /* y */, float* /* u */, float* /* v */) const { - throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} means 'unspecified'.", static_cast(mat_))); + [[nodiscard]] static std::tuple calcRGB(float /* y */, float /* u */, float /* v */) { + throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} means 'unspecified'.", static_cast(mat))); } - [[nodiscard]] std::tuple calcRGB(float /* y */, float /* u */, float /* v */) const { - throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} means 'unspecified'.", static_cast(mat_))); - } - -private: - const MatrixCoefficients mat_; }; // Fallback -class UnimplementedConverter final { -public: - UnimplementedConverter() = delete; - explicit constexpr UnimplementedConverter(MatrixCoefficients mat) - :mat_(mat) { +template +struct UnimplementedConverter { + static void calcYUV(float /* r */, float /* g */, float /* b */, float* /* y */, float* /* u */, float* /* v */) { + throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} is not implemented yet.", static_cast(mat))); } - void calcYUV(float /* r */, float /* g */, float /* b */, float* /* y */, float* /* u */, float* /* v */) const { - throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} is not implemented yet.", static_cast(mat_))); + [[nodiscard]] static std::tuple calcRGB(float /* y */, float /* u */, float /* v */) { + throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} is not implemented yet.", static_cast(mat))); } - [[nodiscard]] std::tuple calcRGB(float /* y */, float /* u */, float /* v */) const { - throw std::logic_error(fmt::format("[TODO] MatrixCoefficients = {} is not implemented yet.", static_cast(mat_))); - } - -private: - const MatrixCoefficients mat_; }; /* * ConverterFactory. It returns different struct according to MatrixCoefficients. */ -// Generally, it is reserved. -template -struct ConverterFactory { - static constexpr auto create() { - return ReservedConverter(code); - } +// Generally, it is unimplemented. +template +struct ColorConverter final: public UnimplementedConverter { }; -template <> -struct ConverterFactory { - static constexpr auto create() { - return IdentityConverter(); - } +template<> +struct ColorConverter final: public IdentityConverter { }; template <> -struct ConverterFactory { - static constexpr auto create() { - return PrimariesConverter(0.2126f, 0.0722f); - } +struct ColorConverter final : public PrimariesConverter> { + static constexpr float Kr = 0.2126f; + static constexpr float Kb = 0.0722f; }; template <> -struct ConverterFactory { - static constexpr auto create() { - return ReservedConverter(MatrixCoefficients::MC_RESERVED_3); - } +struct ColorConverter final : public ReservedConverter { }; template <> -struct ConverterFactory { - static constexpr auto create() { - return PrimariesConverter(0.30f, 0.11f); - } +struct ColorConverter : public PrimariesConverter> { + static constexpr float Kr = 0.30f; + static constexpr float Kb = 0.11f; }; template <> -struct ConverterFactory { - static constexpr auto create() { - return PrimariesConverter(0.299f, 0.114f); - } +struct ColorConverter : public PrimariesConverter> { + static constexpr float Kr = 0.299f; + static constexpr float Kb = 0.114f; }; template <> -struct ConverterFactory { - static constexpr auto create() { - return PrimariesConverter(0.299f, 0.114f); - } +struct ColorConverter : public PrimariesConverter> { + static constexpr float Kr = 0.299f; + static constexpr float Kb = 0.114f; }; template <> -struct ConverterFactory { - static constexpr auto create() { - return PrimariesConverter(0.212f, 0.087f); - } +struct ColorConverter : public PrimariesConverter> { + static constexpr float Kr = 0.212f; + static constexpr float Kb = 0.087f; }; template <> -struct ConverterFactory { - static constexpr auto create() { - return UnimplementedConverter(MatrixCoefficients::MC_SMPTE_YCGCO); - } +struct ColorConverter : public UnimplementedConverter { }; template <> -struct ConverterFactory { - static constexpr auto create() { - return PrimariesConverter(0.2627f, 0.0593f); - } +struct ColorConverter : public PrimariesConverter> { + static constexpr float Kr = 0.2627f; + static constexpr float Kb = 0.0593f; }; template <> -struct ConverterFactory { - static constexpr auto create() { - return UnimplementedConverter(MatrixCoefficients::MC_SMPTE_YCGCO); - } +struct ColorConverter : public UnimplementedConverter { }; template <> -struct ConverterFactory { - static constexpr auto create() { - return UnimplementedConverter(MatrixCoefficients::MC_SMPTE_2085); - } +struct ColorConverter : public UnimplementedConverter { }; template <> -struct ConverterFactory { - static constexpr auto create() { - return UnimplementedConverter(MatrixCoefficients::MC_CHROMAT_NCL); - } +struct ColorConverter : public UnimplementedConverter { }; template <> -struct ConverterFactory { - static constexpr auto create() { - return UnimplementedConverter(MatrixCoefficients::MC_CHROMAT_CL); - } +struct ColorConverter : public UnimplementedConverter { }; template <> -struct ConverterFactory { - static constexpr auto create() { - return UnimplementedConverter(MatrixCoefficients::MC_BT_2100_ICTCP); - } +struct ColorConverter : public UnimplementedConverter { }; }