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 
7 #ifndef LIB_JXL_ENCODE_INTERNAL_H_
8 #define LIB_JXL_ENCODE_INTERNAL_H_
9 
10 #include <vector>
11 
12 #include "jxl/encode.h"
13 #include "jxl/memory_manager.h"
14 #include "jxl/parallel_runner.h"
15 #include "jxl/types.h"
16 #include "lib/jxl/base/data_parallel.h"
17 #include "lib/jxl/enc_frame.h"
18 #include "lib/jxl/memory_manager_internal.h"
19 
20 namespace jxl {
21 
22 // The encoder options (such as quality, compression speed, ...) for a single
23 // frame, but not encoder-wide options such as box-related options.
24 typedef struct JxlEncoderFrameSettingsValuesStruct {
25   // lossless is a separate setting from cparams because it is a combination
26   // setting that overrides multiple settings inside of cparams.
27   bool lossless;
28   CompressParams cparams;
29   JxlFrameHeader header;
30   std::vector<JxlBlendInfo> extra_channel_blend_info;
31   std::string frame_name;
32 } JxlEncoderFrameSettingsValues;
33 
34 typedef std::array<uint8_t, 4> BoxType;
35 
36 // Utility function that makes a BoxType from a string literal. The string must
37 // have 4 characters, a 5th null termination character is optional.
MakeBoxType(const char * type)38 constexpr BoxType MakeBoxType(const char* type) {
39   return BoxType(
40       {{static_cast<uint8_t>(type[0]), static_cast<uint8_t>(type[1]),
41         static_cast<uint8_t>(type[2]), static_cast<uint8_t>(type[3])}});
42 }
43 
44 constexpr unsigned char kContainerHeader[] = {
45     0,   0,   0, 0xc, 'J',  'X', 'L', ' ', 0xd, 0xa, 0x87,
46     0xa, 0,   0, 0,   0x14, 'f', 't', 'y', 'p', 'j', 'x',
47     'l', ' ', 0, 0,   0,    0,   'j', 'x', 'l', ' '};
48 
49 constexpr unsigned char kLevelBoxHeader[] = {0, 0, 0, 0x9, 'j', 'x', 'l', 'l'};
50 
51 struct JxlEncoderQueuedFrame {
52   JxlEncoderFrameSettingsValues option_values;
53   ImageBundle frame;
54   std::vector<uint8_t> ec_initialized;
55 };
56 
57 struct JxlEncoderQueuedBox {
58   BoxType type;
59   std::vector<uint8_t> contents;
60   bool compress_box;
61 };
62 
63 // Either a frame, or a box, not both.
64 struct JxlEncoderQueuedInput {
JxlEncoderQueuedInputJxlEncoderQueuedInput65   JxlEncoderQueuedInput(const JxlMemoryManager& memory_manager)
66       : frame(nullptr, jxl::MemoryManagerDeleteHelper(&memory_manager)),
67         box(nullptr, jxl::MemoryManagerDeleteHelper(&memory_manager)) {}
68   MemoryManagerUniquePtr<JxlEncoderQueuedFrame> frame;
69   MemoryManagerUniquePtr<JxlEncoderQueuedBox> box;
70 };
71 
72 namespace {
73 template <typename T>
Extend(T * vec,size_t size)74 uint8_t* Extend(T* vec, size_t size) {
75   vec->resize(vec->size() + size, 0);
76   return vec->data() + vec->size() - size;
77 }
78 }  // namespace
79 
80 // Appends a JXL container box header with given type, size, and unbounded
81 // properties to output.
82 template <typename T>
AppendBoxHeader(const jxl::BoxType & type,size_t size,bool unbounded,T * output)83 void AppendBoxHeader(const jxl::BoxType& type, size_t size, bool unbounded,
84                      T* output) {
85   uint64_t box_size = 0;
86   bool large_size = false;
87   if (!unbounded) {
88     box_size = size + 8;
89     if (box_size >= 0x100000000ull) {
90       large_size = true;
91     }
92   }
93 
94   StoreBE32(large_size ? 1 : box_size, Extend(output, 4));
95 
96   for (size_t i = 0; i < 4; i++) {
97     output->push_back(*(type.data() + i));
98   }
99 
100   if (large_size) {
101     StoreBE64(box_size, Extend(output, 8));
102   }
103 }
104 
105 }  // namespace jxl
106 
107 // Internal use only struct, can only be initialized correctly by
108 // JxlEncoderCreate.
109 struct JxlEncoderStruct {
110   JxlMemoryManager memory_manager;
111   jxl::MemoryManagerUniquePtr<jxl::ThreadPool> thread_pool{
112       nullptr, jxl::MemoryManagerDeleteHelper(&memory_manager)};
113   JxlCmsInterface cms;
114   std::vector<jxl::MemoryManagerUniquePtr<JxlEncoderFrameSettings>>
115       encoder_options;
116 
117   size_t num_queued_frames;
118   size_t num_queued_boxes;
119   std::vector<jxl::JxlEncoderQueuedInput> input_queue;
120   std::vector<uint8_t> output_byte_queue;
121 
122   // Force using the container even if not needed
123   bool use_container;
124   // User declared they will add metadata boxes
125   bool use_boxes;
126 
127   // TODO(lode): move level into jxl::CompressParams since some C++
128   // implementation decisions should be based on it: level 10 allows more
129   // features to be used.
130   uint32_t codestream_level;
131   bool store_jpeg_metadata;
132   jxl::CodecMetadata metadata;
133   std::vector<uint8_t> jpeg_metadata;
134 
135   // Wrote any output at all, so wrote the data before the first user added
136   // frame or box, such as signature, basic info, ICC profile or jpeg
137   // reconstruction box.
138   bool wrote_bytes;
139   jxl::CompressParams last_used_cparams;
140 
141   // Encoder wrote a jxlp (partial codestream) box, so any next codestream
142   // parts must also be written in jxlp boxes, a single jxlc box cannot be
143   // used. The counter is used for the 4-byte jxlp box index header.
144   size_t jxlp_counter;
145 
146   bool frames_closed;
147   bool boxes_closed;
148   bool basic_info_set;
149   bool color_encoding_set;
150 
151   // Takes the first frame in the input_queue, encodes it, and appends
152   // the bytes to the output_byte_queue.
153   JxlEncoderStatus RefillOutputByteQueue();
154 
MustUseContainerJxlEncoderStruct155   bool MustUseContainer() const {
156     return use_container || codestream_level != 5 || store_jpeg_metadata ||
157            use_boxes;
158   }
159 
160   // Appends the bytes of a JXL box header with the provided type and size to
161   // the end of the output_byte_queue. If unbounded is true, the size won't be
162   // added to the header and the box will be assumed to continue until EOF.
163   void AppendBoxHeader(const jxl::BoxType& type, size_t size, bool unbounded);
164 };
165 
166 struct JxlEncoderFrameSettingsStruct {
167   JxlEncoder* enc;
168   jxl::JxlEncoderFrameSettingsValues values;
169 };
170 
171 #endif  // LIB_JXL_ENCODE_INTERNAL_H_
172