335 lines
12 KiB
C
335 lines
12 KiB
C
|
/*
|
||
|
** SPDX-License-Identifier: BSD-3-Clause
|
||
|
** Copyright Contributors to the OpenEXR Project.
|
||
|
*/
|
||
|
|
||
|
#ifndef OPENEXR_CORE_DECODE_H
|
||
|
#define OPENEXR_CORE_DECODE_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 decoded to a an
|
||
|
* individual sample count list (n, m, o, ...), with an extra int at
|
||
|
* the end containing the total samples.
|
||
|
*
|
||
|
* Without this (i.e. a value of 0 in that bit), indicates the sample
|
||
|
* count table should be decoded to a cumulative list (n, n+m, n+m+o,
|
||
|
* ...), which is the on-disk representation.
|
||
|
*/
|
||
|
#define EXR_DECODE_SAMPLE_COUNTS_AS_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 decode to 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 pointer (if not `NULL`).
|
||
|
*
|
||
|
* So each channel pointer must then point to an array of
|
||
|
* chunk.width * chunk.height pointers.
|
||
|
*
|
||
|
* With this, you can only extract desired pixels (although all the
|
||
|
* pixels must be initially decompressed) to handle such operations
|
||
|
* like proxying where you might want to read every other pixel.
|
||
|
*
|
||
|
* If this is NOT set (0), the default unpacking routine assumes the
|
||
|
* data will be planar and contiguous (each channel is a separate
|
||
|
* memory block), ignoring user_line_stride and user_pixel_stride.
|
||
|
*/
|
||
|
#define EXR_DECODE_NON_IMAGE_DATA_AS_POINTERS ((uint16_t) (1 << 1))
|
||
|
|
||
|
/**
|
||
|
* When reading non-image data (i.e. deep), only read the sample table.
|
||
|
*/
|
||
|
#define EXR_DECODE_SAMPLE_DATA_ONLY ((uint16_t) (1 << 2))
|
||
|
|
||
|
/**
|
||
|
* Struct meant to be used on a per-thread basis for reading 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_decode_pipeline
|
||
|
{
|
||
|
/** Used for versioning the decode pipeline in the future.
|
||
|
*
|
||
|
* \ref EXR_DECODE_PIPELINE_INITIALIZER
|
||
|
*/
|
||
|
size_t pipe_size;
|
||
|
|
||
|
/** The output channel information for this chunk.
|
||
|
*
|
||
|
* User is expected to fill the channel pointers for the desired
|
||
|
* output channels (any that are `NULL` will be skipped) if you are
|
||
|
* going to use exr_decoding_choose_default_routines(). If all that is
|
||
|
* desired is to read and decompress the data, this can be left
|
||
|
* uninitialized.
|
||
|
*
|
||
|
* Describes the channel information. This information is
|
||
|
* allocated dynamically during exr_decoding_initialize().
|
||
|
*/
|
||
|
exr_coding_channel_info_t* channels;
|
||
|
int16_t channel_count;
|
||
|
|
||
|
/** Decode flags to control the behavior. */
|
||
|
uint16_t decode_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;
|
||
|
|
||
|
/** How many lines of the chunk to skip filling, assumes the
|
||
|
* pointer is at the beginning of data (i.e. includes this
|
||
|
* skip so does not need to be adjusted
|
||
|
*/
|
||
|
int32_t user_line_begin_skip;
|
||
|
|
||
|
/** How many lines of the chunk to ignore at the end, assumes the
|
||
|
* output is meant to be N lines smaller
|
||
|
*/
|
||
|
int32_t user_line_end_ignore;
|
||
|
|
||
|
/** How many bytes were actually decoded when items compressed */
|
||
|
uint64_t bytes_decompressed;
|
||
|
|
||
|
/** Can be used by the user to pass custom context data through
|
||
|
* the decode pipeline.
|
||
|
*/
|
||
|
void* decoding_user_data;
|
||
|
|
||
|
/** The (compressed) buffer.
|
||
|
*
|
||
|
* 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;
|
||
|
|
||
|
/** Used when re-using the same decode pipeline struct to know if
|
||
|
* chunk is changed size whether current buffer is large enough.
|
||
|
*/
|
||
|
size_t packed_alloc_size;
|
||
|
|
||
|
/** The decompressed buffer (unpacked_size from the chunk block
|
||
|
* info), but still packed into storage order, 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* unpacked_buffer;
|
||
|
|
||
|
/** Used when re-using the same decode pipeline struct to know if
|
||
|
* chunk is changed size whether current buffer is large enough.
|
||
|
*/
|
||
|
size_t unpacked_alloc_size;
|
||
|
|
||
|
/** For deep or other non-image data: packed sample table
|
||
|
* (compressed, raw on disk representation).
|
||
|
*/
|
||
|
void* packed_sample_count_table;
|
||
|
size_t packed_sample_count_alloc_size;
|
||
|
|
||
|
/** Usable, native sample count table. Depending on the flag set
|
||
|
* above, will be decoded to either a cumulative list (n, n+m,
|
||
|
* n+m+o, ...), or an individual table (n, m, o, ...). As an
|
||
|
* optimization, if the latter individual count table is chosen,
|
||
|
* an extra int32_t will be allocated at the end of the table to
|
||
|
* contain the total count of samples, so the table will be n+1
|
||
|
* samples in size.
|
||
|
*/
|
||
|
int32_t* sample_count_table;
|
||
|
size_t sample_count_alloc_size;
|
||
|
|
||
|
/** A scratch buffer of unpacked_size 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 decode pipeline struct to know if
|
||
|
* chunk is changed size whether current buffer is large enough.
|
||
|
*/
|
||
|
size_t scratch_alloc_size_1;
|
||
|
|
||
|
/** Some decompression routines may need a second scratch buffer (zlib).
|
||
|
*
|
||
|
* 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 decode 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
|
||
|
* decoding 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
|
||
|
* decoding on a GPU). If `NULL`, will use the allocator from the
|
||
|
* context.
|
||
|
*/
|
||
|
void (*free_fn) (exr_transcoding_pipeline_buffer_id_t, void*);
|
||
|
|
||
|
/** Function chosen to read chunk data from the context.
|
||
|
*
|
||
|
* Initialized to a default generic read routine, may be updated
|
||
|
* based on channel information when
|
||
|
* exr_decoding_choose_default_routines() is called. This is done such that
|
||
|
* if the file is uncompressed and the output channel data is
|
||
|
* planar and the same type, the read function can read straight
|
||
|
* into the output channels, getting closer to a zero-copy
|
||
|
* operation. Otherwise a more traditional read, decompress, then
|
||
|
* unpack pipeline will be used with a default reader.
|
||
|
*
|
||
|
* This is allowed to be overridden, but probably is not necessary
|
||
|
* in most scenarios.
|
||
|
*/
|
||
|
exr_result_t (*read_fn) (struct _exr_decode_pipeline* pipeline);
|
||
|
|
||
|
/** Function chosen based on the compression type of the part to
|
||
|
* decompress data.
|
||
|
*
|
||
|
* If the user has a custom decompression method for the
|
||
|
* compression on this part, this can be changed after
|
||
|
* initialization.
|
||
|
*
|
||
|
* If only compressed data is desired, then assign this to `NULL`
|
||
|
* after initialization.
|
||
|
*/
|
||
|
exr_result_t (*decompress_fn) (struct _exr_decode_pipeline* pipeline);
|
||
|
|
||
|
/** Function which can be provided if you have bespoke handling for
|
||
|
* non-image data and need to re-allocate the data to handle the
|
||
|
* about-to-be unpacked data.
|
||
|
*
|
||
|
* If left `NULL`, will assume the memory pointed to by the channel
|
||
|
* pointers is sufficient.
|
||
|
*/
|
||
|
exr_result_t (*realloc_nonimage_data_fn) (
|
||
|
struct _exr_decode_pipeline* pipeline);
|
||
|
|
||
|
/** Function chosen based on the output layout of the channels of the part to
|
||
|
* decompress data.
|
||
|
*
|
||
|
* This will be `NULL` after initialization, until the user
|
||
|
* specifies a custom routine, or initializes the channel data and
|
||
|
* calls exr_decoding_choose_default_routines().
|
||
|
*
|
||
|
* If only compressed data is desired, then leave or assign this
|
||
|
* to `NULL` after initialization.
|
||
|
*/
|
||
|
exr_result_t (*unpack_and_convert_fn) (
|
||
|
struct _exr_decode_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_decode_pipeline_t;
|
||
|
|
||
|
/** @brief Simple macro to initialize an empty decode pipeline. */
|
||
|
#define EXR_DECODE_PIPELINE_INITIALIZER \
|
||
|
{ \
|
||
|
sizeof(exr_decode_pipeline_t), 0 \
|
||
|
}
|
||
|
|
||
|
/** Initialize the decoding pipeline structure with the channel info
|
||
|
* for the specified part, and the first block to be read.
|
||
|
*
|
||
|
* NB: The decode->unpack_and_convert_fn field will be `NULL` after this. If that
|
||
|
* stage is desired, initialize the channel output information and
|
||
|
* call exr_decoding_choose_default_routines().
|
||
|
*/
|
||
|
EXR_EXPORT
|
||
|
exr_result_t exr_decoding_initialize (
|
||
|
exr_const_context_t ctxt,
|
||
|
int part_index,
|
||
|
const exr_chunk_info_t* cinfo,
|
||
|
exr_decode_pipeline_t* decode);
|
||
|
|
||
|
/** Given an initialized decode pipeline, find appropriate functions
|
||
|
* to read and shuffle/convert data into the defined channel outputs.
|
||
|
*
|
||
|
* Calling this is not required if custom routines will be used, or if
|
||
|
* just the raw compressed data is desired. Although in that scenario,
|
||
|
* it is probably easier to just read the chunk directly using
|
||
|
* exr_read_chunk().
|
||
|
*/
|
||
|
EXR_EXPORT
|
||
|
exr_result_t exr_decoding_choose_default_routines (
|
||
|
exr_const_context_t ctxt, int part_index, exr_decode_pipeline_t* decode);
|
||
|
|
||
|
/** Given a decode pipeline previously initialized, update it for the
|
||
|
* new chunk to be read.
|
||
|
*
|
||
|
* 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_decoding_update (
|
||
|
exr_const_context_t ctxt,
|
||
|
int part_index,
|
||
|
const exr_chunk_info_t* cinfo,
|
||
|
exr_decode_pipeline_t* decode);
|
||
|
|
||
|
/** Execute the decoding pipeline. */
|
||
|
EXR_EXPORT
|
||
|
exr_result_t exr_decoding_run (
|
||
|
exr_const_context_t ctxt, int part_index, exr_decode_pipeline_t* decode);
|
||
|
|
||
|
/** Free any intermediate memory in the decoding 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_decoding_destroy (exr_const_context_t ctxt, exr_decode_pipeline_t* decode);
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
} /* extern "C" */
|
||
|
#endif
|
||
|
|
||
|
#endif /* OPENEXR_CORE_DECODE_H */
|