Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert template class scan_codec_factory into template method #296

Merged
merged 1 commit into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
# -clang-diagnostic-unsafe-buffer-usage => Rationale: Too many false warnings, access is verified with other tools.
# -clang-analyzer-core.NonNullParamChecker => Rationale: cannot be effective disabled, already checked by other checkers.
# -misc-non-private-member-variables-in-classes => Rationale: design can be ok, manual review is better
# -misc-include-cleaner => complains about no direct includes
# -modernize-use-trailing-return-type => Rationale: A style recommendation, this style is selected for CharLS
# -readability-magic-numbers => Rationale: To critical rule, used numbers are logical
# -readability-named-parameter => Rationale: to many non problematic warnings
Expand Down Expand Up @@ -81,6 +82,7 @@ Checks: '*,
-clang-diagnostic-unsafe-buffer-usage,
-clang-analyzer-core.NonNullParamChecker,
-misc-non-private-member-variables-in-classes,
-misc-include-cleaner,
-modernize-use-trailing-return-type,
-readability-magic-numbers,
-readability-named-parameter,
Expand Down
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ root = true
charset = utf-8
indent_style = space
trim_trailing_whitespace = true
spelling_exclusion_path = spelling.dic

[*.md]
trim_trailing_whitespace = false
Expand Down
1 change: 1 addition & 0 deletions CharLS.sln
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
SECURITY.md = SECURITY.md
sonar-project.properties = sonar-project.properties
spelling.dic = spelling.dic
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "convert-c", "samples\convert.c\convert-c.vcxproj", "{F42C0547-FEB3-40F4-9379-0FF87B44FA0F}"
Expand Down
13 changes: 13 additions & 0 deletions spelling.dic
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
jpegls
cppcoreguidelines
golomb
charls
opto
Errval
Golomb
maxval
unmap
subspan
misc
bugprone
countl
4 changes: 2 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,13 @@ target_sources(charls
"${CMAKE_CURRENT_LIST_DIR}/jpegls_preset_coding_parameters.h"
"${CMAKE_CURRENT_LIST_DIR}/jpegls_preset_parameters_type.h"
"${CMAKE_CURRENT_LIST_DIR}/lossless_traits.h"
"${CMAKE_CURRENT_LIST_DIR}/make_scan_codec.h"
"${CMAKE_CURRENT_LIST_DIR}/make_scan_codec.cpp"
"${CMAKE_CURRENT_LIST_DIR}/process_decoded_line.h"
"${CMAKE_CURRENT_LIST_DIR}/process_encoded_line.h"
"${CMAKE_CURRENT_LIST_DIR}/quantization_lut.h"
"${CMAKE_CURRENT_LIST_DIR}/quantization_lut.cpp"
"${CMAKE_CURRENT_LIST_DIR}/scan_codec.h"
"${CMAKE_CURRENT_LIST_DIR}/scan_codec_factory.h"
"${CMAKE_CURRENT_LIST_DIR}/scan_codec_factory.cpp"
"${CMAKE_CURRENT_LIST_DIR}/scan_decoder.h"
"${CMAKE_CURRENT_LIST_DIR}/scan_decoder_impl.h"
"${CMAKE_CURRENT_LIST_DIR}/scan_encoder.h"
Expand Down
4 changes: 2 additions & 2 deletions src/CharLS.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@
<ClCompile Include="validate_spiff_header.cpp" />
<ClCompile Include="version.cpp" />
<ClCompile Include="charls_jpegls_decoder.cpp" />
<ClCompile Include="scan_codec_factory.cpp" />
<ClCompile Include="make_scan_codec.cpp" />
<ClCompile Include="charls_jpegls_encoder.cpp" />
<ClCompile Include="jpegls_error.cpp" />
<ClCompile Include="jpeg_stream_reader.cpp" />
Expand All @@ -243,7 +243,7 @@
<ClInclude Include="default_traits.h" />
<ClInclude Include="scan_encoder.h" />
<ClInclude Include="golomb_lut.h" />
<ClInclude Include="scan_codec_factory.h" />
<ClInclude Include="make_scan_codec.h" />
<ClInclude Include="jpegls_algorithm.h" />
<ClInclude Include="jpegls_preset_coding_parameters.h" />
<ClInclude Include="jpeg_marker_code.h" />
Expand Down
4 changes: 2 additions & 2 deletions src/CharLS.vcxproj.filters
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="scan_codec_factory.cpp">
<ClCompile Include="make_scan_codec.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="jpegls_error.cpp">
Expand Down Expand Up @@ -69,7 +69,7 @@
<ClInclude Include="scan_encoder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="scan_codec_factory.h">
<ClInclude Include="make_scan_codec.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="jpeg_marker_code.h">
Expand Down
22 changes: 13 additions & 9 deletions src/charls_jpegls_decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#include "constants.h"
#include "jpeg_stream_reader.h"
#include "scan_codec_factory.h"
#include "make_scan_codec.h"
#include "scan_decoder.h"
#include "util.h"

Expand Down Expand Up @@ -53,14 +53,14 @@ struct charls_jpegls_decoder final
[[nodiscard]]
charls::frame_info frame_info_checked() const
{
check_operation(state_ >= state::header_read);
check_header_read();
return frame_info();
}

[[nodiscard]]
int32_t near_lossless(int32_t /*component*/ = 0) const
{
check_operation(state_ >= state::header_read);
check_header_read();

// Note: The JPEG-LS standard allows to define different NEAR parameter for every scan.
return reader_.parameters().near_lossless;
Expand All @@ -69,7 +69,7 @@ struct charls_jpegls_decoder final
[[nodiscard]]
charls::interleave_mode interleave_mode() const
{
check_operation(state_ >= state::header_read);
check_header_read();

// Note: The JPEG-LS standard allows to define different interleave modes for every scan.
// CharLS doesn't support mixed interleave modes, first scan determines the mode.
Expand All @@ -79,14 +79,14 @@ struct charls_jpegls_decoder final
[[nodiscard]]
charls::color_transformation color_transformation() const
{
check_operation(state_ >= state::header_read);
check_header_read();
return reader_.parameters().transformation;
}

[[nodiscard]]
const jpegls_pc_parameters& preset_coding_parameters() const
{
check_operation(state_ >= state::header_read);
check_header_read();
return reader_.preset_coding_parameters();
}

Expand Down Expand Up @@ -134,7 +134,6 @@ struct charls_jpegls_decoder final
{
check_argument(destination.data() || destination.empty());
check_operation(state_ == state::header_read);

check_parameter_coherent();

// Compute the stride for the uncompressed destination buffer.
Expand All @@ -159,9 +158,9 @@ struct charls_jpegls_decoder final

for (size_t plane{};;)
{
const auto scan_codec{scan_codec_factory<scan_decoder>().create_codec(
const auto decoder{make_scan_codec<scan_decoder>(
frame_info(), reader_.parameters(), reader_.get_validated_preset_coding_parameters())};
const size_t bytes_read{scan_codec->decode_scan(reader_.remaining_source(), destination.data(), stride)};
const size_t bytes_read{decoder->decode_scan(reader_.remaining_source(), destination.data(), stride)};
reader_.advance_position(bytes_read);

++plane;
Expand Down Expand Up @@ -193,6 +192,11 @@ struct charls_jpegls_decoder final
return components_in_plane_count * frame_info().width * bit_to_byte_count(frame_info().bits_per_sample);
}

void check_header_read() const
{
check_operation(state_ >= state::header_read);
}

void check_parameter_coherent() const
{
switch (frame_info().component_count)
Expand Down
6 changes: 3 additions & 3 deletions src/charls_jpegls_encoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

#include "jpeg_stream_writer.h"
#include "jpegls_preset_coding_parameters.h"
#include "scan_codec_factory.h"
#include "make_scan_codec.h"
#include "scan_encoder.h"
#include "util.h"

Expand Down Expand Up @@ -266,9 +266,9 @@ struct charls_jpegls_encoder final
const charls::frame_info frame_info{frame_info_.width, frame_info_.height, frame_info_.bits_per_sample,
component_count};

const auto scan_codec{scan_codec_factory<scan_encoder>().create_codec(
const auto encoder{make_scan_codec<scan_encoder>(
frame_info, {near_lossless_, 0, interleave_mode_, color_transformation_}, preset_coding_parameters_)};
const size_t bytes_written{scan_codec->encode_scan(source, stride, writer_.remaining_destination())};
const size_t bytes_written{encoder->encode_scan(source, stride, writer_.remaining_destination())};

// Synchronize the destination encapsulated in the writer (encode_scan works on a local copy)
writer_.seek(bytes_written);
Expand Down
1 change: 1 addition & 0 deletions src/jpeg_marker_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#pragma once

#include <cstddef>
#include <cstdint>

namespace charls {
Expand Down
117 changes: 62 additions & 55 deletions src/scan_codec_factory.cpp → src/make_scan_codec.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Team CharLS.
// SPDX-License-Identifier: BSD-3-Clause

#include "scan_codec_factory.h"
#include "make_scan_codec.h"

#include "default_traits.h"
#include "jpegls_preset_coding_parameters.h"
Expand Down Expand Up @@ -30,6 +30,7 @@ frame_info update_component_count(const frame_info& frame, const coding_paramete


template<typename ScanProcess, typename Traits>
[[nodiscard]]
unique_ptr<ScanProcess> make_codec(const Traits& traits, const frame_info& frame, const coding_parameters& parameters)
{
if constexpr (std::is_same_v<ScanProcess, scan_encoder>)
Expand All @@ -42,46 +43,9 @@ unique_ptr<ScanProcess> make_codec(const Traits& traits, const frame_info& frame
}
}

} // namespace


template<typename ScanProcess>
unique_ptr<ScanProcess> scan_codec_factory<ScanProcess>::create_codec(const frame_info& frame,
const coding_parameters& parameters,
const jpegls_pc_parameters& preset_coding_parameters)
{
unique_ptr<ScanProcess> codec;

if (preset_coding_parameters.reset_value == default_reset_value)
{
codec = try_create_optimized_codec(frame, parameters);
}

if (!codec)
{
if (frame.bits_per_sample <= 8)
{
default_traits<uint8_t, uint8_t> traits(calculate_maximum_sample_value(frame.bits_per_sample),
parameters.near_lossless, preset_coding_parameters.reset_value);
traits.maximum_sample_value = preset_coding_parameters.maximum_sample_value;
codec = make_codec<ScanProcess, default_traits<uint8_t, uint8_t>>(traits, frame, parameters);
}
else
{
default_traits<uint16_t, uint16_t> traits(calculate_maximum_sample_value(frame.bits_per_sample),
parameters.near_lossless, preset_coding_parameters.reset_value);
traits.maximum_sample_value = preset_coding_parameters.maximum_sample_value;
codec = make_codec<ScanProcess, default_traits<uint16_t, uint16_t>>(traits, frame, parameters);
}
}

codec->set_presets(preset_coding_parameters);
return codec;
}

template<typename ScanProcess>
unique_ptr<ScanProcess> scan_codec_factory<ScanProcess>::try_create_optimized_codec(const frame_info& frame,
const coding_parameters& parameters)
[[nodiscard]]
unique_ptr<ScanProcess> try_make_optimized_codec(const frame_info& frame, const coding_parameters& parameters)
{
if (parameters.interleave_mode == interleave_mode::sample && frame.component_count != 3 && frame.component_count != 4)
return nullptr;
Expand Down Expand Up @@ -116,53 +80,96 @@ unique_ptr<ScanProcess> scan_codec_factory<ScanProcess>::try_create_optimized_co

#endif

const auto maxval{calculate_maximum_sample_value(frame.bits_per_sample)};
const auto maximum_sample_value{calculate_maximum_sample_value(frame.bits_per_sample)};

if (frame.bits_per_sample <= 8)
{
if (parameters.interleave_mode == interleave_mode::sample)
{
if (frame.component_count == 3)
{
return make_codec<ScanProcess>(default_traits<uint8_t, triplet<uint8_t>>(maxval, parameters.near_lossless),
frame, parameters);
return make_codec<ScanProcess>(
default_traits<uint8_t, triplet<uint8_t>>(maximum_sample_value, parameters.near_lossless), frame,
parameters);
}

if (frame.component_count == 4)
{
return make_codec<ScanProcess>(default_traits<uint8_t, quad<uint8_t>>(maxval, parameters.near_lossless),
frame, parameters);
return make_codec<ScanProcess>(
default_traits<uint8_t, quad<uint8_t>>(maximum_sample_value, parameters.near_lossless), frame,
parameters);
}
}

return make_codec<ScanProcess>(default_traits<uint8_t, uint8_t>(maxval, parameters.near_lossless), frame,
parameters);
return make_codec<ScanProcess>(default_traits<uint8_t, uint8_t>(maximum_sample_value, parameters.near_lossless),
frame, parameters);
}
if (frame.bits_per_sample <= 16)
{
if (parameters.interleave_mode == interleave_mode::sample)
{
if (frame.component_count == 3)
{
return make_codec<ScanProcess>(default_traits<uint16_t, triplet<uint16_t>>(maxval, parameters.near_lossless),
frame, parameters);
return make_codec<ScanProcess>(
default_traits<uint16_t, triplet<uint16_t>>(maximum_sample_value, parameters.near_lossless), frame,
parameters);
}

if (frame.component_count == 4)
{
return make_codec<ScanProcess>(default_traits<uint16_t, quad<uint16_t>>(maxval, parameters.near_lossless),
frame, parameters);
return make_codec<ScanProcess>(
default_traits<uint16_t, quad<uint16_t>>(maximum_sample_value, parameters.near_lossless), frame,
parameters);
}
}

return make_codec<ScanProcess>(default_traits<uint16_t, uint16_t>(maxval, parameters.near_lossless), frame,
parameters);
return make_codec<ScanProcess>(default_traits<uint16_t, uint16_t>(maximum_sample_value, parameters.near_lossless),
frame, parameters);
}
return nullptr;
}


template class scan_codec_factory<scan_decoder>;
template class scan_codec_factory<scan_encoder>;
} // namespace


template<typename ScanProcess>
unique_ptr<ScanProcess> make_scan_codec(const frame_info& frame, const coding_parameters& parameters,
const jpegls_pc_parameters& preset_coding_parameters)
{
unique_ptr<ScanProcess> codec;

if (preset_coding_parameters.reset_value == default_reset_value)
{
codec = try_make_optimized_codec<ScanProcess>(frame, parameters);
}

if (!codec)
{
if (frame.bits_per_sample <= 8)
{
default_traits<uint8_t, uint8_t> traits(calculate_maximum_sample_value(frame.bits_per_sample),
parameters.near_lossless, preset_coding_parameters.reset_value);
traits.maximum_sample_value = preset_coding_parameters.maximum_sample_value;
codec = make_codec<ScanProcess, default_traits<uint8_t, uint8_t>>(traits, frame, parameters);
}
else
{
default_traits<uint16_t, uint16_t> traits(calculate_maximum_sample_value(frame.bits_per_sample),
parameters.near_lossless, preset_coding_parameters.reset_value);
traits.maximum_sample_value = preset_coding_parameters.maximum_sample_value;
codec = make_codec<ScanProcess, default_traits<uint16_t, uint16_t>>(traits, frame, parameters);
}
}

codec->set_presets(preset_coding_parameters);
return codec;
}


template std::unique_ptr<scan_decoder> make_scan_codec<scan_decoder>(const frame_info&, const coding_parameters&,
const jpegls_pc_parameters&);
template std::unique_ptr<scan_encoder> make_scan_codec<scan_encoder>(const frame_info&, const coding_parameters&,
const jpegls_pc_parameters&);

} // namespace charls
Loading