From 0e561a06d426c82e8f76d8ede5861a9c2e3a502a Mon Sep 17 00:00:00 2001 From: Yannis Guyon Date: Fri, 4 Apr 2025 14:51:49 +0000 Subject: [PATCH] Add 4:2:0 J2K support with OpenJPEG API It seems to match the output file size of opj_compress -i in.png -o out.jp2 -r {101-q} -s 2,2 --- CHANGELOG.md | 4 ++++ CMakeLists.txt | 2 +- src/codec_openjpeg.cc | 31 ++++++++++++++++--------------- src/result_json.cc | 2 +- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71ef6ca..488a5ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v0.5.5 + +- Add JPEG 2000 4:2:0 support through OpenJPEG. + ## v0.5.4 - Add JPEG 2000 support through OpenJPEG (4:4:4 only). diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d2a674..dd270ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ cmake_minimum_required(VERSION 3.20) project( codec-compare-gen LANGUAGES CXX - VERSION 0.5.4) + VERSION 0.5.5) set(CMAKE_CXX_STANDARD 17) option(BUILD_SHARED_LIBS "Build the shared codec-compare-gen library" ON) diff --git a/src/codec_openjpeg.cc b/src/codec_openjpeg.cc index e8138c0..212ef6d 100644 --- a/src/codec_openjpeg.cc +++ b/src/codec_openjpeg.cc @@ -79,19 +79,19 @@ StatusOr EncodeOpenjpeg(const TaskInput& input, // Match the default settings of opj_compress. parameters.tcp_numlayers = 1; parameters.cp_disto_alloc = 1; - parameters.tcp_mct = 1; // RGB->YCC. TODO(yguyon): Try keeping it to 0. + parameters.tcp_mct = 1; // RGB->YCC. TODO(yguyon): Try keeping it to 0. + uint32_t subsampling = 1; // 1 for 4:4:4, 2 for 4:2:0. if (input.codec_settings.quality == kQualityLossless) { CHECK_OR_RETURN( input.codec_settings.chroma_subsampling == Subsampling::k444 || input.codec_settings.chroma_subsampling == Subsampling::kDefault, quiet); - parameters.subsampling_dx = parameters.subsampling_dy = 1; parameters.tcp_rates[0] = 0.f; // Equivalent to 1.f (lossless). } else { - if (input.codec_settings.chroma_subsampling == Subsampling::k444) { - parameters.subsampling_dx = parameters.subsampling_dy = 1; - } else { - parameters.subsampling_dx = parameters.subsampling_dy = 2; + if (input.codec_settings.chroma_subsampling == Subsampling::k420 || + input.codec_settings.chroma_subsampling == Subsampling::kDefault) { + // Note that opj_cparameters::subsampling_dx/y are ignored by opj_encode. + subsampling = 2; } parameters.tcp_rates[0] = 101.f - input.codec_settings.quality; // parameters.irreversible = 1; // TODO(yguyon): Try this. @@ -116,8 +116,8 @@ StatusOr EncodeOpenjpeg(const TaskInput& input, ? WP2Formatbpalpha(pixels.format()) : WP2Formatbpc(pixels.format()); compparams[i].sgnd = 0; - compparams[i].dx = 1; - compparams[i].dy = 1; + compparams[i].dx = subsampling; + compparams[i].dy = subsampling; compparams[i].w = pixels.width(); compparams[i].h = pixels.height(); } @@ -131,8 +131,10 @@ StatusOr EncodeOpenjpeg(const TaskInput& input, opj_image->x0 = 0; opj_image->y0 = 0; - opj_image->x1 = pixels.width(); // compparams[0].dx * compparams[0].w; - opj_image->y1 = pixels.height(); // compparams[0].dy * compparams[0].h; + // Taken from + // https://github.com/uclouvain/openjpeg/blob/e7453e398b110891778d8da19209792c69ca7169/src/bin/jp2/convert.c#L1890-L1893 + opj_image->x1 = (compparams[0].w - 1) * compparams[0].dx + 1; + opj_image->y1 = (compparams[0].h - 1) * compparams[0].dy + 1; for (uint32_t i = 0; i < num_channels; ++i) { opj_image->comps[i].alpha = i == alpha_channel_index ? 1 : 0; for (uint32_t y = 0; y < pixels.height(); ++y) { @@ -365,11 +367,10 @@ StatusOr> DecodeOpenjpeg( Image image; image.reserve(1); image.emplace_back(WP2::ArgbBuffer(format), /*duration_ms=*/0); - CHECK_OR_RETURN(image.back().pixels.Resize( - static_cast(opj_image->x1 - opj_image->x0), - static_cast(opj_image->y1 - opj_image->y0)) == - WP2_STATUS_OK, - quiet); + CHECK_OR_RETURN( + image.back().pixels.Resize(opj_image->comps[0].w, + opj_image->comps[0].h) == WP2_STATUS_OK, + quiet); WP2::ArgbBuffer& pixels = image.front().pixels; for (uint32_t c = 0; c < opj_image->numcomps; ++c) { diff --git a/src/result_json.cc b/src/result_json.cc index 780577f..64fa546 100644 --- a/src/result_json.cc +++ b/src/result_json.cc @@ -140,7 +140,7 @@ Status TasksToJson(const std::string& batch_pretty_name, CodecSettings settings, " && mv third_party/libavif_avm third_party/libavif" : ""; const std::string build_cmd = - "git clone -b v0.5.4 --depth 1" + "git clone -b v0.5.5 --depth 1" " https://github.com/webmproject/codec-compare-gen.git" " && cd codec-compare-gen && ./deps.sh" + deps_extra_step +