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