summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrimio <vasi.vilvoiu@gmail.com>2019-01-08 13:52:23 +0200
committerrimio <vasi.vilvoiu@gmail.com>2019-01-08 13:52:23 +0200
commita7d5e7ca20c959b739d80f96362f326a5848cdb3 (patch)
tree5fcc392e5e2b6f425bf3ea756801b7aa9fb81b43
parent83608e80322642e681918a647ef54a67e7bb15a3 (diff)
Image management
-rw-r--r--src/encoder.c34
-rw-r--r--src/libsstv.template.h116
-rw-r--r--src/sstv.c143
-rw-r--r--src/tools/sstv-encode.cpp18
-rw-r--r--test/test-image.bmpbin6220922 -> 952442 bytes
5 files changed, 295 insertions, 16 deletions
diff --git a/src/encoder.c b/src/encoder.c
index a670a11..4fa059a 100644
--- a/src/encoder.c
+++ b/src/encoder.c
@@ -12,8 +12,12 @@
* Encoder context
*/
typedef struct {
- /* common encoder stuff */
+ /* input image */
+ sstv_image_t image;
+
+ /* output configuration */
sstv_mode_t mode;
+ size_t sample_rate;
} sstv_encoder_context_t;
/* default encoder contexts, for when no allocation/deallocation routines are provided */
@@ -22,7 +26,7 @@ static uint64_t default_encoder_context_usage = 0x0;
sstv_error_t
-sstv_create_encoder(sstv_mode_t mode, uint8_t *image, size_t sample_rate, void **out_ctx)
+sstv_create_encoder(void **out_ctx, sstv_image_t image, sstv_mode_t mode, size_t sample_rate)
{
sstv_encoder_context_t *ctx = NULL;
@@ -31,12 +35,30 @@ sstv_create_encoder(sstv_mode_t mode, uint8_t *image, size_t sample_rate, void *
return SSTV_BAD_PARAMETER;
}
+ /* check image properties */
+ {
+ size_t w, h;
+ sstv_image_format_t fmt;
+ sstv_error_t rc;
+
+ rc = sstv_get_mode_image_props(mode, &w, &h, &fmt);
+ if (rc != SSTV_OK) {
+ return rc;
+ }
+ if (w != image.width || h != image.height) {
+ return SSTV_BAD_RESOLUTION;
+ }
+ if (fmt != image.format) {
+ return SSTV_BAD_FORMAT;
+ }
+ }
+
/* create context */
if (sstv_malloc_user) {
/* user allocator */
ctx = (sstv_encoder_context_t *) sstv_malloc_user(sizeof(sstv_encoder_context_t));
if (!ctx) {
- return SSTV_BAD_USER_ALLOC;
+ return SSTV_ALLOC_FAIL;
}
} else {
size_t i;
@@ -55,7 +77,9 @@ sstv_create_encoder(sstv_mode_t mode, uint8_t *image, size_t sample_rate, void *
}
/* initialize context */
+ ctx->image = image;
ctx->mode = mode;
+ ctx->sample_rate = sample_rate;
/* set output */
*out_ctx = ctx;
@@ -69,6 +93,10 @@ sstv_delete_encoder(void *ctx)
{
size_t i;
+ if (!ctx) {
+ return SSTV_BAD_PARAMETER;
+ }
+
/* check default contexts */
for (i = 0; i < SSTV_DEFAULT_ENCODER_CONTEXT_COUNT; i++) {
if (ctx == default_encoder_context+i) {
diff --git a/src/libsstv.template.h b/src/libsstv.template.h
index fdaad3d..2a22474 100644
--- a/src/libsstv.template.h
+++ b/src/libsstv.template.h
@@ -39,6 +39,11 @@ typedef enum {
SSTV_BAD_USER_ALLOC = 101,
SSTV_BAD_USER_DEALLOC = 102,
SSTV_BAD_PARAMETER = 103,
+ SSTV_BAD_MODE = 104,
+ SSTV_BAD_FORMAT = 105,
+ SSTV_BAD_RESOLUTION = 106,
+
+ SSTV_ALLOC_FAIL = 200,
/* Encoder return codes */
SSTV_ENCODE_SUCCESSFUL = 1000,
@@ -50,13 +55,12 @@ typedef enum {
* SSTV modes
*/
typedef enum {
-
/* PD modes */
- SSTV_PD90,
- SSTV_PD120,
- SSTV_PD160,
- SSTV_PD180,
- SSTV_PD240,
+ SSTV_MODE_PD90,
+ SSTV_MODE_PD120,
+ SSTV_MODE_PD160,
+ SSTV_MODE_PD180,
+ SSTV_MODE_PD240
} sstv_mode_t;
/*
@@ -66,11 +70,107 @@ typedef void* (*sstv_malloc_t)(size_t);
typedef void (*sstv_free_t)(void *);
/*
- * Routines
+ * Image format
+ */
+typedef enum {
+ /* grayscale */
+ SSTV_FORMAT_Y,
+
+ /* YCbCr */
+ SSTV_FORMAT_YCBCR,
+
+ /* RGB */
+ SSTV_FORMAT_RGB
+} sstv_image_format_t;
+
+/*
+ * Image container
+ */
+typedef struct {
+ /* image properties */
+ size_t width;
+ size_t height;
+ sstv_image_format_t format;
+
+ /* image buffer */
+ uint8_t *buffer;
+} sstv_image_t;
+
+
+/*
+ * Initialize the library.
+ * alloc_func(in): memory allocation function (e.g. malloc)
+ * dealloc_func(in): memory deallocation function (e.g. free)
+ * returns: error code
+ *
+ * NOTE: Call to this function is optional. If no allocation/deallocation
+ * routines are provided then the library will provide limited functionality.
*/
extern sstv_error_t sstv_init(sstv_malloc_t alloc_func, sstv_free_t dealloc_func);
-extern sstv_error_t sstv_create_encoder(sstv_mode_t mode, uint8_t *image, size_t sample_rate, void **out_ctx);
+/*
+ * Retrieve the image properties for a supported SSTV mode.
+ * mode(in): desired SSTV mode
+ * width(out): width of image
+ * height(out): height of image
+ * format(out): pixel format
+ * returns: error code
+ */
+extern sstv_error_t sstv_get_mode_image_props(sstv_mode_t mode, size_t *width, size_t *height, sstv_image_format_t *format);
+
+/*
+ * Create an image given an SSTV mode.
+ * out_img(out): pointer to an image structure to initialize
+ * mode(in): desired SSTV mode
+ * returns: error code
+ *
+ * NOTE: This function allocates the pixel buffer, so it requires a valid call
+ * to sstv_init().
+ * NOTE: The resulting image must be deleted using sstv_delete_image() once it
+ * goes out of scope (i.e. after the encoder is deleted).
+ */
+extern sstv_error_t sstv_create_image_from_mode(sstv_image_t *out_img, sstv_mode_t mode);
+
+/*
+ * Create an image given image properties.
+ * out_img(out): pointer to an image structure to initialize
+ * w(in): width
+ * h(in): height
+ * format(in): pixel format
+ * returns: error code
+ *
+ * NOTE: This function allocates the pixel buffer, so it requires a valid call
+ * to sstv_init().
+ * NOTE: The resulting image must be deleted using sstv_delete_image() once it
+ * goes out of scope (i.e. after the encoder is deleted).
+ */
+extern sstv_error_t sstv_create_image_from_props(sstv_image_t *out_img, size_t w, size_t h, sstv_image_format_t format);
+
+/*
+ * Pack an image into an image structure, given properties and buffer.
+ * out_img(out): pointer to an image structure to initialize
+ * width(in): width
+ * height(in): height
+ * format(in): pixel format
+ * buffer(in): pixel buffer
+ * returns: error code
+ *
+ * NOTE: Pixel buffer is managed by user. Do NOT call sstv_delete_image() on
+ * resulting image.
+ */
+extern sstv_error_t sstv_pack_image(sstv_image_t *out_img, size_t width, size_t height, sstv_image_format_t format, uint8_t *buffer);
+
+/*
+ * Deletes an image.
+ * img(img): pointer to an image structure to delete
+ * returns: error code
+ *
+ * NOTE: This function deallocates the pixel buffer, so it requires a valid
+ * call to sstv_init().
+ */
+extern sstv_error_t sstv_delete_image(sstv_image_t *img);
+
+extern sstv_error_t sstv_create_encoder(void **out_ctx, sstv_image_t image, sstv_mode_t mode, size_t sample_rate);
extern sstv_error_t sstv_delete_encoder(void *ctx);
extern sstv_error_t sstv_encode(void *ctx, uint8_t *buffer, size_t buffer_size);
diff --git a/src/sstv.c b/src/sstv.c
index e91ae2b..25fe0be 100644
--- a/src/sstv.c
+++ b/src/sstv.c
@@ -22,4 +22,147 @@ sstv_init(sstv_malloc_t alloc_func, sstv_free_t dealloc_func)
sstv_malloc_user = alloc_func;
sstv_free_user = dealloc_func;
return SSTV_OK;
+}
+
+sstv_error_t
+sstv_get_mode_image_props(sstv_mode_t mode, size_t *width, size_t *height, sstv_image_format_t *format)
+{
+ switch (mode) {
+ /* PD modes */
+ case SSTV_MODE_PD90:
+ if (width) *width = 320;
+ if (height) *height = 256;
+ if (format) *format = SSTV_FORMAT_YCBCR;
+ break;
+
+ case SSTV_MODE_PD120:
+ if (width) *width = 640;
+ if (height) *height = 496;
+ if (format) *format = SSTV_FORMAT_YCBCR;
+ break;
+
+ case SSTV_MODE_PD160:
+ if (width) *width = 512;
+ if (height) *height = 400;
+ if (format) *format = SSTV_FORMAT_YCBCR;
+ break;
+
+ case SSTV_MODE_PD180:
+ if (width) *width = 640;
+ if (height) *height = 496;
+ if (format) *format = SSTV_FORMAT_YCBCR;
+ break;
+
+ case SSTV_MODE_PD240:
+ if (width) *width = 640;
+ if (height) *height = 496;
+ if (format) *format = SSTV_FORMAT_YCBCR;
+ break;
+
+ default:
+ return SSTV_BAD_MODE;
+ }
+
+ return SSTV_OK;
+}
+
+sstv_error_t
+sstv_create_image_from_mode(sstv_image_t *out_img, sstv_mode_t mode)
+{
+ size_t w, h;
+ sstv_image_format_t fmt;
+ sstv_error_t rc;
+
+ rc = sstv_get_mode_image_props(mode, &w, &h, &fmt);
+ if (rc != SSTV_OK) {
+ return rc;
+ }
+
+ return sstv_create_image_from_props(out_img, w, h, fmt);
+}
+
+sstv_error_t
+sstv_create_image_from_props(sstv_image_t *out_img, size_t w, size_t h, sstv_image_format_t format)
+{
+ size_t bsize;
+
+ if (!out_img) {
+ return SSTV_BAD_PARAMETER;
+ }
+
+ /* function needs memory allocator */
+ if (!sstv_malloc_user) {
+ return SSTV_BAD_USER_ALLOC;
+ }
+
+ /* element size */
+ switch (format) {
+ case SSTV_FORMAT_Y:
+ bsize = 1;
+ break;
+
+ case SSTV_FORMAT_YCBCR:
+ case SSTV_FORMAT_RGB:
+ bsize = 3;
+ break;
+
+ default:
+ return SSTV_BAD_FORMAT;
+ }
+
+ /* compute total size */
+ bsize *= w * h;
+
+ /* allocate buffer */
+ out_img->buffer = (uint8_t *)sstv_malloc_user(bsize);
+ if (!out_img->buffer) {
+ return SSTV_ALLOC_FAIL;
+ }
+
+ /* keep image specs */
+ out_img->width = w;
+ out_img->height = h;
+ out_img->format = format;
+
+ /* done */
+ return SSTV_OK;
+}
+
+sstv_error_t
+sstv_pack_image(sstv_image_t *out_img, size_t width, size_t height, sstv_image_format_t format, uint8_t *buffer)
+{
+ if (!out_img || !buffer) {
+ return SSTV_BAD_PARAMETER;
+ }
+
+ /* package image */
+ out_img->width = width;
+ out_img->height = height;
+ out_img->format = format;
+ out_img->buffer = buffer;
+
+ /* done */
+ return SSTV_OK;
+}
+
+sstv_error_t
+sstv_delete_image(sstv_image_t *img)
+{
+ if (!img) {
+ return SSTV_BAD_PARAMETER;
+ }
+
+ /* free buffer if allocated */
+ if (!sstv_free_user) {
+ return SSTV_BAD_USER_DEALLOC;
+ }
+ sstv_free_user(img->buffer);
+
+ /* reset fields */
+ img->width = 0;
+ img->height = 0;
+ img->buffer = NULL;
+
+ /* done */
+ return SSTV_OK;
} \ No newline at end of file
diff --git a/src/tools/sstv-encode.cpp b/src/tools/sstv-encode.cpp
index b621a5c..9c7c141 100644
--- a/src/tools/sstv-encode.cpp
+++ b/src/tools/sstv-encode.cpp
@@ -42,20 +42,28 @@ int main(int argc, char **argv)
LOG(FATAL) << "Encoding mode not provided, use --mode";
}
- /* load image */
+ /* TODO: parse SSTV mode */
+ sstv_mode_t mode = SSTV_MODE_PD120;
+
+ /* load image from file (TODO: perform normalization from source to desired properties) */
LOG(INFO) << "Loading image from " << FLAGS_input;
- cimg_library::CImg<unsigned char> input_image(FLAGS_input.c_str());
- uint8_t *bytes = input_image.data();
+ cimg_library::CImg<unsigned char> input_image = (cimg_library::CImg<>(FLAGS_input.c_str())).RGBtoYCbCr();
+
+ sstv_image_t sstv_image;
+ if (sstv_pack_image(&sstv_image, input_image.width(), input_image.height(), SSTV_FORMAT_YCBCR, input_image.data()) != SSTV_OK) {
+ LOG(FATAL) << "sstv_pack_image() failed";
+ }
- /* initialize an encoder */
+ /* initialize library */
LOG(INFO) << "Initializing libsstv";
if (sstv_init(malloc, free) != SSTV_OK) {
LOG(FATAL) << "Failed to initialize libsstv";
}
+ /* create encoder context */
LOG(INFO) << "Creating encoding context";
void *ctx = nullptr;
- if (sstv_create_encoder(SSTV_PD120, bytes, FLAGS_sample_rate, &ctx) != SSTV_OK) {
+ if (sstv_create_encoder(&ctx, sstv_image, mode, FLAGS_sample_rate) != SSTV_OK) {
LOG(FATAL) << "Failed to create SSTV encoder";
}
if (!ctx) {
diff --git a/test/test-image.bmp b/test/test-image.bmp
index 90a240d..d8e6d80 100644
--- a/test/test-image.bmp
+++ b/test/test-image.bmp
Binary files differ