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