From 410511e06d08e84ed79370f837eb1d6194fdd025 Mon Sep 17 00:00:00 2001
From: Dominik Loidolt <dominik.loidolt@univie.ac.at>
Date: Mon, 11 Mar 2024 14:28:48 +0100
Subject: [PATCH] Add chunk compression to cmp_tool

---
 meson.build         |   2 +-
 programs/cmp_io.c   | 176 ++++++++++++++++++--------------------------
 programs/cmp_io.h   |   3 +-
 programs/cmp_tool.c |  92 +++++++++++++++++++----
 4 files changed, 151 insertions(+), 122 deletions(-)

diff --git a/meson.build b/meson.build
index 6eadf1a..86680ee 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
 project('cmp_tool', 'c',
-  version : '0.12-b2',
+  version : '0.12-b3',
   meson_version : '>= 0.56',
   license : 'GPL-2.0',
   default_options : [
diff --git a/programs/cmp_io.c b/programs/cmp_io.c
index 90a933b..fd11008 100644
--- a/programs/cmp_io.c
+++ b/programs/cmp_io.c
@@ -31,6 +31,7 @@
 
 #include "cmp_io.h"
 #include <cmp_support.h>
+#include <cmp_chunk.h>
 #include <rdcu_cmd.h>
 #include <byteorder.h>
 #include <cmp_data_types.h>
@@ -65,6 +66,7 @@ static const struct {
 	{DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE, "DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE"},
 	{DATA_TYPE_F_CAM_OFFSET, "DATA_TYPE_F_CAM_OFFSET"},
 	{DATA_TYPE_F_CAM_BACKGROUND, "DATA_TYPE_F_CAM_BACKGROUND"},
+	{DATA_TYPE_CHUNK, "DATA_TYPE_CHUNK"},
 	{DATA_TYPE_UNKNOWN, "DATA_TYPE_UNKNOWN"}
 };
 
@@ -528,22 +530,31 @@ int cmp_mode_parse(const char *cmp_mode_str, enum cmp_mode *cmp_mode)
  * @param fp	FILE pointer
  * @param cfg	compression configuration structure holding the read in
  *		configuration
+ * @param par	chunk compression parameters structure holding the read in
+ *		chunk configuration
  *
  * @returns 0 on success, error otherwise
  */
 
-static int parse_cfg(FILE *fp, struct cmp_cfg *cfg)
+static int parse_cfg(FILE *fp, struct cmp_cfg *cfg, struct cmp_par *par)
 {
+#define chunk_parse_uint32_parmter(parmter)			\
+	if (!strcmp(token1, #parmter)) {			\
+		if (atoui32(token1, token2, &par->parmter))	\
+			return -1;				\
+		cfg->data_type = DATA_TYPE_CHUNK;		\
+		continue;					\
+}
 	char *token1, *token2;
 	char line[MAX_CONFIG_LINE];
 	enum {CMP_MODE, SAMPLES, BUFFER_LENGTH, LAST_ITEM};
 	int j, must_read_items[LAST_ITEM] = {0};
 
 	if (!fp)
-		return -1;
+		abort();
 
 	if (!cfg)
-		return -1;
+		abort();
 
 	while (fgets(line, sizeof(line), fp) != NULL) {
 		if (line[0] == '#' || line[0] == '\n')
@@ -576,6 +587,7 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg)
 			must_read_items[CMP_MODE] = 1;
 			if (cmp_mode_parse(token2, &cfg->cmp_mode))
 				return -1;
+			par->cmp_mode = cfg->cmp_mode;
 			continue;
 		}
 		if (!strcmp(token1, "golomb_par")) {
@@ -591,6 +603,7 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg)
 		if (!strcmp(token1, "model_value")) {
 			if (atoui32(token1, token2, &cfg->model_value))
 				return -1;
+			par->model_value = cfg->model_value;
 			continue;
 		}
 		if (!strcmp(token1, "round")) {
@@ -618,98 +631,7 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg)
 				return -1;
 			continue;
 		}
-		if (!strcmp(token1, "cmp_par_exp_flags")) {
-			if (atoui32(token1, token2, &cfg->cmp_par_exp_flags))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "spill_exp_flags")) {
-			if (atoui32(token1, token2, &cfg->spill_exp_flags))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "cmp_par_fx")) {
-			if (atoui32(token1, token2, &cfg->cmp_par_fx))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "spill_fx")) {
-			if (atoui32(token1, token2, &cfg->spill_fx))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "cmp_par_ncob")) {
-			if (atoui32(token1, token2, &cfg->cmp_par_ncob))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "spill_ncob")) {
-			if (atoui32(token1, token2, &cfg->spill_ncob))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "cmp_par_efx")) {
-			if (atoui32(token1, token2, &cfg->cmp_par_efx))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "spill_efx")) {
-			if (atoui32(token1, token2, &cfg->spill_efx))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "cmp_par_ecob")) {
-			if (atoui32(token1, token2, &cfg->cmp_par_ecob))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "spill_ecob")) {
-			if (atoui32(token1, token2, &cfg->spill_ecob))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "cmp_par_fx_cob_variance")) {
-			if (atoui32(token1, token2, &cfg->cmp_par_fx_cob_variance))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "spill_fx_cob_variance")) {
-			if (atoui32(token1, token2, &cfg->spill_fx_cob_variance))
-				return -1;
-			continue;
-		}
-#if 0
-		if (!strcmp(token1, "cmp_par_mean")) {
-			if (atoui32(token1, token2, &cfg->cmp_par_mean))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "spill_mean")) {
-			if (atoui32(token1, token2, &cfg->spill_mean))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "cmp_par_variance")) {
-			if (atoui32(token1, token2, &cfg->cmp_par_variance))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "spill_variance")) {
-			if (atoui32(token1, token2, &cfg->spill_variance))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "cmp_par_pixels_error")) {
-			if (atoui32(token1, token2, &cfg->cmp_par_pixels_error))
-				return -1;
-			continue;
-		}
-		if (!strcmp(token1, "spill_pixels_error")) {
-			if (atoui32(token1, token2, &cfg->spill_pixels_error))
-				return -1;
-			continue;
-		}
-#endif
+
 		if (!strcmp(token1, "rdcu_data_adr")) {
 			int i = sram_addr_to_int(token2);
 
@@ -766,18 +688,57 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg)
 			must_read_items[BUFFER_LENGTH] = 1;
 			continue;
 		}
+
+		/* chunk_parse_uint32_parmter(model_value); */
+		chunk_parse_uint32_parmter(lossy_par);
+
+		chunk_parse_uint32_parmter(nc_imagette);
+
+		chunk_parse_uint32_parmter(s_exp_flags);
+		chunk_parse_uint32_parmter(s_fx);
+		chunk_parse_uint32_parmter(s_ncob);
+		chunk_parse_uint32_parmter(s_efx);
+		chunk_parse_uint32_parmter(s_ecob);
+
+		chunk_parse_uint32_parmter(l_exp_flags);
+		chunk_parse_uint32_parmter(l_fx);
+		chunk_parse_uint32_parmter(l_ncob);
+		chunk_parse_uint32_parmter(l_efx);
+		chunk_parse_uint32_parmter(l_ecob);
+		chunk_parse_uint32_parmter(l_fx_cob_variance);
+
+		chunk_parse_uint32_parmter(saturated_imagette);
+
+		chunk_parse_uint32_parmter(nc_offset_mean);
+		chunk_parse_uint32_parmter(nc_offset_variance);
+		chunk_parse_uint32_parmter(nc_background_mean);
+		chunk_parse_uint32_parmter(nc_background_variance);
+		chunk_parse_uint32_parmter(nc_background_outlier_pixels);
+
+		chunk_parse_uint32_parmter(smearing_mean);
+		chunk_parse_uint32_parmter(smearing_variance_mean);
+		chunk_parse_uint32_parmter(smearing_outlier_pixels);
+
+		chunk_parse_uint32_parmter(fc_imagette);
+		chunk_parse_uint32_parmter(fc_offset_mean);
+		chunk_parse_uint32_parmter(fc_offset_variance);
+		chunk_parse_uint32_parmter(fc_background_mean);
+		chunk_parse_uint32_parmter(fc_background_variance);
+		chunk_parse_uint32_parmter(fc_background_outlier_pixels);
 	}
 
-	if (raw_mode_is_used(cfg->cmp_mode))
-		if (must_read_items[CMP_MODE] == 1 &&
-		    must_read_items[BUFFER_LENGTH] == 1)
-			return 0;
+	if (cfg->data_type != DATA_TYPE_CHUNK) {
+		if (raw_mode_is_used(cfg->cmp_mode))
+			if (must_read_items[CMP_MODE] == 1 &&
+			    must_read_items[BUFFER_LENGTH] == 1)
+				return 0;
 
-	for (j = 0; j < LAST_ITEM; j++) {
-		if (must_read_items[j] < 1) {
-			fprintf(stderr, "%s: Some parameters are missing. Check if the following parameters: cmp_mode, golomb_par, spill, samples and buffer_length are all set in the configuration file.\n",
-				PROGRAM_NAME);
-			return -1;
+		for (j = 0; j < LAST_ITEM; j++) {
+			if (must_read_items[j] < 1) {
+				fprintf(stderr, "%s: Some parameters are missing. Check if the following parameters: cmp_mode, golomb_par, spill, samples and buffer_length are all set in the configuration file.\n",
+					PROGRAM_NAME);
+				return -1;
+			}
 		}
 	}
 
@@ -791,12 +752,15 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg)
  * @param file_name	file containing the compression configuration file
  * @param cfg		compression configuration structure holding the read in
  *			configuration
+ * @param par		chunk compression parameters structure holding the read
+ *			in chunk configuration
  * @param verbose_en	print verbose output if not zero
  *
  * @returns 0 on success, error otherwise
  */
 
-int cmp_cfg_read(const char *file_name, struct cmp_cfg *cfg, int verbose_en)
+int cmp_cfg_read(const char *file_name, struct cmp_cfg *cfg, struct cmp_par *par,
+		 int verbose_en)
 {
 	int err;
 	FILE *fp;
@@ -820,7 +784,7 @@ int cmp_cfg_read(const char *file_name, struct cmp_cfg *cfg, int verbose_en)
 		return -1;
 	}
 
-	err = parse_cfg(fp, cfg);
+	err = parse_cfg(fp, cfg, par);
 	fclose(fp);
 	if (err)
 		return err;
diff --git a/programs/cmp_io.h b/programs/cmp_io.h
index 60c3910..c1f4e86 100644
--- a/programs/cmp_io.h
+++ b/programs/cmp_io.h
@@ -24,6 +24,7 @@
 #include <string.h>
 
 #include <cmp_support.h>
+#include <cmp_chunk.h>
 #include <cmp_entity.h>
 
 #define MAX_CONFIG_LINE 256
@@ -39,7 +40,7 @@
 
 void print_help(const char *program_name);
 
-int cmp_cfg_read(const char *file_name, struct cmp_cfg *cfg, int verbose_en);
+int cmp_cfg_read(const char *file_name, struct cmp_cfg *cfg, struct cmp_par *par, int verbose_en);
 int cmp_info_read(const char *file_name, struct cmp_info *info, int verbose_en);
 
 ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t buf_size, int flags);
diff --git a/programs/cmp_tool.c b/programs/cmp_tool.c
index 9560c9d..3dd5a9a 100644
--- a/programs/cmp_tool.c
+++ b/programs/cmp_tool.c
@@ -27,6 +27,7 @@
 #include "cmp_tool-config.h"
 #include "cmp_io.h"
 #include "cmp_icu.h"
+#include "cmp_chunk.h"
 #include "cmp_rdcu.h"
 #include "decmp.h"
 #include "cmp_guess.h"
@@ -48,6 +49,9 @@ static enum cmp_data_type parse_data_type(const char *data_type_str);
 static int guess_cmp_pars(struct cmp_cfg *cfg, const char *guess_cmp_mode,
 			  int guess_level);
 
+/* compress chunk data and write the results to files */
+static int compression_of_chunk(void *chunk, uint32_t size, void *model, struct cmp_par *chunk_par);
+
 /* compress the data and write the results to files */
 static int compression(struct cmp_cfg *cfg, struct cmp_info *info);
 
@@ -152,9 +156,12 @@ int main(int argc, char **argv)
 	struct cmp_entity *decomp_entity = NULL;
 	/* buffer containing the read in model */
 	uint16_t *input_model_buf = NULL;
+	/* size of the data to be compressed and the model of it */
+	uint32_t input_size;
 
 	struct cmp_info info = {0}; /* decompression information struct */
 	struct cmp_cfg cfg = {0}; /* compressor configuration struct */
+	struct cmp_par chunk_par = {0}; /* compressor parameters for chunk compression */
 
 	cfg.data_type = DATA_TYPE_IMAGETTE; /* use imagette as default data type */
 	cfg.max_used_bits = &MAX_USED_BITS_SAFE; /* define max_used_bits default */
@@ -327,12 +334,11 @@ int main(int argc, char **argv)
 
 	if (cmp_operation || guess_operation) {
 		ssize_t size;
-		uint32_t input_size;
 
 		if (cmp_operation) {
 			printf("## Starting the compression ##\n");
 			printf("Importing configuration file %s ... ", cfg_file_name);
-			error = cmp_cfg_read(cfg_file_name, &cfg, io_flags & CMP_IO_VERBOSE);
+			error = cmp_cfg_read(cfg_file_name, &cfg, &chunk_par, io_flags & CMP_IO_VERBOSE);
 			if (error)
 				goto fail;
 			printf("DONE\n");
@@ -342,20 +348,28 @@ int main(int argc, char **argv)
 
 		printf("Importing data file %s ... ", data_file_name);
 		/* count the samples in the data file when samples == 0 */
-		if (cfg.samples == 0) {
-			int32_t samples;
+		if (cfg.data_type != DATA_TYPE_CHUNK) {
+			if (cfg.samples == 0) {
+				int32_t samples;
+
+				size = read_file_data(data_file_name, cfg.data_type, NULL, 0, io_flags);
+				if (size <= 0 || size > UINT32_MAX) /* empty file is treated as an error */
+					goto fail;
+				samples = cmp_input_size_to_samples((uint32_t)size, cfg.data_type);
+				if (samples < 0)
+					goto fail;
+				cfg.samples = (uint32_t)samples;
+				printf("\nNo samples parameter set. Use samples = %u.\n... ", cfg.samples);
+			}
 
-			size = read_file_data(data_file_name, cfg.data_type, NULL, 0, io_flags);
+			input_size = cmp_cal_size_of_data(cfg.samples, cfg.data_type);
+		} else {
+			size  = read_file_data(data_file_name, cfg.data_type, NULL, 0, io_flags);
 			if (size <= 0 || size > UINT32_MAX) /* empty file is treated as an error */
 				goto fail;
-			samples = cmp_input_size_to_samples((uint32_t)size, cfg.data_type);
-			if (samples < 0)
-				goto fail;
-			cfg.samples = (uint32_t)samples;
-			printf("\nNo samples parameter set. Use samples = %u.\n... ", cfg.samples);
+			input_size = (uint32_t)size;
 		}
 
-		input_size = cmp_cal_size_of_data(cfg.samples, cfg.data_type);
 		cfg.input_buf = malloc(input_size);
 		if (!cfg.input_buf) {
 			fprintf(stderr, "%s: Error allocating memory for input data buffer.\n", PROGRAM_NAME);
@@ -456,7 +470,7 @@ int main(int argc, char **argv)
 
 		if (cmp_operation || guess_operation) {
 			data_type = cfg.data_type;
-			model_size = cmp_cal_size_of_data(cfg.samples, cfg.data_type);
+			model_size = input_size;
 		} else {
 			data_type = cmp_ent_get_data_type(decomp_entity);
 			model_size = cmp_ent_get_original_size(decomp_entity);
@@ -483,7 +497,11 @@ int main(int argc, char **argv)
 		if (error)
 			goto fail;
 	} else if (cmp_operation) {
-		error = compression(&cfg, &info);
+		if (cfg.data_type == DATA_TYPE_CHUNK)
+			error = compression_of_chunk(cfg.input_buf, input_size,
+						     input_model_buf, &chunk_par);
+		else
+			error = compression(&cfg, &info);
 		if (error)
 			goto fail;
 	} else {
@@ -502,7 +520,7 @@ int main(int argc, char **argv)
 		printf("Write updated model to file %s_upmodel.dat ... ", output_prefix);
 		if (cmp_operation) {
 			data_type = cfg.data_type;
-			model_size = cmp_cal_size_of_data(cfg.samples, data_type);
+			model_size = input_size;
 		} else {
 			data_type = cmp_ent_get_data_type(decomp_entity);
 			model_size = cmp_ent_get_original_size(decomp_entity);
@@ -705,6 +723,52 @@ static int cmp_gernate_rdcu_info(const struct cmp_cfg *cfg, int cmp_size_bit,
 }
 
 
+/**
+ * @brief compress chunk data and write the results to files
+ */
+
+static int compression_of_chunk(void *chunk, uint32_t size, void *model, struct cmp_par *chunk_par)
+{
+	uint32_t bound = compress_chunk_cmp_size_bound(chunk, size);
+	uint32_t *cmp_data;
+	int32_t cmp_size;
+	int error;
+
+	if (!bound)
+		return -1;
+	cmp_data = calloc(1, bound);
+	if (cmp_data == NULL) {
+		fprintf(stderr, "%s: Error allocating memory for output buffer.\n", PROGRAM_NAME);
+		return -1;
+	}
+
+	printf("Compress chunk data ... ");
+	cmp_size = compress_chunk(chunk, size, model, model,
+				  cmp_data, bound, chunk_par);
+
+	if (cmp_size < 0) {
+		if (cmp_size == CMP_ERROR_SMALL_BUF)
+			fprintf(stderr, "Error: The buffer for the compressed data is too small to hold the compressed data. Try a larger buffer_length parameter.\n");
+		free(cmp_data);
+		cmp_data = NULL;
+		printf("FAILED\n");
+		return -1;
+	}
+
+	printf("DONE\nWrite compressed data to file %s.cmp ... ", output_prefix);
+	error = write_data_to_file(cmp_data, (uint32_t)cmp_size, output_prefix,
+				   ".cmp", io_flags);
+	free(cmp_data);
+	cmp_data = NULL;
+	if (error) {
+		printf("FAILED\n");
+		return -1;
+	}
+	printf("DONE\n");
+	return 0;
+}
+
+
 /**
  * @brief compress the data and write the results to files
  */
-- 
GitLab