diff options
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.cc | 106 |
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 |