libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

dec_cache.cc (10183B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #include "lib/jxl/dec_cache.h"
      7 
      8 #include "lib/jxl/base/status.h"
      9 #include "lib/jxl/blending.h"
     10 #include "lib/jxl/common.h"  // JXL_HIGH_PRECISION
     11 #include "lib/jxl/render_pipeline/stage_blending.h"
     12 #include "lib/jxl/render_pipeline/stage_chroma_upsampling.h"
     13 #include "lib/jxl/render_pipeline/stage_cms.h"
     14 #include "lib/jxl/render_pipeline/stage_epf.h"
     15 #include "lib/jxl/render_pipeline/stage_from_linear.h"
     16 #include "lib/jxl/render_pipeline/stage_gaborish.h"
     17 #include "lib/jxl/render_pipeline/stage_noise.h"
     18 #include "lib/jxl/render_pipeline/stage_patches.h"
     19 #include "lib/jxl/render_pipeline/stage_splines.h"
     20 #include "lib/jxl/render_pipeline/stage_spot.h"
     21 #include "lib/jxl/render_pipeline/stage_to_linear.h"
     22 #include "lib/jxl/render_pipeline/stage_tone_mapping.h"
     23 #include "lib/jxl/render_pipeline/stage_upsampling.h"
     24 #include "lib/jxl/render_pipeline/stage_write.h"
     25 #include "lib/jxl/render_pipeline/stage_xyb.h"
     26 #include "lib/jxl/render_pipeline/stage_ycbcr.h"
     27 
     28 namespace jxl {
     29 
     30 Status PassesDecoderState::PreparePipeline(const FrameHeader& frame_header,
     31                                            ImageBundle* decoded,
     32                                            PipelineOptions options) {
     33   size_t num_c = 3 + frame_header.nonserialized_metadata->m.num_extra_channels;
     34   if (options.render_noise && (frame_header.flags & FrameHeader::kNoise) != 0) {
     35     num_c += 3;
     36   }
     37 
     38   if (frame_header.CanBeReferenced()) {
     39     // Necessary so that SetInputSizes() can allocate output buffers as needed.
     40     frame_storage_for_referencing = ImageBundle(decoded->metadata());
     41   }
     42 
     43   RenderPipeline::Builder builder(num_c);
     44 
     45   if (options.use_slow_render_pipeline) {
     46     builder.UseSimpleImplementation();
     47   }
     48 
     49   if (!frame_header.chroma_subsampling.Is444()) {
     50     for (size_t c = 0; c < 3; c++) {
     51       if (frame_header.chroma_subsampling.HShift(c) != 0) {
     52         builder.AddStage(GetChromaUpsamplingStage(c, /*horizontal=*/true));
     53       }
     54       if (frame_header.chroma_subsampling.VShift(c) != 0) {
     55         builder.AddStage(GetChromaUpsamplingStage(c, /*horizontal=*/false));
     56       }
     57     }
     58   }
     59 
     60   if (frame_header.loop_filter.gab) {
     61     builder.AddStage(GetGaborishStage(frame_header.loop_filter));
     62   }
     63 
     64   {
     65     const LoopFilter& lf = frame_header.loop_filter;
     66     if (lf.epf_iters >= 3) {
     67       builder.AddStage(GetEPFStage(lf, sigma, 0));
     68     }
     69     if (lf.epf_iters >= 1) {
     70       builder.AddStage(GetEPFStage(lf, sigma, 1));
     71     }
     72     if (lf.epf_iters >= 2) {
     73       builder.AddStage(GetEPFStage(lf, sigma, 2));
     74     }
     75   }
     76 
     77   bool late_ec_upsample = frame_header.upsampling != 1;
     78   for (auto ecups : frame_header.extra_channel_upsampling) {
     79     if (ecups != frame_header.upsampling) {
     80       // If patches are applied, either frame_header.upsampling == 1 or
     81       // late_ec_upsample is true.
     82       late_ec_upsample = false;
     83     }
     84   }
     85 
     86   if (!late_ec_upsample) {
     87     for (size_t ec = 0; ec < frame_header.extra_channel_upsampling.size();
     88          ec++) {
     89       if (frame_header.extra_channel_upsampling[ec] != 1) {
     90         builder.AddStage(GetUpsamplingStage(
     91             frame_header.nonserialized_metadata->transform_data, 3 + ec,
     92             CeilLog2Nonzero(frame_header.extra_channel_upsampling[ec])));
     93       }
     94     }
     95   }
     96 
     97   if ((frame_header.flags & FrameHeader::kPatches) != 0) {
     98     builder.AddStage(
     99         GetPatchesStage(&shared->image_features.patches,
    100                         3 + shared->metadata->m.num_extra_channels));
    101   }
    102   if ((frame_header.flags & FrameHeader::kSplines) != 0) {
    103     builder.AddStage(GetSplineStage(&shared->image_features.splines));
    104   }
    105 
    106   if (frame_header.upsampling != 1) {
    107     size_t nb_channels =
    108         3 +
    109         (late_ec_upsample ? frame_header.extra_channel_upsampling.size() : 0);
    110     for (size_t c = 0; c < nb_channels; c++) {
    111       builder.AddStage(GetUpsamplingStage(
    112           frame_header.nonserialized_metadata->transform_data, c,
    113           CeilLog2Nonzero(frame_header.upsampling)));
    114     }
    115   }
    116   if (options.render_noise && (frame_header.flags & FrameHeader::kNoise) != 0) {
    117     builder.AddStage(GetConvolveNoiseStage(num_c - 3));
    118     builder.AddStage(GetAddNoiseStage(shared->image_features.noise_params,
    119                                       shared->cmap, num_c - 3));
    120   }
    121   if (frame_header.dc_level != 0) {
    122     builder.AddStage(GetWriteToImage3FStage(
    123         &shared_storage.dc_frames[frame_header.dc_level - 1]));
    124   }
    125 
    126   if (frame_header.CanBeReferenced() &&
    127       frame_header.save_before_color_transform) {
    128     builder.AddStage(GetWriteToImageBundleStage(
    129         &frame_storage_for_referencing, output_encoding_info.color_encoding));
    130   }
    131 
    132   bool has_alpha = false;
    133   size_t alpha_c = 0;
    134   for (size_t i = 0; i < decoded->metadata()->extra_channel_info.size(); i++) {
    135     if (decoded->metadata()->extra_channel_info[i].type ==
    136         ExtraChannel::kAlpha) {
    137       has_alpha = true;
    138       alpha_c = 3 + i;
    139       break;
    140     }
    141   }
    142 
    143   if (fast_xyb_srgb8_conversion) {
    144 #if !JXL_HIGH_PRECISION
    145     JXL_ASSERT(!NeedsBlending(frame_header));
    146     JXL_ASSERT(!frame_header.CanBeReferenced() ||
    147                frame_header.save_before_color_transform);
    148     JXL_ASSERT(!options.render_spotcolors ||
    149                !decoded->metadata()->Find(ExtraChannel::kSpotColor));
    150     bool is_rgba = (main_output.format.num_channels == 4);
    151     uint8_t* rgb_output = reinterpret_cast<uint8_t*>(main_output.buffer);
    152     builder.AddStage(GetFastXYBTosRGB8Stage(rgb_output, main_output.stride,
    153                                             width, height, is_rgba, has_alpha,
    154                                             alpha_c));
    155 #endif
    156   } else {
    157     bool linear = false;
    158     if (frame_header.color_transform == ColorTransform::kYCbCr) {
    159       builder.AddStage(GetYCbCrStage());
    160     } else if (frame_header.color_transform == ColorTransform::kXYB) {
    161       builder.AddStage(GetXYBStage(output_encoding_info));
    162       if (output_encoding_info.color_encoding.GetColorSpace() !=
    163           ColorSpace::kXYB) {
    164         linear = true;
    165       }
    166     }  // Nothing to do for kNone.
    167 
    168     if (options.coalescing && NeedsBlending(frame_header)) {
    169       if (linear) {
    170         builder.AddStage(GetFromLinearStage(output_encoding_info));
    171         linear = false;
    172       }
    173       builder.AddStage(GetBlendingStage(frame_header, this,
    174                                         output_encoding_info.color_encoding));
    175     }
    176 
    177     if (options.coalescing && frame_header.CanBeReferenced() &&
    178         !frame_header.save_before_color_transform) {
    179       if (linear) {
    180         builder.AddStage(GetFromLinearStage(output_encoding_info));
    181         linear = false;
    182       }
    183       builder.AddStage(GetWriteToImageBundleStage(
    184           &frame_storage_for_referencing, output_encoding_info.color_encoding));
    185     }
    186 
    187     if (options.render_spotcolors &&
    188         frame_header.nonserialized_metadata->m.Find(ExtraChannel::kSpotColor)) {
    189       for (size_t i = 0; i < decoded->metadata()->extra_channel_info.size();
    190            i++) {
    191         // Don't use Find() because there may be multiple spot color channels.
    192         const ExtraChannelInfo& eci =
    193             decoded->metadata()->extra_channel_info[i];
    194         if (eci.type == ExtraChannel::kSpotColor) {
    195           builder.AddStage(GetSpotColorStage(3 + i, eci.spot_color));
    196         }
    197       }
    198     }
    199 
    200     auto tone_mapping_stage = GetToneMappingStage(output_encoding_info);
    201     if (tone_mapping_stage) {
    202       if (!linear) {
    203         auto to_linear_stage = GetToLinearStage(output_encoding_info);
    204         if (!to_linear_stage) {
    205           if (!output_encoding_info.cms_set) {
    206             return JXL_FAILURE("Cannot tonemap this colorspace without a CMS");
    207           }
    208           auto cms_stage = GetCmsStage(output_encoding_info);
    209           if (cms_stage) {
    210             builder.AddStage(std::move(cms_stage));
    211           }
    212         } else {
    213           builder.AddStage(std::move(to_linear_stage));
    214         }
    215         linear = true;
    216       }
    217       builder.AddStage(std::move(tone_mapping_stage));
    218     }
    219 
    220     if (linear) {
    221       const size_t channels_src =
    222           (output_encoding_info.orig_color_encoding.IsCMYK()
    223                ? 4
    224                : output_encoding_info.orig_color_encoding.Channels());
    225       const size_t channels_dst =
    226           output_encoding_info.color_encoding.Channels();
    227       bool mixing_color_and_grey = (channels_dst != channels_src);
    228       if ((output_encoding_info.color_encoding_is_original) ||
    229           (!output_encoding_info.cms_set) || mixing_color_and_grey) {
    230         // in those cases we only need a linear stage in other cases we attempt
    231         // to obtain an cms stage: the cases are
    232         // - output_encoding_info.color_encoding_is_original: no cms stage
    233         // needed because it would be a no-op
    234         // - !output_encoding_info.cms_set: can't use the cms, so no point in
    235         // trying to add a cms stage
    236         // - mixing_color_and_grey: cms stage can't handle that
    237         // TODO(firsching): remove "mixing_color_and_grey" condition after
    238         // adding support for greyscale to cms stage.
    239         builder.AddStage(GetFromLinearStage(output_encoding_info));
    240       } else {
    241         if (!output_encoding_info.linear_color_encoding.CreateICC()) {
    242           return JXL_FAILURE("Failed to create ICC");
    243         }
    244         auto cms_stage = GetCmsStage(output_encoding_info);
    245         if (cms_stage) {
    246           builder.AddStage(std::move(cms_stage));
    247         }
    248       }
    249       linear = false;
    250     }
    251     (void)linear;
    252 
    253     if (main_output.callback.IsPresent() || main_output.buffer) {
    254       builder.AddStage(GetWriteToOutputStage(main_output, width, height,
    255                                              has_alpha, unpremul_alpha, alpha_c,
    256                                              undo_orientation, extra_output));
    257     } else {
    258       builder.AddStage(GetWriteToImageBundleStage(
    259           decoded, output_encoding_info.color_encoding));
    260     }
    261   }
    262   JXL_ASSIGN_OR_RETURN(render_pipeline,
    263                        std::move(builder).Finalize(shared->frame_dim));
    264   return render_pipeline->IsInitialized();
    265 }
    266 
    267 }  // namespace jxl