summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc')
-rw-r--r--third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc106
1 files changed, 61 insertions, 45 deletions
diff --git a/third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc b/third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc
index 0abd177809..f19ba0dd9e 100644
--- a/third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc
+++ b/third_party/jpeg-xl/lib/jxl/enc_patch_dictionary.cc
@@ -5,24 +5,22 @@
#include "lib/jxl/enc_patch_dictionary.h"
+#include <jxl/types.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <algorithm>
#include <atomic>
-#include <string>
-#include <tuple>
#include <utility>
#include <vector>
-#include "lib/jxl/ans_params.h"
#include "lib/jxl/base/common.h"
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/override.h"
+#include "lib/jxl/base/printf_macros.h"
#include "lib/jxl/base/random.h"
#include "lib/jxl/base/status.h"
-#include "lib/jxl/chroma_from_luma.h"
#include "lib/jxl/dec_cache.h"
#include "lib/jxl/dec_frame.h"
#include "lib/jxl/enc_ans.h"
@@ -31,7 +29,6 @@
#include "lib/jxl/enc_debug_image.h"
#include "lib/jxl/enc_dot_dictionary.h"
#include "lib/jxl/enc_frame.h"
-#include "lib/jxl/entropy_coder.h"
#include "lib/jxl/frame_header.h"
#include "lib/jxl/image.h"
#include "lib/jxl/image_bundle.h"
@@ -100,7 +97,7 @@ void PatchDictionaryEncoder::Encode(const PatchDictionary& pdic,
add_num(kPatchAlphaChannelContext, info.alpha_channel);
}
if (UsesClamp(info.mode)) {
- add_num(kPatchClampContext, info.clamp);
+ add_num(kPatchClampContext, TO_JXL_BOOL(info.clamp));
}
}
}
@@ -159,7 +156,7 @@ void PatchDictionaryEncoder::SubtractFrom(const PatchDictionary& pdic,
// Nothing to do.
} else {
JXL_UNREACHABLE("Blending mode %u not yet implemented",
- (uint32_t)mode);
+ static_cast<uint32_t>(mode));
}
}
}
@@ -208,11 +205,12 @@ struct PatchColorspaceInfo {
}
};
-std::vector<PatchInfo> FindTextLikePatches(
+StatusOr<std::vector<PatchInfo>> FindTextLikePatches(
const CompressParams& cparams, const Image3F& opsin,
const PassesEncoderState* JXL_RESTRICT state, ThreadPool* pool,
AuxOut* aux_out, bool is_xyb) {
- if (state->cparams.patches == Override::kOff) return {};
+ std::vector<PatchInfo> info;
+ if (state->cparams.patches == Override::kOff) return info;
const auto& frame_dim = state->shared.frame_dim;
PatchColorspaceInfo pci(is_xyb);
@@ -222,7 +220,8 @@ std::vector<PatchInfo> FindTextLikePatches(
std::pair<uint32_t, uint32_t> p2,
const float* JXL_RESTRICT rows[3],
size_t stride, float threshold) {
- float v1[3], v2[3];
+ float v1[3];
+ float v2[3];
for (size_t c = 0; c < 3; c++) {
v1[c] = rows[c][p1.second * stride + p1.first];
v2[c] = rows[c][p2.second * stride + p2.first];
@@ -258,8 +257,9 @@ std::vector<PatchInfo> FindTextLikePatches(
// Look for kPatchSide size squares, naturally aligned, that all have the same
// pixel values.
- ImageB is_screenshot_like(DivCeil(frame_dim.xsize, kPatchSide),
- DivCeil(frame_dim.ysize, kPatchSide));
+ JXL_ASSIGN_OR_RETURN(ImageB is_screenshot_like,
+ ImageB::Create(DivCeil(frame_dim.xsize, kPatchSide),
+ DivCeil(frame_dim.ysize, kPatchSide)));
ZeroFillImage(&is_screenshot_like);
uint8_t* JXL_RESTRICT screenshot_row = is_screenshot_like.Row(0);
const size_t screenshot_stride = is_screenshot_like.PixelsPerRow();
@@ -302,19 +302,22 @@ std::vector<PatchInfo> FindTextLikePatches(
// TODO(veluca): also parallelize the rest of this function.
if (WantDebugOutput(cparams)) {
- DumpPlaneNormalized(cparams, "screenshot_like", is_screenshot_like);
+ JXL_RETURN_IF_ERROR(
+ DumpPlaneNormalized(cparams, "screenshot_like", is_screenshot_like));
}
constexpr int kSearchRadius = 1;
if (!ApplyOverride(state->cparams.patches, has_screenshot_areas)) {
- return {};
+ return info;
}
// Search for "similar enough" pixels near the screenshot-like areas.
- ImageB is_background(frame_dim.xsize, frame_dim.ysize);
+ JXL_ASSIGN_OR_RETURN(ImageB is_background,
+ ImageB::Create(frame_dim.xsize, frame_dim.ysize));
ZeroFillImage(&is_background);
- Image3F background(frame_dim.xsize, frame_dim.ysize);
+ JXL_ASSIGN_OR_RETURN(Image3F background,
+ Image3F::Create(frame_dim.xsize, frame_dim.ysize));
ZeroFillImage(&background);
constexpr size_t kDistanceLimit = 50;
float* JXL_RESTRICT background_rows[3] = {
@@ -383,13 +386,14 @@ std::vector<PatchInfo> FindTextLikePatches(
Rng rng(0);
bool paint_ccs = false;
if (WantDebugOutput(cparams)) {
- DumpPlaneNormalized(cparams, "is_background", is_background);
+ JXL_RETURN_IF_ERROR(
+ DumpPlaneNormalized(cparams, "is_background", is_background));
if (is_xyb) {
- DumpXybImage(cparams, "background", background);
+ JXL_RETURN_IF_ERROR(DumpXybImage(cparams, "background", background));
} else {
- DumpImage(cparams, "background", background);
+ JXL_RETURN_IF_ERROR(DumpImage(cparams, "background", background));
}
- ccs = ImageF(frame_dim.xsize, frame_dim.ysize);
+ JXL_ASSIGN_OR_RETURN(ccs, ImageF::Create(frame_dim.xsize, frame_dim.ysize));
ZeroFillImage(&ccs);
paint_ccs = true;
}
@@ -407,11 +411,10 @@ std::vector<PatchInfo> FindTextLikePatches(
constexpr int kMinPeak = 2;
constexpr int kHasSimilarRadius = 2;
- std::vector<PatchInfo> info;
-
// Find small CC outside the "similar enough" areas, compute bounding boxes,
// and run heuristics to exclude some patches.
- ImageB visited(frame_dim.xsize, frame_dim.ysize);
+ JXL_ASSIGN_OR_RETURN(ImageB visited,
+ ImageB::Create(frame_dim.xsize, frame_dim.ysize));
ZeroFillImage(&visited);
uint8_t* JXL_RESTRICT visited_row = visited.Row(0);
const size_t visited_stride = visited.PixelsPerRow();
@@ -525,10 +528,10 @@ std::vector<PatchInfo> FindTextLikePatches(
if (paint_ccs) {
JXL_ASSERT(WantDebugOutput(cparams));
- DumpPlaneNormalized(cparams, "ccs", ccs);
+ JXL_RETURN_IF_ERROR(DumpPlaneNormalized(cparams, "ccs", ccs));
}
if (info.empty()) {
- return {};
+ return info;
}
// Remove duplicates.
@@ -560,19 +563,22 @@ std::vector<PatchInfo> FindTextLikePatches(
// don't use patches if all patches are smaller than this
constexpr size_t kMinMaxPatchSize = 20;
- if (max_patch_size < kMinMaxPatchSize) return {};
+ if (max_patch_size < kMinMaxPatchSize) {
+ info.clear();
+ }
return info;
}
} // namespace
-void FindBestPatchDictionary(const Image3F& opsin,
- PassesEncoderState* JXL_RESTRICT state,
- const JxlCmsInterface& cms, ThreadPool* pool,
- AuxOut* aux_out, bool is_xyb) {
- std::vector<PatchInfo> info =
- FindTextLikePatches(state->cparams, opsin, state, pool, aux_out, is_xyb);
+Status FindBestPatchDictionary(const Image3F& opsin,
+ PassesEncoderState* JXL_RESTRICT state,
+ const JxlCmsInterface& cms, ThreadPool* pool,
+ AuxOut* aux_out, bool is_xyb) {
+ JXL_ASSIGN_OR_RETURN(
+ std::vector<PatchInfo> info,
+ FindTextLikePatches(state->cparams, opsin, state, pool, aux_out, is_xyb));
// TODO(veluca): this doesn't work if both dots and patches are enabled.
// For now, since dots and patches are not likely to occur in the same kind of
@@ -582,10 +588,13 @@ void FindBestPatchDictionary(const Image3F& opsin,
state->cparams.dots,
state->cparams.speed_tier <= SpeedTier::kSquirrel &&
state->cparams.butteraugli_distance >= kMinButteraugliForDots)) {
- info = FindDotDictionary(state->cparams, opsin, state->shared.cmap, pool);
+ Rect rect(0, 0, state->shared.frame_dim.xsize,
+ state->shared.frame_dim.ysize);
+ JXL_ASSIGN_OR_RETURN(info, FindDotDictionary(state->cparams, opsin, rect,
+ state->shared.cmap, pool));
}
- if (info.empty()) return;
+ if (info.empty()) return true;
std::sort(
info.begin(), info.end(), [&](const PatchInfo& a, const PatchInfo& b) {
@@ -616,7 +625,7 @@ void FindBestPatchDictionary(const Image3F& opsin,
ref_xsize = ref_xsize * kBinPackingSlackness + 1;
ref_ysize = ref_ysize * kBinPackingSlackness + 1;
- ImageB occupied(ref_xsize, ref_ysize);
+ JXL_ASSIGN_OR_RETURN(ImageB occupied, ImageB::Create(ref_xsize, ref_ysize));
ZeroFillImage(&occupied);
uint8_t* JXL_RESTRICT occupied_rows = occupied.Row(0);
size_t occupied_stride = occupied.PixelsPerRow();
@@ -667,7 +676,7 @@ void FindBestPatchDictionary(const Image3F& opsin,
ref_positions[patch] = {x0, y0};
for (size_t y = y0; y < y0 + ysize; y++) {
for (size_t x = x0; x < x0 + xsize; x++) {
- occupied_rows[y * occupied_stride + x] = true;
+ occupied_rows[y * occupied_stride + x] = JXL_TRUE;
}
}
max_y = std::max(max_y, y0 + ysize);
@@ -680,7 +689,8 @@ void FindBestPatchDictionary(const Image3F& opsin,
ref_ysize = max_y;
- Image3F reference_frame(ref_xsize, ref_ysize);
+ JXL_ASSIGN_OR_RETURN(Image3F reference_frame,
+ Image3F::Create(ref_xsize, ref_ysize));
// TODO(veluca): figure out a better way to fill the image.
ZeroFillImage(&reference_frame);
std::vector<PatchPosition> positions;
@@ -710,6 +720,8 @@ void FindBestPatchDictionary(const Image3F& opsin,
}
}
for (const auto& pos : info[i].second) {
+ JXL_DEBUG_V(4, "Patch %" PRIuS "x%" PRIuS " at position %u,%u",
+ ref_pos.xsize, ref_pos.ysize, pos.first, pos.second);
positions.emplace_back(
PatchPosition{pos.first, pos.second, pref_positions.size()});
// Add blending for color channels, ignore other channels.
@@ -718,15 +730,16 @@ void FindBestPatchDictionary(const Image3F& opsin,
blendings.push_back({PatchBlendMode::kNone, 0, false});
}
}
- pref_positions.emplace_back(std::move(ref_pos));
+ pref_positions.emplace_back(ref_pos);
}
CompressParams cparams = state->cparams;
// Recursive application of patches could create very weird issues.
cparams.patches = Override::kOff;
- RoundtripPatchFrame(&reference_frame, state, kPatchFrameReferenceId, cparams,
- cms, pool, aux_out, /*subtract=*/true);
+ JXL_RETURN_IF_ERROR(RoundtripPatchFrame(&reference_frame, state,
+ kPatchFrameReferenceId, cparams, cms,
+ pool, aux_out, /*subtract=*/true));
// TODO(veluca): this assumes that applying patches is commutative, which is
// not true for all blending modes. This code only produces kAdd patches, so
@@ -734,12 +747,13 @@ void FindBestPatchDictionary(const Image3F& opsin,
PatchDictionaryEncoder::SetPositions(
&state->shared.image_features.patches, std::move(positions),
std::move(pref_positions), std::move(blendings));
+ return true;
}
-void RoundtripPatchFrame(Image3F* reference_frame,
- PassesEncoderState* JXL_RESTRICT state, int idx,
- CompressParams& cparams, const JxlCmsInterface& cms,
- ThreadPool* pool, AuxOut* aux_out, bool subtract) {
+Status RoundtripPatchFrame(Image3F* reference_frame,
+ PassesEncoderState* JXL_RESTRICT state, int idx,
+ CompressParams& cparams, const JxlCmsInterface& cms,
+ ThreadPool* pool, AuxOut* aux_out, bool subtract) {
FrameInfo patch_frame_info;
cparams.resampling = 1;
cparams.ec_resampling = 1;
@@ -768,7 +782,8 @@ void RoundtripPatchFrame(Image3F* reference_frame,
std::vector<ImageF> extra_channels;
extra_channels.reserve(ib.metadata()->extra_channel_info.size());
for (size_t i = 0; i < ib.metadata()->extra_channel_info.size(); i++) {
- extra_channels.emplace_back(ib.xsize(), ib.ysize());
+ JXL_ASSIGN_OR_RETURN(ImageF ch, ImageF::Create(ib.xsize(), ib.ysize()));
+ extra_channels.emplace_back(std::move(ch));
// Must initialize the image with data to not affect blending with
// uninitialized memory.
// TODO(lode): patches must copy and use the real extra channels instead.
@@ -814,6 +829,7 @@ void RoundtripPatchFrame(Image3F* reference_frame,
} else {
state->shared.reference_frames[idx].frame = std::move(ib);
}
+ return true;
}
} // namespace jxl