diff options
| author | rimio <vasi.vilvoiu@gmail.com> | 2019-01-08 13:52:23 +0200 |
|---|---|---|
| committer | rimio <vasi.vilvoiu@gmail.com> | 2019-01-08 13:52:23 +0200 |
| commit | a7d5e7ca20c959b739d80f96362f326a5848cdb3 (patch) | |
| tree | 5fcc392e5e2b6f425bf3ea756801b7aa9fb81b43 | |
| parent | 83608e80322642e681918a647ef54a67e7bb15a3 (diff) | |
Image management
| -rw-r--r-- | src/encoder.c | 34 | ||||
| -rw-r--r-- | src/libsstv.template.h | 116 | ||||
| -rw-r--r-- | src/sstv.c | 143 | ||||
| -rw-r--r-- | src/tools/sstv-encode.cpp | 18 | ||||
| -rw-r--r-- | test/test-image.bmp | bin | 6220922 -> 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); @@ -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 Binary files differindex 90a240d..d8e6d80 100644 --- a/test/test-image.bmp +++ b/test/test-image.bmp |
