summaryrefslogtreecommitdiff
path: root/media/libjxl/src/lib/jxl/headers.cc
diff options
context:
space:
mode:
Diffstat (limited to 'media/libjxl/src/lib/jxl/headers.cc')
-rw-r--r--media/libjxl/src/lib/jxl/headers.cc214
1 files changed, 214 insertions, 0 deletions
diff --git a/media/libjxl/src/lib/jxl/headers.cc b/media/libjxl/src/lib/jxl/headers.cc
new file mode 100644
index 0000000000..7add681e1a
--- /dev/null
+++ b/media/libjxl/src/lib/jxl/headers.cc
@@ -0,0 +1,214 @@
+// Copyright (c) the JPEG XL Project Authors. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "lib/jxl/headers.h"
+
+#include "lib/jxl/base/printf_macros.h"
+#include "lib/jxl/common.h"
+#include "lib/jxl/fields.h"
+
+namespace jxl {
+namespace {
+
+struct Rational {
+ constexpr explicit Rational(uint32_t num, uint32_t den)
+ : num(num), den(den) {}
+
+ // Returns floor(multiplicand * rational).
+ constexpr uint32_t MulTruncate(uint32_t multiplicand) const {
+ return uint64_t(multiplicand) * num / den;
+ }
+
+ uint32_t num;
+ uint32_t den;
+};
+
+Rational FixedAspectRatios(uint32_t ratio) {
+ JXL_ASSERT(0 != ratio && ratio < 8);
+ // Other candidates: 5/4, 7/5, 14/9, 16/10, 5/3, 21/9, 12/5
+ constexpr Rational kRatios[7] = {Rational(1, 1), // square
+ Rational(12, 10), //
+ Rational(4, 3), // camera
+ Rational(3, 2), // mobile camera
+ Rational(16, 9), // camera/display
+ Rational(5, 4), //
+ Rational(2, 1)}; //
+ return kRatios[ratio - 1];
+}
+
+uint32_t FindAspectRatio(uint32_t xsize, uint32_t ysize) {
+ for (uint32_t r = 1; r < 8; ++r) {
+ if (xsize == FixedAspectRatios(r).MulTruncate(ysize)) {
+ return r;
+ }
+ }
+ return 0; // Must send xsize instead
+}
+
+} // namespace
+
+size_t SizeHeader::xsize() const {
+ if (ratio_ != 0) {
+ return FixedAspectRatios(ratio_).MulTruncate(
+ static_cast<uint32_t>(ysize()));
+ }
+ return small_ ? ((xsize_div8_minus_1_ + 1) * 8) : xsize_;
+}
+
+Status SizeHeader::Set(size_t xsize64, size_t ysize64) {
+ if (xsize64 > 0xFFFFFFFFull || ysize64 > 0xFFFFFFFFull) {
+ return JXL_FAILURE("Image too large");
+ }
+ const uint32_t xsize32 = static_cast<uint32_t>(xsize64);
+ const uint32_t ysize32 = static_cast<uint32_t>(ysize64);
+ if (xsize64 == 0 || ysize64 == 0) return JXL_FAILURE("Empty image");
+ ratio_ = FindAspectRatio(xsize32, ysize32);
+ small_ = ysize64 <= 256 && (ysize64 % kBlockDim) == 0 &&
+ (ratio_ != 0 || (xsize64 <= 256 && (xsize64 % kBlockDim) == 0));
+ if (small_) {
+ ysize_div8_minus_1_ = ysize32 / 8 - 1;
+ } else {
+ ysize_ = ysize32;
+ }
+
+ if (ratio_ == 0) {
+ if (small_) {
+ xsize_div8_minus_1_ = xsize32 / 8 - 1;
+ } else {
+ xsize_ = xsize32;
+ }
+ }
+ JXL_ASSERT(xsize() == xsize64);
+ JXL_ASSERT(ysize() == ysize64);
+ return true;
+}
+
+Status PreviewHeader::Set(size_t xsize64, size_t ysize64) {
+ const uint32_t xsize32 = static_cast<uint32_t>(xsize64);
+ const uint32_t ysize32 = static_cast<uint32_t>(ysize64);
+ if (xsize64 == 0 || ysize64 == 0) return JXL_FAILURE("Empty preview");
+ div8_ = (xsize64 % kBlockDim) == 0 && (ysize64 % kBlockDim) == 0;
+ if (div8_) {
+ ysize_div8_ = ysize32 / 8;
+ } else {
+ ysize_ = ysize32;
+ }
+
+ ratio_ = FindAspectRatio(xsize32, ysize32);
+ if (ratio_ == 0) {
+ if (div8_) {
+ xsize_div8_ = xsize32 / 8;
+ } else {
+ xsize_ = xsize32;
+ }
+ }
+ JXL_ASSERT(xsize() == xsize64);
+ JXL_ASSERT(ysize() == ysize64);
+ return true;
+}
+
+size_t PreviewHeader::xsize() const {
+ if (ratio_ != 0) {
+ return FixedAspectRatios(ratio_).MulTruncate(
+ static_cast<uint32_t>(ysize()));
+ }
+ return div8_ ? (xsize_div8_ * 8) : xsize_;
+}
+
+SizeHeader::SizeHeader() { Bundle::Init(this); }
+Status SizeHeader::VisitFields(Visitor* JXL_RESTRICT visitor) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &small_));
+
+ if (visitor->Conditional(small_)) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, 0, &ysize_div8_minus_1_));
+ }
+ if (visitor->Conditional(!small_)) {
+ // (Could still be small, but non-multiple of 8.)
+ JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(9, 1), BitsOffset(13, 1),
+ BitsOffset(18, 1), BitsOffset(30, 1),
+ 1, &ysize_));
+ }
+
+ JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &ratio_));
+ if (visitor->Conditional(ratio_ == 0 && small_)) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, 0, &xsize_div8_minus_1_));
+ }
+ if (visitor->Conditional(ratio_ == 0 && !small_)) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(9, 1), BitsOffset(13, 1),
+ BitsOffset(18, 1), BitsOffset(30, 1),
+ 1, &xsize_));
+ }
+
+ return true;
+}
+
+PreviewHeader::PreviewHeader() { Bundle::Init(this); }
+Status PreviewHeader::VisitFields(Visitor* JXL_RESTRICT visitor) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &div8_));
+
+ if (visitor->Conditional(div8_)) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(16), Val(32), BitsOffset(5, 1),
+ BitsOffset(9, 33), 1, &ysize_div8_));
+ }
+ if (visitor->Conditional(!div8_)) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(6, 1), BitsOffset(8, 65),
+ BitsOffset(10, 321),
+ BitsOffset(12, 1345), 1, &ysize_));
+ }
+
+ JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &ratio_));
+ if (visitor->Conditional(ratio_ == 0 && div8_)) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(16), Val(32), BitsOffset(5, 1),
+ BitsOffset(9, 33), 1, &xsize_div8_));
+ }
+ if (visitor->Conditional(ratio_ == 0 && !div8_)) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(6, 1), BitsOffset(8, 65),
+ BitsOffset(10, 321),
+ BitsOffset(12, 1345), 1, &xsize_));
+ }
+
+ return true;
+}
+
+AnimationHeader::AnimationHeader() { Bundle::Init(this); }
+Status AnimationHeader::VisitFields(Visitor* JXL_RESTRICT visitor) {
+ JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(100), Val(1000), BitsOffset(10, 1),
+ BitsOffset(30, 1), 1, &tps_numerator));
+ JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(1), Val(1001), BitsOffset(8, 1),
+ BitsOffset(10, 1), 1,
+ &tps_denominator));
+
+ JXL_QUIET_RETURN_IF_ERROR(
+ visitor->U32(Val(0), Bits(3), Bits(16), Bits(32), 0, &num_loops));
+
+ JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &have_timecodes));
+ return true;
+}
+
+Status ReadSizeHeader(BitReader* JXL_RESTRICT reader,
+ SizeHeader* JXL_RESTRICT size) {
+ return Bundle::Read(reader, size);
+}
+
+Status WriteSizeHeader(const SizeHeader& size, BitWriter* JXL_RESTRICT writer,
+ size_t layer, AuxOut* aux_out) {
+ const size_t max_bits = Bundle::MaxBits(size);
+ if (max_bits != SizeHeader::kMaxBits) {
+ JXL_ABORT("Please update SizeHeader::kMaxBits from %" PRIuS " to %" PRIuS
+ "\n",
+ SizeHeader::kMaxBits, max_bits);
+ }
+
+ // Only check the number of non-extension bits (extensions are unbounded).
+ // (Bundle::Write will call CanEncode again, but it is fast because SizeHeader
+ // is tiny.)
+ size_t extension_bits, total_bits;
+ JXL_RETURN_IF_ERROR(Bundle::CanEncode(size, &extension_bits, &total_bits));
+ JXL_ASSERT(total_bits - extension_bits < SizeHeader::kMaxBits);
+
+ return Bundle::Write(size, writer, layer, aux_out);
+}
+
+} // namespace jxl