encode_internal.h (23504B)
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 <jxl/cms_interface.h> 11 #include <jxl/codestream_header.h> 12 #include <jxl/encode.h> 13 #include <jxl/memory_manager.h> 14 #include <jxl/types.h> 15 16 #include <algorithm> 17 #include <array> 18 #include <cstddef> 19 #include <cstdint> 20 #include <cstring> 21 #include <functional> 22 #include <map> 23 #include <memory> 24 #include <string> 25 #include <utility> 26 #include <vector> 27 28 #include "lib/jxl/base/c_callback_support.h" 29 #include "lib/jxl/base/common.h" 30 #include "lib/jxl/base/compiler_specific.h" 31 #include "lib/jxl/base/data_parallel.h" 32 #include "lib/jxl/base/status.h" 33 #include "lib/jxl/enc_aux_out.h" 34 #include "lib/jxl/enc_fast_lossless.h" 35 #include "lib/jxl/enc_params.h" 36 #include "lib/jxl/image_metadata.h" 37 #include "lib/jxl/jpeg/jpeg_data.h" 38 #include "lib/jxl/memory_manager_internal.h" 39 #include "lib/jxl/padded_bytes.h" 40 41 namespace jxl { 42 43 /* Frame index box 'jxli' will start with Varint() for 44 NF: has type Varint(): number of frames listed in the index. 45 TNUM: has type u32: numerator of tick unit. 46 TDEN: has type u32: denominator of tick unit. Value 0 means the file is 47 ill-formed. per frame i listed: OFFi: has type Varint(): offset of start byte of 48 this frame compared to start byte of previous frame from this index in the JPEG 49 XL codestream. For the first frame, this is the offset from the first byte of 50 the JPEG XL codestream. Ti: has type Varint(): duration in ticks between the 51 start of this frame and the start of the next frame in the index. If this is the 52 last frame in the index, this is the duration in ticks between the start of this 53 frame and the end of the stream. A tick lasts TNUM / TDEN seconds. Fi: has type 54 Varint(): amount of frames the next frame in the index occurs after this frame. 55 If this is the last frame in the index, this is the amount of frames after this 56 frame in the remainder of the stream. Only frames that are presented by the 57 decoder are counted for this purpose, this excludes frames that are not intended 58 for display but for compositing with other frames, such as frames that aren't 59 the last frame with a duration of 0 ticks. 60 61 All the frames listed in jxli are keyframes and the first frame is 62 present in the list. 63 There shall be either zero or one Frame Index boxes in a JPEG XL file. 64 The offsets OFFi per frame are given as bytes in the codestream, not as 65 bytes in the file format using the box structure. This means if JPEG XL Partial 66 Codestream boxes are used, the offset is counted within the concatenated 67 codestream, bytes from box headers or non-codestream boxes are not counted. 68 */ 69 70 typedef struct JxlEncoderFrameIndexBoxEntryStruct { 71 bool to_be_indexed; 72 uint32_t duration; 73 uint64_t OFFi; 74 } JxlEncoderFrameIndexBoxEntry; 75 76 typedef struct JxlEncoderFrameIndexBoxStruct { 77 // We always need to record the first frame entry, so presence of the 78 // first entry alone is not an indication if it was requested to be 79 // stored. 80 bool index_box_requested_through_api = false; 81 82 int64_t NF() const { return entries.size(); } 83 bool StoreFrameIndexBox() { 84 for (auto e : entries) { 85 if (e.to_be_indexed) { 86 return true; 87 } 88 } 89 return false; 90 } 91 int32_t TNUM = 1; 92 int32_t TDEN = 1000; 93 94 std::vector<JxlEncoderFrameIndexBoxEntry> entries; 95 96 // That way we can ensure that every index box will have the first frame. 97 // If the API user decides to mark it as an indexed frame, we call 98 // the AddFrame again, this time with requested. 99 void AddFrame(uint64_t OFFi, uint32_t duration, bool to_be_indexed) { 100 // We call AddFrame to every frame. 101 // Recording the first frame is required by the standard. 102 // Knowing the last frame is required, since the last indexed frame 103 // needs to know how many frames until the end. 104 // To be able to tell how many frames there are between each index 105 // entry we just record every frame here. 106 if (entries.size() == 1) { 107 if (OFFi == entries[0].OFFi) { 108 // API use for the first frame, let's clear the already recorded first 109 // frame. 110 entries.clear(); 111 } 112 } 113 JxlEncoderFrameIndexBoxEntry e; 114 e.to_be_indexed = to_be_indexed; 115 e.OFFi = OFFi; 116 e.duration = duration; 117 entries.push_back(e); 118 } 119 } JxlEncoderFrameIndexBox; 120 121 // The encoder options (such as quality, compression speed, ...) for a single 122 // frame, but not encoder-wide options such as box-related options. 123 typedef struct JxlEncoderFrameSettingsValuesStruct { 124 // lossless is a separate setting from cparams because it is a combination 125 // setting that overrides multiple settings inside of cparams. 126 bool lossless; 127 CompressParams cparams; 128 JxlFrameHeader header; 129 std::vector<JxlBlendInfo> extra_channel_blend_info; 130 std::string frame_name; 131 JxlBitDepth image_bit_depth; 132 bool frame_index_box = false; 133 jxl::AuxOut* aux_out = nullptr; 134 } JxlEncoderFrameSettingsValues; 135 136 typedef std::array<uint8_t, 4> BoxType; 137 138 // Utility function that makes a BoxType from a string literal. The string must 139 // have 4 characters, a 5th null termination character is optional. 140 constexpr BoxType MakeBoxType(const char* type) { 141 return BoxType( 142 {{static_cast<uint8_t>(type[0]), static_cast<uint8_t>(type[1]), 143 static_cast<uint8_t>(type[2]), static_cast<uint8_t>(type[3])}}); 144 } 145 146 constexpr std::array<unsigned char, 32> kContainerHeader = { 147 0, 0, 0, 0xc, 'J', 'X', 'L', ' ', 0xd, 0xa, 0x87, 148 0xa, 0, 0, 0, 0x14, 'f', 't', 'y', 'p', 'j', 'x', 149 'l', ' ', 0, 0, 0, 0, 'j', 'x', 'l', ' '}; 150 151 constexpr std::array<unsigned char, 8> kLevelBoxHeader = {0, 0, 0, 0x9, 152 'j', 'x', 'l', 'l'}; 153 154 static JXL_INLINE size_t BitsPerChannel(JxlDataType data_type) { 155 switch (data_type) { 156 case JXL_TYPE_UINT8: 157 return 8; 158 case JXL_TYPE_UINT16: 159 return 16; 160 case JXL_TYPE_FLOAT: 161 return 32; 162 case JXL_TYPE_FLOAT16: 163 return 16; 164 default: 165 return 0; // signals unhandled JxlDataType 166 } 167 } 168 169 static JXL_INLINE size_t BytesPerPixel(JxlPixelFormat format) { 170 return format.num_channels * BitsPerChannel(format.data_type) / 8; 171 } 172 173 using ScopedInputBuffer = 174 std::unique_ptr<const void, std::function<void(const void*)>>; 175 176 static JXL_INLINE ScopedInputBuffer 177 GetColorBuffer(JxlChunkedFrameInputSource& input, size_t xpos, size_t ypos, 178 size_t xsize, size_t ysize, size_t* row_offset) { 179 return ScopedInputBuffer( 180 input.get_color_channel_data_at(input.opaque, xpos, ypos, xsize, ysize, 181 row_offset), 182 [&input](const void* p) { input.release_buffer(input.opaque, p); }); 183 } 184 185 static JXL_INLINE ScopedInputBuffer GetExtraChannelBuffer( 186 JxlChunkedFrameInputSource& input, size_t ec_index, size_t xpos, 187 size_t ypos, size_t xsize, size_t ysize, size_t* row_offset) { 188 return ScopedInputBuffer( 189 input.get_extra_channel_data_at(input.opaque, ec_index, xpos, ypos, xsize, 190 ysize, row_offset), 191 [&input](const void* p) { input.release_buffer(input.opaque, p); }); 192 } 193 194 // Common adapter for an existing frame input source or a whole-image input 195 // buffer or a parsed JPEG file. 196 class JxlEncoderChunkedFrameAdapter { 197 public: 198 JxlEncoderChunkedFrameAdapter(size_t xs, size_t ys, size_t num_extra_channels) 199 : xsize(xs), ysize(ys), channels_(1 + num_extra_channels) {} 200 201 void SetInputSource(JxlChunkedFrameInputSource input_source) { 202 input_source_ = input_source; 203 has_input_source_ = true; 204 } 205 206 bool SetFromBuffer(size_t channel, const uint8_t* buffer, size_t size, 207 JxlPixelFormat format) { 208 if (channel >= channels_.size()) return false; 209 if (!channels_[channel].SetFromBuffer(buffer, size, format, xsize, ysize)) { 210 return false; 211 } 212 if (channel > 0) channels_[channel].CopyBuffer(); 213 return true; 214 } 215 216 // TODO(szabadka) Move instead of copy. 217 void SetJPEGData(const jpeg::JPEGData jpeg_data) { 218 jpeg_data_ = jpeg_data; 219 has_jpeg_data_ = true; 220 } 221 bool IsJPEG() const { return has_jpeg_data_; } 222 223 jpeg::JPEGData&& TakeJPEGData() { 224 JXL_ASSERT(has_jpeg_data_); 225 return std::move(jpeg_data_); 226 } 227 228 JxlChunkedFrameInputSource GetInputSource() { 229 if (has_input_source_) { 230 return input_source_; 231 } 232 return JxlChunkedFrameInputSource{ 233 this, 234 METHOD_TO_C_CALLBACK( 235 &JxlEncoderChunkedFrameAdapter::GetColorChannelsPixelFormat), 236 METHOD_TO_C_CALLBACK( 237 &JxlEncoderChunkedFrameAdapter::GetColorChannelDataAt), 238 METHOD_TO_C_CALLBACK( 239 &JxlEncoderChunkedFrameAdapter::GetExtraChannelPixelFormat), 240 METHOD_TO_C_CALLBACK( 241 &JxlEncoderChunkedFrameAdapter::GetExtraChannelDataAt), 242 METHOD_TO_C_CALLBACK( 243 &JxlEncoderChunkedFrameAdapter::ReleaseCurrentData)}; 244 } 245 246 bool CopyBuffers() { 247 if (has_input_source_) { 248 JxlPixelFormat format{4, JXL_TYPE_UINT8, JXL_NATIVE_ENDIAN, 0}; 249 input_source_.get_color_channels_pixel_format(input_source_.opaque, 250 &format); 251 size_t row_offset; 252 { 253 auto buffer = 254 GetColorBuffer(input_source_, 0, 0, xsize, ysize, &row_offset); 255 if (!buffer) return false; 256 channels_[0].CopyFromBuffer(buffer.get(), format, xsize, ysize, 257 row_offset); 258 } 259 for (size_t ec = 0; ec + 1 < channels_.size(); ++ec) { 260 input_source_.get_extra_channel_pixel_format(input_source_.opaque, ec, 261 &format); 262 auto buffer = GetExtraChannelBuffer(input_source_, ec, 0, 0, xsize, 263 ysize, &row_offset); 264 if (!buffer) continue; 265 channels_[1 + ec].CopyFromBuffer(buffer.get(), format, xsize, ysize, 266 row_offset); 267 } 268 has_input_source_ = false; 269 } else { 270 channels_[0].CopyBuffer(); 271 } 272 return true; 273 } 274 275 bool StreamingInput() const { return has_input_source_; } 276 277 const size_t xsize; 278 const size_t ysize; 279 280 private: 281 void GetColorChannelsPixelFormat(JxlPixelFormat* pixel_format) { 282 *pixel_format = channels_[0].format_; 283 } 284 285 const void* GetColorChannelDataAt(size_t xpos, size_t ypos, size_t xsize, 286 size_t ysize, size_t* row_offset) { 287 return channels_[0].GetDataAt(xpos, ypos, xsize, ysize, row_offset); 288 } 289 290 void GetExtraChannelPixelFormat(size_t ec_index, 291 JxlPixelFormat* pixel_format) { 292 JXL_ASSERT(1 + ec_index < channels_.size()); 293 *pixel_format = channels_[1 + ec_index].format_; 294 } 295 296 const void* GetExtraChannelDataAt(size_t ec_index, size_t xpos, size_t ypos, 297 size_t xsize, size_t ysize, 298 size_t* row_offset) { 299 JXL_ASSERT(1 + ec_index < channels_.size()); 300 return channels_[1 + ec_index].GetDataAt(xpos, ypos, xsize, ysize, 301 row_offset); 302 } 303 304 void ReleaseCurrentData(const void* buffer) { 305 // No dynamic memory is allocated in GetColorChannelDataAt or 306 // GetExtraChannelDataAt. Therefore, no cleanup is required here. 307 } 308 309 JxlChunkedFrameInputSource input_source_ = {}; 310 bool has_input_source_ = false; 311 jpeg::JPEGData jpeg_data_; 312 bool has_jpeg_data_ = false; 313 struct Channel { 314 const uint8_t* buffer_ = nullptr; 315 size_t buffer_size_; 316 JxlPixelFormat format_; 317 size_t xsize_; 318 size_t ysize_; 319 size_t bytes_per_pixel_; 320 size_t stride_; 321 std::vector<uint8_t> copy_; 322 323 void SetFormatAndDimensions(JxlPixelFormat format, size_t xsize, 324 size_t ysize) { 325 format_ = format; 326 xsize_ = xsize; 327 ysize_ = ysize; 328 bytes_per_pixel_ = BytesPerPixel(format_); 329 const size_t last_row_size = xsize_ * bytes_per_pixel_; 330 const size_t align = format_.align; 331 stride_ = (align > 1 ? jxl::DivCeil(last_row_size, align) * align 332 : last_row_size); 333 } 334 335 bool SetFromBuffer(const uint8_t* buffer, size_t size, 336 JxlPixelFormat format, size_t xsize, size_t ysize) { 337 SetFormatAndDimensions(format, xsize, ysize); 338 buffer_ = buffer; 339 buffer_size_ = size; 340 const size_t min_buffer_size = 341 stride_ * (ysize_ - 1) + xsize_ * bytes_per_pixel_; 342 return min_buffer_size <= size; 343 } 344 345 void CopyFromBuffer(const void* buffer, JxlPixelFormat format, size_t xsize, 346 size_t ysize, size_t row_offset) { 347 SetFormatAndDimensions(format, xsize, ysize); 348 buffer_ = nullptr; 349 copy_.resize(ysize * stride_); 350 for (size_t y = 0; y < ysize; ++y) { 351 memcpy(copy_.data() + y * stride_, 352 reinterpret_cast<const uint8_t*>(buffer) + y * row_offset, 353 stride_); 354 } 355 } 356 357 void CopyBuffer() { 358 if (buffer_) { 359 copy_ = std::vector<uint8_t>(buffer_, buffer_ + buffer_size_); 360 buffer_ = nullptr; 361 } 362 } 363 364 const void* GetDataAt(size_t xpos, size_t ypos, size_t xsize, size_t ysize, 365 size_t* row_offset) const { 366 const uint8_t* buffer = copy_.empty() ? buffer_ : copy_.data(); 367 JXL_ASSERT(ypos + ysize <= ysize_); 368 JXL_ASSERT(xpos + xsize <= xsize_); 369 JXL_ASSERT(buffer); 370 *row_offset = stride_; 371 return buffer + ypos * stride_ + xpos * bytes_per_pixel_; 372 } 373 }; 374 std::vector<Channel> channels_; 375 }; 376 377 struct JxlEncoderQueuedFrame { 378 JxlEncoderFrameSettingsValues option_values; 379 JxlEncoderChunkedFrameAdapter frame_data; 380 std::vector<uint8_t> ec_initialized; 381 }; 382 383 struct JxlEncoderQueuedBox { 384 BoxType type; 385 std::vector<uint8_t> contents; 386 bool compress_box; 387 }; 388 389 using FJXLFrameUniquePtr = 390 std::unique_ptr<JxlFastLosslessFrameState, 391 decltype(&JxlFastLosslessFreeFrameState)>; 392 393 // Either a frame, or a box, not both. 394 // Can also be a FJXL frame. 395 struct JxlEncoderQueuedInput { 396 explicit JxlEncoderQueuedInput(const JxlMemoryManager& memory_manager) 397 : frame(nullptr, jxl::MemoryManagerDeleteHelper(&memory_manager)), 398 box(nullptr, jxl::MemoryManagerDeleteHelper(&memory_manager)) {} 399 MemoryManagerUniquePtr<JxlEncoderQueuedFrame> frame; 400 MemoryManagerUniquePtr<JxlEncoderQueuedBox> box; 401 FJXLFrameUniquePtr fast_lossless_frame = {nullptr, 402 JxlFastLosslessFreeFrameState}; 403 }; 404 405 static constexpr size_t kSmallBoxHeaderSize = 8; 406 static constexpr size_t kLargeBoxHeaderSize = 16; 407 static constexpr size_t kLargeBoxContentSizeThreshold = 408 0x100000000ull - kSmallBoxHeaderSize; 409 410 size_t WriteBoxHeader(const jxl::BoxType& type, size_t size, bool unbounded, 411 bool force_large_box, uint8_t* output); 412 413 // Appends a JXL container box header with given type, size, and unbounded 414 // properties to output. 415 template <typename T> 416 void AppendBoxHeader(const jxl::BoxType& type, size_t size, bool unbounded, 417 T* output) { 418 size_t current_size = output->size(); 419 output->resize(current_size + kLargeBoxHeaderSize); 420 size_t header_size = 421 WriteBoxHeader(type, size, unbounded, /*force_large_box=*/false, 422 output->data() + current_size); 423 output->resize(current_size + header_size); 424 } 425 426 } // namespace jxl 427 428 class JxlOutputProcessorBuffer; 429 430 class JxlEncoderOutputProcessorWrapper { 431 friend class JxlOutputProcessorBuffer; 432 433 public: 434 JxlEncoderOutputProcessorWrapper() = default; 435 explicit JxlEncoderOutputProcessorWrapper(JxlEncoderOutputProcessor processor) 436 : external_output_processor_( 437 jxl::make_unique<JxlEncoderOutputProcessor>(processor)) {} 438 439 bool HasAvailOut() const { return avail_out_ != nullptr; } 440 441 // Caller can never overwrite a previously-written buffer. Asking for a buffer 442 // with `min_size` such that `position + min_size` overlaps with a 443 // previously-written buffer is invalid. 444 jxl::StatusOr<JxlOutputProcessorBuffer> GetBuffer(size_t min_size, 445 size_t requested_size = 0); 446 447 void Seek(size_t pos); 448 449 void SetFinalizedPosition(); 450 451 size_t CurrentPosition() const { return position_; } 452 453 bool SetAvailOut(uint8_t** next_out, size_t* avail_out); 454 455 bool WasStopRequested() const { return stop_requested_; } 456 bool OutputProcessorSet() const { 457 return external_output_processor_ != nullptr; 458 } 459 bool HasOutputToWrite() const { 460 return output_position_ < finalized_position_; 461 } 462 463 void CopyOutput(std::vector<uint8_t>& output, uint8_t* next_out, 464 size_t& avail_out); 465 466 private: 467 void ReleaseBuffer(size_t bytes_used); 468 469 // Tries to write all the bytes up to the finalized position. 470 void FlushOutput(); 471 472 bool AppendBufferToExternalProcessor(void* data, size_t count); 473 474 struct InternalBuffer { 475 // Bytes in the range `[output_position_ - start_of_the_buffer, 476 // written_bytes)` need to be flushed out. 477 size_t written_bytes = 0; 478 // If data has been buffered, it is stored in `owned_data`. 479 jxl::PaddedBytes owned_data; 480 }; 481 482 // Invariant: `internal_buffers_` does not contain chunks that are entirely 483 // below the output position. 484 std::map<size_t, InternalBuffer> internal_buffers_; 485 486 uint8_t** next_out_ = nullptr; 487 size_t* avail_out_ = nullptr; 488 // Where the next GetBuffer call will write bytes to. 489 size_t position_ = 0; 490 // The position of the last SetFinalizedPosition call. 491 size_t finalized_position_ = 0; 492 // Either the position of the `external_output_processor_` or the position 493 // `next_out_` points to. 494 size_t output_position_ = 0; 495 496 bool stop_requested_ = false; 497 bool has_buffer_ = false; 498 499 std::unique_ptr<JxlEncoderOutputProcessor> external_output_processor_; 500 }; 501 502 class JxlOutputProcessorBuffer { 503 public: 504 size_t size() const { return size_; }; 505 uint8_t* data() { return data_; } 506 507 JxlOutputProcessorBuffer(uint8_t* buffer, size_t size, size_t bytes_used, 508 JxlEncoderOutputProcessorWrapper* wrapper) 509 : data_(buffer), 510 size_(size), 511 bytes_used_(bytes_used), 512 wrapper_(wrapper) {} 513 ~JxlOutputProcessorBuffer() { release(); } 514 515 JxlOutputProcessorBuffer(const JxlOutputProcessorBuffer&) = delete; 516 JxlOutputProcessorBuffer(JxlOutputProcessorBuffer&& other) noexcept 517 : JxlOutputProcessorBuffer(other.data_, other.size_, other.bytes_used_, 518 other.wrapper_) { 519 other.data_ = nullptr; 520 other.size_ = 0; 521 } 522 523 void advance(size_t count) { 524 JXL_ASSERT(count <= size_); 525 data_ += count; 526 size_ -= count; 527 bytes_used_ += count; 528 } 529 530 void release() { 531 if (this->data_) { 532 wrapper_->ReleaseBuffer(bytes_used_); 533 } 534 data_ = nullptr; 535 size_ = 0; 536 } 537 538 void append(const void* data, size_t count) { 539 memcpy(data_, data, count); 540 advance(count); 541 } 542 543 template <typename T> 544 void append(const T& data) { 545 static_assert(sizeof(*std::begin(data)) == 1, "Cannot append non-bytes"); 546 append(&*std::begin(data), std::end(data) - std::begin(data)); 547 } 548 549 JxlOutputProcessorBuffer& operator=(const JxlOutputProcessorBuffer&) = delete; 550 JxlOutputProcessorBuffer& operator=( 551 JxlOutputProcessorBuffer&& other) noexcept { 552 data_ = other.data_; 553 size_ = other.size_; 554 wrapper_ = other.wrapper_; 555 return *this; 556 } 557 558 private: 559 uint8_t* data_; 560 size_t size_; 561 size_t bytes_used_; 562 JxlEncoderOutputProcessorWrapper* wrapper_; 563 }; 564 565 template <typename T> 566 jxl::Status AppendData(JxlEncoderOutputProcessorWrapper& output_processor, 567 const T& data) { 568 size_t size = std::end(data) - std::begin(data); 569 size_t written = 0; 570 while (written < size) { 571 JXL_ASSIGN_OR_RETURN(auto buffer, 572 output_processor.GetBuffer(1, size - written)); 573 size_t n = std::min(size - written, buffer.size()); 574 buffer.append(data.data() + written, n); 575 written += n; 576 } 577 return jxl::OkStatus(); 578 } 579 580 // Internal use only struct, can only be initialized correctly by 581 // JxlEncoderCreate. 582 struct JxlEncoderStruct { 583 JxlMemoryManager memory_manager; 584 jxl::MemoryManagerUniquePtr<jxl::ThreadPool> thread_pool{ 585 nullptr, jxl::MemoryManagerDeleteHelper(&memory_manager)}; 586 std::vector<jxl::MemoryManagerUniquePtr<JxlEncoderFrameSettings>> 587 encoder_options; 588 589 size_t num_queued_frames; 590 size_t num_queued_boxes; 591 std::vector<jxl::JxlEncoderQueuedInput> input_queue; 592 JxlEncoderOutputProcessorWrapper output_processor; 593 594 // How many codestream bytes have been written, i.e., 595 // content of jxlc and jxlp boxes. Frame index box jxli 596 // requires position indices to point to codestream bytes, 597 // so we need to keep track of the total of flushed or queue 598 // codestream bytes. These bytes may be in a single jxlc box 599 // or across multiple jxlp boxes. 600 size_t codestream_bytes_written_end_of_frame; 601 jxl::JxlEncoderFrameIndexBox frame_index_box; 602 603 JxlCmsInterface cms; 604 bool cms_set; 605 606 // Force using the container even if not needed 607 bool use_container; 608 // User declared they will add metadata boxes 609 bool use_boxes; 610 611 // TODO(lode): move level into jxl::CompressParams since some C++ 612 // implementation decisions should be based on it: level 10 allows more 613 // features to be used. 614 bool store_jpeg_metadata; 615 int32_t codestream_level; 616 jxl::CodecMetadata metadata; 617 std::vector<uint8_t> jpeg_metadata; 618 619 jxl::CompressParams last_used_cparams; 620 JxlBasicInfo basic_info; 621 622 JxlEncoderError error = JxlEncoderError::JXL_ENC_ERR_OK; 623 624 // Encoder wrote a jxlp (partial codestream) box, so any next codestream 625 // parts must also be written in jxlp boxes, a single jxlc box cannot be 626 // used. The counter is used for the 4-byte jxlp box index header. 627 size_t jxlp_counter; 628 629 // Wrote any output at all, so wrote the data before the first user added 630 // frame or box, such as signature, basic info, ICC profile or jpeg 631 // reconstruction box. 632 bool wrote_bytes; 633 634 bool frames_closed; 635 bool boxes_closed; 636 bool basic_info_set; 637 bool color_encoding_set; 638 bool intensity_target_set; 639 bool allow_expert_options = false; 640 int brotli_effort = -1; 641 642 // Takes the first frame in the input_queue, encodes it, and appends 643 // the bytes to the output_byte_queue. 644 jxl::Status ProcessOneEnqueuedInput(); 645 646 bool MustUseContainer() const { 647 return use_container || (codestream_level != 5 && codestream_level != -1) || 648 store_jpeg_metadata || use_boxes; 649 } 650 651 // `write_box` must never seek before the position the output wrapper was at 652 // the moment of the call, and must leave the output wrapper such that its 653 // position is one byte past the end of the written box. 654 template <typename WriteBox> 655 jxl::Status AppendBox(const jxl::BoxType& type, bool unbounded, 656 size_t box_max_size, const WriteBox& write_box); 657 658 template <typename BoxContents> 659 jxl::Status AppendBoxWithContents(const jxl::BoxType& type, 660 const BoxContents& contents); 661 }; 662 663 struct JxlEncoderFrameSettingsStruct { 664 JxlEncoder* enc; 665 jxl::JxlEncoderFrameSettingsValues values; 666 }; 667 668 struct JxlEncoderStatsStruct { 669 jxl::AuxOut aux_out; 670 }; 671 672 #endif // LIB_JXL_ENCODE_INTERNAL_H_