#include "hdf5_stub.h"
#include <stdlib.h>
#include <assert.h>
#include "ebcc_codec.h"
#include "log.h"
#define H5Z_FILTER_EBCC 308
static size_t H5Z_filter_ebcc(unsigned int flags, size_t cd_nelmts, const unsigned int cd_values[], size_t nbytes, size_t *buf_size, void **buf);
const H5Z_class2_t H5Z_EBCC[1] = {{
H5Z_CLASS_T_VERS,
(H5Z_filter_t) H5Z_FILTER_EBCC,
1,
1,
"HDF5 EBCC filter L&L",
NULL,
NULL,
(H5Z_func_t) H5Z_filter_ebcc,
}};
EBCC_API H5PL_type_t H5PLget_plugin_type(void) { return H5PL_TYPE_FILTER; }
EBCC_API const void *H5PLget_plugin_info(void) { return H5Z_EBCC; }
float uint_ptr_to_float(const unsigned int *ptr) {
return *((float *) ptr);
}
float uint_ptr_to_double(const unsigned int *ptr) {
return *((double *) ptr);
}
EBCC_API void populate_config(codec_config_t *config, size_t cd_nelmts, const unsigned int cd_values[], size_t buf_size) {
if (cd_nelmts < 4) {
log_fatal("EBCC filter requires at least 4 configuration values, got %lu", cd_nelmts);
exit(1);
}
for (size_t i = 0; i < NDIMS; ++i) {
config->chunk_dims[i] = 0;
}
size_t tile_height = cd_values[0];
size_t tile_width = cd_values[1];
if (tile_height < EBCC_MIN_INTERNAL_IMAGE_DIM || tile_width < EBCC_MIN_INTERNAL_IMAGE_DIM ||
tile_height > EBCC_MAX_INTERNAL_IMAGE_DIM ||
tile_width > EBCC_MAX_INTERNAL_IMAGE_DIM) {
log_fatal("Tile size %lu x %lu is invalid, each dimension must be between %d and %d",
tile_height, tile_width, EBCC_MIN_INTERNAL_IMAGE_DIM, EBCC_MAX_INTERNAL_IMAGE_DIM);
exit(1);
}
size_t tile_size = tile_height * tile_width;
config->dims[0] = buf_size / sizeof(float);
if (config->dims[0] < tile_size) {
log_fatal("Buffer size %lu is smaller than the tile size %lu x %lu = %lu", config->dims[0], tile_height, tile_width, tile_size);
exit(1);
}
if (config->dims[0] % tile_size != 0) {
log_fatal("Buffer size %lu is not divisible by the tile size %lu x %lu = %lu", config->dims[0], tile_height, tile_width, tile_size);
exit(1);
}
for (size_t i = 0; i < 2; ++i) {
size_t cur = cd_values[i];
config->dims[0] /= cur;
config->dims[i + 1] = cur;
}
if (config->dims[1] != 0 && config->dims[0] > EBCC_MAX_INTERNAL_IMAGE_DIM / config->dims[1]) {
log_fatal("Flattened EBCC image height %lu x %lu exceeds the limit of %d",
config->dims[0], config->dims[1],
EBCC_MAX_INTERNAL_IMAGE_DIM);
exit(1);
}
config->base_cr = uint_ptr_to_float(&cd_values[2]);
config->residual_compression_type = (residual_t) cd_values[3];
switch (config->residual_compression_type) {
case NONE:
assert(cd_nelmts == 4);
break;
case MAX_ERROR:
case RELATIVE_ERROR:
assert(cd_nelmts == 5);
config->error = uint_ptr_to_float(&cd_values[4]);
break;
}
}
static size_t H5Z_filter_ebcc(unsigned int flags, size_t cd_nelmts, const unsigned int cd_values[], size_t nbytes, size_t *buf_size, void **buf) {
if (flags & H5Z_FLAG_REVERSE) {
float *out_buffer = NULL;
*buf_size = ebcc_decode(*buf, nbytes, &out_buffer);
free_buffer(*buf);
*buf = out_buffer;
return *buf_size;
} else {
codec_config_t config;
populate_config(&config, cd_nelmts, cd_values, *buf_size);
uint8_t *out_buffer = NULL;
*buf_size = ebcc_encode(*buf, &config, &out_buffer);
free_buffer(*buf);
*buf = out_buffer;
return *buf_size;
}
}