DYT/Tool/OpenSceneGraph-3.6.5/include/OpenEXR/openexr_encode.h

351 lines
12 KiB
C
Raw Permalink Normal View History

2024-12-24 23:49:36 +00:00
/*
** SPDX-License-Identifier: BSD-3-Clause
** Copyright Contributors to the OpenEXR Project.
*/
#ifndef OPENEXR_CORE_ENCODE_H
#define OPENEXR_CORE_ENCODE_H
#include "openexr_chunkio.h"
#include "openexr_coding.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @file */
/** Can be bit-wise or'ed into the decode_flags in the decode pipeline.
*
* Indicates that the sample count table should be encoded from an
* individual sample count list (n, m, o, ...), meaning it will have
* to compute the cumulative counts on the fly.
*
* Without this (i.e. a value of 0 in that bit), indicates the sample
* count table is already a cumulative list (n, n+m, n+m+o, ...),
* which is the on-disk representation.
*/
#define EXR_ENCODE_DATA_SAMPLE_COUNTS_ARE_INDIVIDUAL ((uint16_t) (1 << 0))
/** Can be bit-wise or'ed into the decode_flags in the decode pipeline.
*
* Indicates that the data in the channel pointers to encode from is not
* a direct pointer, but instead is a pointer-to-pointers. In this
* mode, the user_pixel_stride and user_line_stride are used to
* advance the pointer offsets for each pixel in the output, but the
* user_bytes_per_element and user_data_type are used to put
* (successive) entries into each destination.
*
* So each channel pointer must then point to an array of
* chunk.width * chunk.height pointers. If an entry is
* `NULL`, 0 samples will be placed in the output.
*
* If this is NOT set (0), the default packing routine assumes the
* data will be planar and contiguous (each channel is a separate
* memory block), ignoring user_line_stride and user_pixel_stride and
* advancing only by the sample counts and bytes per element.
*/
#define EXR_ENCODE_NON_IMAGE_DATA_AS_POINTERS ((uint16_t) (1 << 1))
/** Struct meant to be used on a per-thread basis for writing exr data.
*
* As should be obvious, this structure is NOT thread safe, but rather
* meant to be used by separate threads, which can all be accessing
* the same context concurrently.
*/
typedef struct _exr_encode_pipeline
{
/** Used for versioning the decode pipeline in the future
*
* \ref EXR_ENCODE_PIPELINE_INITIALIZER
*/
size_t pipe_size;
/** The output channel information for this chunk.
*
* User is expected to fill the channel pointers for the input
* channels. For writing, all channels must be initialized prior
* to using exr_encoding_choose_default_routines(). If a custom pack routine
* is written, that is up to the implementor.
*
* Describes the channel information. This information is
* allocated dynamically during exr_encoding_initialize().
*/
exr_coding_channel_info_t* channels;
int16_t channel_count;
/** Encode flags to control the behavior. */
uint16_t encode_flags;
/** Copy of the parameters given to the initialize/update for convenience. */
int part_index;
exr_const_context_t context;
exr_chunk_info_t chunk;
/** Can be used by the user to pass custom context data through
* the encode pipeline.
*/
void* encoding_user_data;
/** The packed buffer where individual channels have been put into here.
*
* If `NULL`, will be allocated during the run of the pipeline.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
void* packed_buffer;
/** Differing from the allocation size, the number of actual bytes */
uint64_t packed_bytes;
/** Used when re-using the same encode pipeline struct to know if
* chunk is changed size whether current buffer is large enough
*
* If `NULL`, will be allocated during the run of the pipeline.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
size_t packed_alloc_size;
/** For deep data. NB: the members NOT const because we need to
* temporarily swap it to xdr order and restore it (to avoid a
* duplicate buffer allocation).
*
* Depending on the flag set above, will be treated either as a
* cumulative list (n, n+m, n+m+o, ...), or an individual table
* (n, m, o, ...). */
int32_t* sample_count_table;
/** Allocated table size (to avoid re-allocations). Number of
* samples must always be width * height for the chunk.
*/
size_t sample_count_alloc_size;
/** Packed sample table (compressed, raw on disk representation)
* for deep or other non-image data.
*/
void* packed_sample_count_table;
/** Number of bytes to write (actual size) for the
* packed_sample_count_table.
*/
size_t packed_sample_count_bytes;
/** Allocated size (to avoid re-allocations) for the
* packed_sample_count_table.
*/
size_t packed_sample_count_alloc_size;
/** The compressed buffer, only needed for compressed files.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
void* compressed_buffer;
/** Must be filled in as the pipeline runs to inform the writing
* software about the compressed size of the chunk (if it is an
* uncompressed file or the compression would make the file
* larger, it is expected to be the packed_buffer)
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to zero here. Be cognizant of any
* custom allocators.
*/
size_t compressed_bytes;
/** Used when re-using the same encode pipeline struct to know if
* chunk is changed size whether current buffer is large enough.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to zero here. Be cognizant of any
* custom allocators.
*/
size_t compressed_alloc_size;
/** A scratch buffer for intermediate results.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
void* scratch_buffer_1;
/** Used when re-using the same encode pipeline struct to know if
* chunk is changed size whether current buffer is large enough.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
size_t scratch_alloc_size_1;
/** Some compression routines may need a second scratch buffer.
*
* If `NULL`, will be allocated during the run of the pipeline when
* needed.
*
* If the caller wishes to take control of the buffer, simple
* adopt the pointer and set it to `NULL` here. Be cognizant of any
* custom allocators.
*/
void* scratch_buffer_2;
/** Used when re-using the same encode pipeline struct to know if
* chunk is changed size whether current buffer is large enough.
*/
size_t scratch_alloc_size_2;
/** Enable a custom allocator for the different buffers (if
* encoding on a GPU). If `NULL`, will use the allocator from the
* context.
*/
void* (*alloc_fn) (exr_transcoding_pipeline_buffer_id_t, size_t);
/** Enable a custom allocator for the different buffers (if
* encoding on a GPU). If `NULL`, will use the allocator from the
* context.
*/
void (*free_fn) (exr_transcoding_pipeline_buffer_id_t, void*);
/** Function chosen based on the output layout of the channels of the part to
* decompress data.
*
* If the user has a custom method for the
* compression on this part, this can be changed after
* initialization.
*/
exr_result_t (*convert_and_pack_fn) (struct _exr_encode_pipeline* pipeline);
/** Function chosen based on the compression type of the part to
* compress data.
*
* If the user has a custom compression method for the compression
* type on this part, this can be changed after initialization.
*/
exr_result_t (*compress_fn) (struct _exr_encode_pipeline* pipeline);
/** This routine is used when waiting for other threads to finish
* writing previous chunks such that this thread can write this
* chunk. This is used for parts which have a specified chunk
* ordering (increasing/decreasing y) and the chunks can not be
* written randomly (as could be true for uncompressed).
*
* This enables the calling application to contribute thread time
* to other computation as needed, or just use something like
* pthread_yield().
*
* By default, this routine will be assigned to a function which
* returns an error, failing the encode immediately. In this way,
* it assumes that there is only one thread being used for
* writing.
*
* It is up to the user to provide an appropriate routine if
* performing multi-threaded writing.
*/
exr_result_t (*yield_until_ready_fn) (
struct _exr_encode_pipeline* pipeline);
/** Function chosen to write chunk data to the context.
*
* This is allowed to be overridden, but probably is not necessary
* in most scenarios.
*/
exr_result_t (*write_fn) (struct _exr_encode_pipeline* pipeline);
/** Small stash of channel info values. This is faster than calling
* malloc when the channel count in the part is small (RGBAZ),
* which is super common, however if there are a large number of
* channels, it will allocate space for that, so do not rely on
* this being used.
*/
exr_coding_channel_info_t _quick_chan_store[5];
} exr_encode_pipeline_t;
/** @brief Simple macro to initialize an empty decode pipeline. */
#define EXR_ENCODE_PIPELINE_INITIALIZER \
{ \
sizeof(exr_encode_pipeline_t), 0 \
}
/** Initialize the encoding pipeline structure with the channel info
* for the specified part based on the chunk to be written.
*
* NB: The encode_pipe->pack_and_convert_fn field will be `NULL` after this. If that
* stage is desired, initialize the channel output information and
* call exr_encoding_choose_default_routines().
*/
EXR_EXPORT
exr_result_t exr_encoding_initialize (
exr_const_context_t ctxt,
int part_index,
const exr_chunk_info_t* cinfo,
exr_encode_pipeline_t* encode_pipe);
/** Given an initialized encode pipeline, find an appropriate
* function to shuffle and convert data into the defined channel
* outputs.
*
* Calling this is not required if a custom routine will be used, or
* if just the raw decompressed data is desired.
*/
EXR_EXPORT
exr_result_t exr_encoding_choose_default_routines (
exr_const_context_t ctxt,
int part_index,
exr_encode_pipeline_t* encode_pipe);
/** Given a encode pipeline previously initialized, update it for the
* new chunk to be written.
*
* In this manner, memory buffers can be re-used to avoid continual
* malloc/free calls. Further, it allows the previous choices for
* the various functions to be quickly re-used.
*/
EXR_EXPORT
exr_result_t exr_encoding_update (
exr_const_context_t ctxt,
int part_index,
const exr_chunk_info_t* cinfo,
exr_encode_pipeline_t* encode_pipe);
/** Execute the encoding pipeline. */
EXR_EXPORT
exr_result_t exr_encoding_run (
exr_const_context_t ctxt,
int part_index,
exr_encode_pipeline_t* encode_pipe);
/** Free any intermediate memory in the encoding pipeline.
*
* This does NOT free any pointers referred to in the channel info
* areas, but rather only the intermediate buffers and memory needed
* for the structure itself.
*/
EXR_EXPORT
exr_result_t exr_encoding_destroy (
exr_const_context_t ctxt, exr_encode_pipeline_t* encode_pipe);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* OPENEXR_CORE_ENCODE_H */