1 /* 2 ** SPDX-License-Identifier: BSD-3-Clause 3 ** Copyright Contributors to the OpenEXR Project. 4 */ 5 6 #ifndef OPENEXR_CORE_ENCODE_H 7 #define OPENEXR_CORE_ENCODE_H 8 9 #include "openexr_chunkio.h" 10 #include "openexr_coding.h" 11 12 #ifdef __cplusplus 13 extern "C" { 14 #endif 15 16 /** @file */ 17 18 /** Can be bit-wise or'ed into the decode_flags in the decode pipeline. 19 * 20 * Indicates that the sample count table should be encoded from an 21 * individual sample count list (n, m, o, ...), meaning it will have 22 * to compute the cumulative counts on the fly. 23 * 24 * Without this (i.e. a value of 0 in that bit), indicates the sample 25 * count table is already a cumulative list (n, n+m, n+m+o, ...), 26 * which is the on-disk representation. 27 */ 28 #define EXR_ENCODE_DATA_SAMPLE_COUNTS_ARE_INDIVIDUAL ((uint16_t) (1 << 0)) 29 30 /** Can be bit-wise or'ed into the decode_flags in the decode pipeline. 31 * 32 * Indicates that the data in the channel pointers to encode from is not 33 * a direct pointer, but instead is a pointer-to-pointers. In this 34 * mode, the user_pixel_stride and user_line_stride are used to 35 * advance the pointer offsets for each pixel in the output, but the 36 * user_bytes_per_element and user_data_type are used to put 37 * (successive) entries into each destination. 38 * 39 * So each channel pointer must then point to an array of 40 * chunk.width * chunk.height pointers. If an entry is 41 * `NULL`, 0 samples will be placed in the output. 42 * 43 * If this is NOT set (0), the default packing routine assumes the 44 * data will be planar and contiguous (each channel is a separate 45 * memory block), ignoring user_line_stride and user_pixel_stride and 46 * advancing only by the sample counts and bytes per element. 47 */ 48 #define EXR_ENCODE_NON_IMAGE_DATA_AS_POINTERS ((uint16_t) (1 << 1)) 49 50 /** Struct meant to be used on a per-thread basis for writing exr data. 51 * 52 * As should be obvious, this structure is NOT thread safe, but rather 53 * meant to be used by separate threads, which can all be accessing 54 * the same context concurrently. 55 */ 56 typedef struct _exr_encode_pipeline 57 { 58 /** The output channel information for this chunk. 59 * 60 * User is expected to fill the channel pointers for the input 61 * channels. For writing, all channels must be initialized prior 62 * to using exr_encoding_choose_default_routines(). If a custom pack routine 63 * is written, that is up to the implementor. 64 * 65 * Describes the channel information. This information is 66 * allocated dynamically during exr_encoding_initialize(). 67 */ 68 exr_coding_channel_info_t* channels; 69 int16_t channel_count; 70 71 /** Encode flags to control the behavior. */ 72 uint16_t encode_flags; 73 74 /** Copy of the parameters given to the initialize/update for convenience. */ 75 int part_index; 76 exr_const_context_t context; 77 exr_chunk_info_t chunk; 78 79 /** Can be used by the user to pass custom context data through 80 * the encode pipeline. 81 */ 82 void* encoding_user_data; 83 84 /** The packed buffer where individual channels have been put into here. 85 * 86 * If `NULL`, will be allocated during the run of the pipeline. 87 * 88 * If the caller wishes to take control of the buffer, simple 89 * adopt the pointer and set it to `NULL` here. Be cognizant of any 90 * custom allocators. 91 */ 92 void* packed_buffer; 93 94 /** Differing from the allocation size, the number of actual bytes */ 95 uint64_t packed_bytes; 96 97 /** Used when re-using the same encode pipeline struct to know if 98 * chunk is changed size whether current buffer is large enough 99 * 100 * If `NULL`, will be allocated during the run of the pipeline. 101 * 102 * If the caller wishes to take control of the buffer, simple 103 * adopt the pointer and set it to `NULL` here. Be cognizant of any 104 * custom allocators. 105 */ 106 size_t packed_alloc_size; 107 108 /** For deep data. NB: the members NOT const because we need to 109 * temporarily swap it to xdr order and restore it (to avoid a 110 * duplicate buffer allocation). 111 * 112 * Depending on the flag set above, will be treated either as a 113 * cumulative list (n, n+m, n+m+o, ...), or an individual table 114 * (n, m, o, ...). */ 115 int32_t* sample_count_table; 116 117 /** Allocated table size (to avoid re-allocations). Number of 118 * samples must always be width * height for the chunk. 119 */ 120 size_t sample_count_alloc_size; 121 122 /** Packed sample table (compressed, raw on disk representation) 123 * for deep or other non-image data. 124 */ 125 void* packed_sample_count_table; 126 127 /** Number of bytes to write (actual size) for the 128 * packed_sample_count_table. 129 */ 130 size_t packed_sample_count_bytes; 131 132 /** Allocated size (to avoid re-allocations) for the 133 * packed_sample_count_table. 134 */ 135 size_t packed_sample_count_alloc_size; 136 137 /** The compressed buffer, only needed for compressed files. 138 * 139 * If `NULL`, will be allocated during the run of the pipeline when 140 * needed. 141 * 142 * If the caller wishes to take control of the buffer, simple 143 * adopt the pointer and set it to `NULL` here. Be cognizant of any 144 * custom allocators. 145 */ 146 void* compressed_buffer; 147 148 /** Must be filled in as the pipeline runs to inform the writing 149 * software about the compressed size of the chunk (if it is an 150 * uncompressed file or the compression would make the file 151 * larger, it is expected to be the packed_buffer) 152 * 153 * If the caller wishes to take control of the buffer, simple 154 * adopt the pointer and set it to zero here. Be cognizant of any 155 * custom allocators. 156 */ 157 size_t compressed_bytes; 158 159 /** Used when re-using the same encode pipeline struct to know if 160 * chunk is changed size whether current buffer is large enough. 161 * 162 * If `NULL`, will be allocated during the run of the pipeline when 163 * needed. 164 * 165 * If the caller wishes to take control of the buffer, simple 166 * adopt the pointer and set it to zero here. Be cognizant of any 167 * custom allocators. 168 */ 169 size_t compressed_alloc_size; 170 171 /** A scratch buffer for intermediate results. 172 * 173 * If `NULL`, will be allocated during the run of the pipeline when 174 * needed. 175 * 176 * If the caller wishes to take control of the buffer, simple 177 * adopt the pointer and set it to `NULL` here. Be cognizant of any 178 * custom allocators. 179 */ 180 void* scratch_buffer_1; 181 182 /** Used when re-using the same encode pipeline struct to know if 183 * chunk is changed size whether current buffer is large enough. 184 * 185 * If `NULL`, will be allocated during the run of the pipeline when 186 * needed. 187 * 188 * If the caller wishes to take control of the buffer, simple 189 * adopt the pointer and set it to `NULL` here. Be cognizant of any 190 * custom allocators. 191 */ 192 size_t scratch_alloc_size_1; 193 194 /** Some compression routines may need a second scratch buffer. 195 * 196 * If `NULL`, will be allocated during the run of the pipeline when 197 * needed. 198 * 199 * If the caller wishes to take control of the buffer, simple 200 * adopt the pointer and set it to `NULL` here. Be cognizant of any 201 * custom allocators. 202 */ 203 void* scratch_buffer_2; 204 205 /** Used when re-using the same encode pipeline struct to know if 206 * chunk is changed size whether current buffer is large enough. 207 */ 208 size_t scratch_alloc_size_2; 209 210 /** Enable a custom allocator for the different buffers (if 211 * encoding on a GPU). If `NULL`, will use the allocator from the 212 * context. 213 */ 214 void* (*alloc_fn) (exr_transcoding_pipeline_buffer_id_t, size_t); 215 216 /** Enable a custom allocator for the different buffers (if 217 * encoding on a GPU). If `NULL`, will use the allocator from the 218 * context. 219 */ 220 void (*free_fn) (exr_transcoding_pipeline_buffer_id_t, void*); 221 222 /** Function chosen based on the output layout of the channels of the part to 223 * decompress data. 224 * 225 * If the user has a custom method for the 226 * compression on this part, this can be changed after 227 * initialization. 228 */ 229 exr_result_t (*convert_and_pack_fn) (struct _exr_encode_pipeline* pipeline); 230 231 /** Function chosen based on the compression type of the part to 232 * compress data. 233 * 234 * If the user has a custom compression method for the compression 235 * type on this part, this can be changed after initialization. 236 */ 237 exr_result_t (*compress_fn) (struct _exr_encode_pipeline* pipeline); 238 239 /** This routine is used when waiting for other threads to finish 240 * writing previous chunks such that this thread can write this 241 * chunk. This is used for parts which have a specified chunk 242 * ordering (increasing/decreasing y) and the chunks can not be 243 * written randomly (as could be true for uncompressed). 244 * 245 * This enables the calling application to contribute thread time 246 * to other computation as needed, or just use something like 247 * pthread_yield(). 248 * 249 * By default, this routine will be assigned to a function which 250 * returns an error, failing the encode immediately. In this way, 251 * it assumes that there is only one thread being used for 252 * writing. 253 * 254 * It is up to the user to provide an appropriate routine if 255 * performing multi-threaded writing. 256 */ 257 exr_result_t (*yield_until_ready_fn) ( 258 struct _exr_encode_pipeline* pipeline); 259 260 /** Function chosen to write chunk data to the context. 261 * 262 * This is allowed to be overridden, but probably is not necessary 263 * in most scenarios. 264 */ 265 exr_result_t (*write_fn) (struct _exr_encode_pipeline* pipeline); 266 267 /** Small stash of channel info values. This is faster than calling 268 * malloc when the channel count in the part is small (RGBAZ), 269 * which is super common, however if there are a large number of 270 * channels, it will allocate space for that, so do not rely on 271 * this being used. 272 */ 273 exr_coding_channel_info_t _quick_chan_store[5]; 274 } exr_encode_pipeline_t; 275 276 /** @brief Simple macro to initialize an empty decode pipeline. */ 277 #define EXR_ENCODE_PIPELINE_INITIALIZER \ 278 { \ 279 0 \ 280 } 281 282 /** Initialize the encoding pipeline structure with the channel info 283 * for the specified part based on the chunk to be written. 284 * 285 * NB: The encode_pipe->pack_and_convert_fn field will be `NULL` after this. If that 286 * stage is desired, initialize the channel output information and 287 * call exr_encoding_choose_default_routines(). 288 */ 289 EXR_EXPORT 290 exr_result_t exr_encoding_initialize ( 291 exr_const_context_t ctxt, 292 int part_index, 293 const exr_chunk_info_t* cinfo, 294 exr_encode_pipeline_t* encode_pipe); 295 296 /** Given an initialized encode pipeline, find an appropriate 297 * function to shuffle and convert data into the defined channel 298 * outputs. 299 * 300 * Calling this is not required if a custom routine will be used, or 301 * if just the raw decompressed data is desired. 302 */ 303 EXR_EXPORT 304 exr_result_t exr_encoding_choose_default_routines ( 305 exr_const_context_t ctxt, 306 int part_index, 307 exr_encode_pipeline_t* encode_pipe); 308 309 /** Given a encode pipeline previously initialized, update it for the 310 * new chunk to be written. 311 * 312 * In this manner, memory buffers can be re-used to avoid continual 313 * malloc/free calls. Further, it allows the previous choices for 314 * the various functions to be quickly re-used. 315 */ 316 EXR_EXPORT 317 exr_result_t exr_encoding_update ( 318 exr_const_context_t ctxt, 319 int part_index, 320 const exr_chunk_info_t* cinfo, 321 exr_encode_pipeline_t* encode_pipe); 322 323 /** Execute the encoding pipeline. */ 324 EXR_EXPORT 325 exr_result_t exr_encoding_run ( 326 exr_const_context_t ctxt, 327 int part_index, 328 exr_encode_pipeline_t* encode_pipe); 329 330 /** Free any intermediate memory in the encoding pipeline. 331 * 332 * This does NOT free any pointers referred to in the channel info 333 * areas, but rather only the intermediate buffers and memory needed 334 * for the structure itself. 335 */ 336 EXR_EXPORT 337 exr_result_t exr_encoding_destroy ( 338 exr_const_context_t ctxt, exr_encode_pipeline_t* encode_pipe); 339 340 #ifdef __cplusplus 341 } /* extern "C" */ 342 #endif 343 344 #endif /* OPENEXR_CORE_ENCODE_H */ 345