1 // Copyright (c) Team CharLS.
2 // SPDX-License-Identifier: BSD-3-Clause
3
4 #pragma once
5
6 #include "coding_parameters.h"
7 #include "util.h"
8
9 #include <algorithm>
10 #include <cstring>
11 #include <sstream>
12 #include <vector>
13
14
15 //
16 // This file defines the ProcessLine base class, its derivatives and helper functions.
17 // During coding/decoding, CharLS process one line at a time. The different ProcessLine implementations
18 // convert the uncompressed format to and from the internal format for encoding.
19 // Conversions include color transforms, line interleaved vs sample interleaved, masking out unused bits,
20 // accounting for line padding etc.
21 // This mechanism could be used to encode/decode images as they are received.
22 //
23
24 namespace charls {
25
26 class process_line
27 {
28 public:
29 virtual ~process_line() = default;
30
31 process_line(const process_line&) = delete;
32 process_line(process_line&&) = delete;
33 process_line& operator=(const process_line&) = delete;
34 process_line& operator=(process_line&&) = delete;
35
36 virtual void new_line_decoded(const void* source, size_t pixel_count, size_t source_stride) = 0;
37 virtual void new_line_requested(void* destination, size_t pixel_count, size_t destination_stride) = 0;
38
39 protected:
40 process_line() = default;
41 };
42
43
44 class post_process_single_component final : public process_line
45 {
46 public:
post_process_single_component(void * raw_data,const size_t stride,const size_t bytes_per_pixel)47 post_process_single_component(void* raw_data, const size_t stride, const size_t bytes_per_pixel) noexcept :
48 raw_data_{static_cast<uint8_t*>(raw_data)}, bytes_per_pixel_{bytes_per_pixel}, stride_{stride}
49 {
50 ASSERT(bytes_per_pixel == sizeof(uint8_t) || bytes_per_pixel == sizeof(uint16_t));
51 }
52
new_line_requested(void * destination,const size_t pixel_count,size_t)53 void new_line_requested(void* destination, const size_t pixel_count,
54 size_t /* destination_stride */) noexcept(false) override
55 {
56 memcpy(destination, raw_data_, pixel_count * bytes_per_pixel_);
57 raw_data_ += stride_;
58 }
59
new_line_decoded(const void * source,const size_t pixel_count,size_t)60 void new_line_decoded(const void* source, const size_t pixel_count, size_t /* source_stride */) noexcept(false) override
61 {
62 memcpy(raw_data_, source, pixel_count * bytes_per_pixel_);
63 raw_data_ += stride_;
64 }
65
66 private:
67 uint8_t* raw_data_;
68 size_t bytes_per_pixel_;
69 size_t stride_;
70 };
71
72
73 class post_process_single_component_masked final : public process_line
74 {
75 public:
post_process_single_component_masked(void * raw_data,const size_t stride,const size_t bytes_per_pixel,const uint32_t bits_per_pixel)76 post_process_single_component_masked(void* raw_data, const size_t stride, const size_t bytes_per_pixel,
77 const uint32_t bits_per_pixel) noexcept :
78 raw_data_{raw_data},
79 bytes_per_pixel_{bytes_per_pixel},
80 stride_{stride},
81 mask_{(1U << bits_per_pixel) - 1U},
82 single_byte_pixel_{bytes_per_pixel_ == sizeof(uint8_t)}
83 {
84 ASSERT(bytes_per_pixel == sizeof(uint8_t) || bytes_per_pixel == sizeof(uint16_t));
85 }
86
new_line_requested(void * destination,const size_t pixel_count,size_t)87 void new_line_requested(void* destination, const size_t pixel_count,
88 size_t /* destination_stride */) noexcept(false) override
89 {
90 if (single_byte_pixel_)
91 {
92 const auto* pixel_source{static_cast<uint8_t*>(raw_data_)};
93 auto* pixel_destination{static_cast<uint8_t*>(destination)};
94 for (size_t i{}; i < pixel_count; ++i)
95 {
96 pixel_destination[i] = pixel_source[i] & mask_;
97 }
98 }
99 else
100 {
101 const auto* pixel_source{static_cast<uint16_t*>(raw_data_)};
102 auto* pixel_destination{static_cast<uint16_t*>(destination)};
103 for (size_t i{}; i < pixel_count; ++i)
104 {
105 pixel_destination[i] = pixel_source[i] & mask_;
106 }
107 }
108
109 raw_data_ = static_cast<uint8_t*>(raw_data_) + stride_;
110 }
111
new_line_decoded(const void * source,const size_t pixel_count,size_t)112 void new_line_decoded(const void* source, const size_t pixel_count, size_t /* source_stride */) noexcept(false) override
113 {
114 memcpy(raw_data_, source, pixel_count * bytes_per_pixel_);
115 raw_data_ = static_cast<uint8_t*>(raw_data_) + stride_;
116 }
117
118 private:
119 void* raw_data_;
120 size_t bytes_per_pixel_;
121 size_t stride_;
122 uint32_t mask_;
123 bool single_byte_pixel_;
124 };
125
126
127 template<typename Transform, typename PixelType>
transform_line_to_quad(const PixelType * source,const size_t pixel_stride_in,quad<PixelType> * destination,const size_t pixel_stride,Transform & transform)128 void transform_line_to_quad(const PixelType* source, const size_t pixel_stride_in, quad<PixelType>* destination,
129 const size_t pixel_stride,
130 Transform& transform) noexcept
131 {
132 const auto pixel_count{std::min(pixel_stride, pixel_stride_in)};
133
134 for (size_t i{}; i < pixel_count; ++i)
135 {
136 const quad<PixelType> pixel(transform(source[i], source[i + pixel_stride_in], source[i + 2 * pixel_stride_in]),
137 source[i + 3 * pixel_stride_in]);
138 destination[i] = pixel;
139 }
140 }
141
142
143 template<typename Transform, typename PixelType>
transform_quad_to_line(const quad<PixelType> * source,const size_t pixel_stride_in,PixelType * destination,const size_t pixel_stride,Transform & transform)144 void transform_quad_to_line(const quad<PixelType>* source, const size_t pixel_stride_in, PixelType* destination,
145 const size_t pixel_stride,
146 Transform& transform) noexcept
147 {
148 const auto pixel_count{std::min(pixel_stride, pixel_stride_in)};
149
150 for (size_t i{}; i < pixel_count; ++i)
151 {
152 const quad<PixelType> color{source[i]};
153 const quad<PixelType> color_transformed(transform(color.v1, color.v2, color.v3), color.v4);
154
155 destination[i] = color_transformed.v1;
156 destination[i + pixel_stride] = color_transformed.v2;
157 destination[i + 2 * pixel_stride] = color_transformed.v3;
158 destination[i + 3 * pixel_stride] = color_transformed.v4;
159 }
160 }
161
162
163 template<typename Transform, typename PixelType>
transform_quad_to_line(const quad<PixelType> * source,const size_t pixel_stride_in,PixelType * destination,const size_t pixel_stride,Transform & transform,const uint32_t mask)164 void transform_quad_to_line(const quad<PixelType>* source, const size_t pixel_stride_in, PixelType* destination,
165 const size_t pixel_stride, Transform& transform, const uint32_t mask) noexcept
166 {
167 const auto pixel_count{std::min(pixel_stride, pixel_stride_in)};
168
169 for (size_t i{}; i < pixel_count; ++i)
170 {
171 const quad<PixelType> color{source[i]};
172 const quad<PixelType> color_transformed(transform(color.v1 & mask, color.v2 & mask, color.v3 & mask),
173 color.v4 & mask);
174
175 destination[i] = color_transformed.v1;
176 destination[i + pixel_stride] = color_transformed.v2;
177 destination[i + 2 * pixel_stride] = color_transformed.v3;
178 destination[i + 3 * pixel_stride] = color_transformed.v4;
179 }
180 }
181
182
183 template<typename T>
transform_rgb_to_bgr(T * buffer,int samples_per_pixel,const size_t pixel_count)184 void transform_rgb_to_bgr(T* buffer, int samples_per_pixel, const size_t pixel_count) noexcept
185 {
186 for (size_t i{}; i < pixel_count; ++i)
187 {
188 std::swap(buffer[0], buffer[2]);
189 buffer += samples_per_pixel;
190 }
191 }
192
193
194 template<typename Transform, typename PixelType>
transform_line(triplet<PixelType> * destination,const triplet<PixelType> * source,const size_t pixel_count,Transform & transform)195 void transform_line(triplet<PixelType>* destination, const triplet<PixelType>* source, const size_t pixel_count,
196 Transform& transform) noexcept
197 {
198 for (size_t i{}; i < pixel_count; ++i)
199 {
200 destination[i] = transform(source[i].v1, source[i].v2, source[i].v3);
201 }
202 }
203
204
205 template<typename Transform, typename PixelType>
transform_line(triplet<PixelType> * destination,const triplet<PixelType> * source,const size_t pixel_count,Transform & transform,const uint32_t mask)206 void transform_line(triplet<PixelType>* destination, const triplet<PixelType>* source, const size_t pixel_count,
207 Transform& transform, const uint32_t mask) noexcept
208 {
209 for (size_t i{}; i < pixel_count; ++i)
210 {
211 destination[i] = transform(source[i].v1 & mask, source[i].v2 & mask, source[i].v3 & mask);
212 }
213 }
214
215
216 template<typename Transform, typename PixelType>
transform_line(quad<PixelType> * destination,const quad<PixelType> * source,const size_t pixel_count,Transform & transform)217 void transform_line(quad<PixelType>* destination, const quad<PixelType>* source, const size_t pixel_count,
218 Transform& transform) noexcept
219 {
220 for (size_t i{}; i < pixel_count; ++i)
221 {
222 destination[i] = quad<PixelType>(transform(source[i].v1, source[i].v2, source[i].v3), source[i].v4);
223 }
224 }
225
226
227 template<typename Transform, typename PixelType>
transform_line(quad<PixelType> * destination,const quad<PixelType> * source,const size_t pixel_count,Transform & transform,const uint32_t mask)228 void transform_line(quad<PixelType>* destination, const quad<PixelType>* source, const size_t pixel_count,
229 Transform& transform, const uint32_t mask) noexcept
230 {
231 for (size_t i{}; i < pixel_count; ++i)
232 {
233 destination[i] =
234 quad<PixelType>(transform(source[i].v1 & mask, source[i].v2 & mask, source[i].v3 & mask), source[i].v4 & mask);
235 }
236 }
237
238
239 template<typename Transform, typename PixelType>
transform_line_to_triplet(const PixelType * source,const size_t pixel_stride_in,triplet<PixelType> * destination,const size_t pixel_stride,Transform & transform)240 void transform_line_to_triplet(const PixelType* source, const size_t pixel_stride_in, triplet<PixelType>* destination,
241 const size_t pixel_stride, Transform& transform) noexcept
242 {
243 const auto pixel_count{std::min(pixel_stride, pixel_stride_in)};
244 triplet<PixelType>* type_buffer = destination;
245
246 for (size_t i{}; i < pixel_count; ++i)
247 {
248 type_buffer[i] = transform(source[i], source[i + pixel_stride_in], source[i + 2 * pixel_stride_in]);
249 }
250 }
251
252
253 template<typename Transform, typename PixelType>
transform_triplet_to_line(const triplet<PixelType> * source,const size_t pixel_stride_in,PixelType * destination,const size_t pixel_stride,Transform & transform)254 void transform_triplet_to_line(const triplet<PixelType>* source, const size_t pixel_stride_in, PixelType* destination,
255 const size_t pixel_stride, Transform& transform) noexcept
256 {
257 const auto pixel_count{std::min(pixel_stride, pixel_stride_in)};
258 const triplet<PixelType>* type_buffer_in{source};
259
260 for (size_t i{}; i < pixel_count; ++i)
261 {
262 const triplet<PixelType> color = type_buffer_in[i];
263 const triplet<PixelType> color_transformed = transform(color.v1, color.v2, color.v3);
264
265 destination[i] = color_transformed.v1;
266 destination[i + pixel_stride] = color_transformed.v2;
267 destination[i + 2 * pixel_stride] = color_transformed.v3;
268 }
269 }
270
271
272 template<typename Transform, typename PixelType>
transform_triplet_to_line(const triplet<PixelType> * source,const size_t pixel_stride_in,PixelType * destination,const size_t pixel_stride,Transform & transform,const uint32_t mask)273 void transform_triplet_to_line(const triplet<PixelType>* source, const size_t pixel_stride_in, PixelType* destination,
274 const size_t pixel_stride, Transform& transform, const uint32_t mask) noexcept
275 {
276 const auto pixel_count{std::min(pixel_stride, pixel_stride_in)};
277 const triplet<PixelType>* type_buffer_in{source};
278
279 for (size_t i{}; i < pixel_count; ++i)
280 {
281 const triplet<PixelType> color = type_buffer_in[i];
282 const triplet<PixelType> color_transformed = transform(color.v1 & mask, color.v2 & mask, color.v3 & mask);
283
284 destination[i] = color_transformed.v1;
285 destination[i + pixel_stride] = color_transformed.v2;
286 destination[i + 2 * pixel_stride] = color_transformed.v3;
287 }
288 }
289
290
291 template<typename TransformType>
292 class process_transformed final : public process_line
293 {
294 public:
process_transformed(byte_span source_pixels,const size_t stride,const frame_info & info,const coding_parameters & parameters,TransformType transform)295 process_transformed(byte_span source_pixels, const size_t stride, const frame_info& info,
296 const coding_parameters& parameters, TransformType transform) :
297 frame_info_{info},
298 parameters_{parameters},
299 stride_{stride},
300 temp_line_(static_cast<size_t>(info.component_count) * info.width),
301 buffer_(static_cast<size_t>(info.component_count) * info.width * sizeof(size_type)),
302 transform_{transform},
303 inverse_transform_{transform},
304 raw_pixels_{source_pixels},
305 mask_{(1U << info.bits_per_sample) - 1U}
306 {
307 }
308
new_line_requested(void * destination,const size_t pixel_count,const size_t destination_stride)309 void new_line_requested(void* destination, const size_t pixel_count,
310 const size_t destination_stride) noexcept(false) override
311 {
312 encode_transform(raw_pixels_.data, destination, pixel_count, destination_stride);
313 raw_pixels_.data += stride_;
314 }
315
encode_transform(const void * source,void * destination,const size_t pixel_count,const size_t destination_stride)316 void encode_transform(const void* source, void* destination, const size_t pixel_count, const size_t destination_stride) noexcept
317 {
318 if (parameters_.output_bgr)
319 {
320 memcpy(temp_line_.data(), source, sizeof(triplet<size_type>) * pixel_count);
321 transform_rgb_to_bgr(temp_line_.data(), frame_info_.component_count, pixel_count);
322 source = temp_line_.data();
323 }
324
325 if (frame_info_.component_count == 3)
326 {
327 if (parameters_.interleave_mode == interleave_mode::sample)
328 {
329 transform_line(static_cast<triplet<size_type>*>(destination), static_cast<const triplet<size_type>*>(source),
330 pixel_count, transform_, mask_);
331 }
332 else
333 {
334 transform_triplet_to_line(static_cast<const triplet<size_type>*>(source), pixel_count,
335 static_cast<size_type*>(destination), destination_stride, transform_, mask_);
336 }
337 }
338 else if (frame_info_.component_count == 4)
339 {
340 if (parameters_.interleave_mode == interleave_mode::sample)
341 {
342 transform_line(static_cast<quad<size_type>*>(destination), static_cast<const quad<size_type>*>(source),
343 pixel_count, transform_, mask_);
344 }
345 else if (parameters_.interleave_mode == interleave_mode::line)
346 {
347 transform_quad_to_line(static_cast<const quad<size_type>*>(source), pixel_count,
348 static_cast<size_type*>(destination), destination_stride, transform_, mask_);
349 }
350 }
351 }
352
decode_transform(const void * source,void * destination,const size_t pixel_count,const size_t byte_stride)353 void decode_transform(const void* source, void* destination, const size_t pixel_count, const size_t byte_stride) noexcept
354 {
355 if (frame_info_.component_count == 3)
356 {
357 if (parameters_.interleave_mode == interleave_mode::sample)
358 {
359 transform_line(static_cast<triplet<size_type>*>(destination), static_cast<const triplet<size_type>*>(source),
360 pixel_count, inverse_transform_);
361 }
362 else
363 {
364 transform_line_to_triplet(static_cast<const size_type*>(source), byte_stride,
365 static_cast<triplet<size_type>*>(destination), pixel_count, inverse_transform_);
366 }
367 }
368 else if (frame_info_.component_count == 4)
369 {
370 if (parameters_.interleave_mode == interleave_mode::sample)
371 {
372 transform_line(static_cast<quad<size_type>*>(destination), static_cast<const quad<size_type>*>(source),
373 pixel_count, inverse_transform_);
374 }
375 else if (parameters_.interleave_mode == interleave_mode::line)
376 {
377 transform_line_to_quad(static_cast<const size_type*>(source), byte_stride,
378 static_cast<quad<size_type>*>(destination), pixel_count, inverse_transform_);
379 }
380 }
381
382 if (parameters_.output_bgr)
383 {
384 transform_rgb_to_bgr(static_cast<size_type*>(destination), frame_info_.component_count, pixel_count);
385 }
386 }
387
new_line_decoded(const void * source,const size_t pixel_count,const size_t source_stride)388 void new_line_decoded(const void* source, const size_t pixel_count, const size_t source_stride) noexcept(false) override
389 {
390 decode_transform(source, raw_pixels_.data, pixel_count, source_stride);
391 raw_pixels_.data += stride_;
392 }
393
394 private:
395 using size_type = typename TransformType::size_type;
396
397 const frame_info& frame_info_;
398 const coding_parameters& parameters_;
399 const size_t stride_;
400 std::vector<size_type> temp_line_;
401 std::vector<uint8_t> buffer_;
402 TransformType transform_;
403 typename TransformType::inverse inverse_transform_;
404 byte_span raw_pixels_;
405 uint32_t mask_;
406 };
407
408 } // namespace charls
409