summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrimio <vasi.vilvoiu@gmail.com>2019-02-11 02:18:00 +0200
committerrimio <vasi.vilvoiu@gmail.com>2019-02-11 02:18:00 +0200
commit00ad11118c8c16c5b5d167bba04fea4d8113dd54 (patch)
tree7cc6a8601911f4b6f55013ea660a630ba5047a55
parent84a3971982ddd04f3e8cab8be69ae07ef201010d (diff)
Remove size_t; precompute timings in microsamples; support all PD modes
-rw-r--r--src/encoder.c186
-rw-r--r--src/libsstv.template.h32
-rw-r--r--src/sstv.c30
-rw-r--r--src/tools/sstv-encode.cpp30
4 files changed, 211 insertions, 67 deletions
diff --git a/src/encoder.c b/src/encoder.c
index 65edc18..7d5655a 100644
--- a/src/encoder.c
+++ b/src/encoder.c
@@ -10,11 +10,42 @@
#include "luts.h"
/*
+ * Frequencies (all expressed in Hz)
+ */
+#define LEADER_FREQ 1900
+#define BREAK_FREQ 1200
+
+#define VIS_START_STOP_FREQ 1200
+#define VIS_LOW_FREQ 1300
+#define VIS_HIGH_FREQ 1100
+
+#define SYNC_FREQ 1200
+#define PORCH_FREQ 1500
+
+#define DATA_BASE_FREQ 1500
+#define DATA_BANDWIDTH 800
+
+/*
+ * Durations (useconds)
+ */
+#define LEADER_TONE_USEC 300000
+#define BREAK_USEC 10000
+#define VIS_BIT_USEC 30000
+
+/*
* Computation helpers
*/
-#define MILLISAMPLES_FROM_MICROSECONDS(time_us, sample_rate) ((uint64_t)(time_us) * (uint64_t)(sample_rate) / 1000)
+#define MICROSAMPLES_FROM_MICROSECONDS(time_us, sample_rate) ((uint64_t)(time_us) * (uint64_t)(sample_rate))
#define DPHASE_FROM_FREQ(freq, sample_rate) ((((uint64_t)(freq)) << 32) / (uint64_t)(sample_rate))
+#define BYTE_TO_FREQ(b) (DATA_BASE_FREQ + (b) * DATA_BANDWIDTH / 255)
+
+#define FSK(ctx, usamples, freq) \
+ { \
+ (ctx)->fsk.phase_delta = DPHASE_FROM_FREQ((freq), context->sample_rate); \
+ (ctx)->fsk.remaining_usamp += usamples; \
+ }
+
/*
* Encoder state
*/
@@ -56,7 +87,7 @@ typedef struct {
/* output configuration */
sstv_mode_t mode;
- size_t sample_rate;
+ uint32_t sample_rate;
/* current state */
sstv_encoder_state_t state;
@@ -65,9 +96,16 @@ typedef struct {
struct {
uint32_t phase;
uint32_t phase_delta;
- size_t remaining_samples;
+ uint64_t remaining_usamp;
} fsk;
+ /* mode timings */
+ struct {
+ uint32_t sync_usamp;
+ uint32_t porch_usamp;
+ uint32_t pixel_usamp;
+ } timings;
+
/* state extra info */
union {
struct {
@@ -76,8 +114,8 @@ typedef struct {
} vis;
struct {
- size_t curr_line;
- size_t curr_col;
+ uint32_t curr_line;
+ uint32_t curr_col;
} scan;
} extra;
} sstv_encoder_context_t;
@@ -90,7 +128,7 @@ static uint64_t default_encoder_context_usage = 0x0;
sstv_error_t
-sstv_create_encoder(void **out_ctx, sstv_image_t image, sstv_mode_t mode, size_t sample_rate)
+sstv_create_encoder(void **out_ctx, sstv_image_t image, sstv_mode_t mode, uint32_t sample_rate)
{
sstv_encoder_context_t *ctx = NULL;
@@ -101,7 +139,7 @@ sstv_create_encoder(void **out_ctx, sstv_image_t image, sstv_mode_t mode, size_t
/* check image properties */
{
- size_t w, h;
+ uint32_t w, h;
sstv_image_format_t fmt;
sstv_error_t rc;
@@ -125,7 +163,7 @@ sstv_create_encoder(void **out_ctx, sstv_image_t image, sstv_mode_t mode, size_t
return SSTV_ALLOC_FAIL;
}
} else {
- size_t i;
+ uint32_t i;
/* use default contexts */
for (i = 0; i < SSTV_DEFAULT_ENCODER_CONTEXT_COUNT; i++) {
if ((default_encoder_context_usage & (0x1 << i)) == 0) {
@@ -145,7 +183,64 @@ sstv_create_encoder(void **out_ctx, sstv_image_t image, sstv_mode_t mode, size_t
ctx->sample_rate = sample_rate;
ctx->state = SSTV_ENCODER_STATE_START;
ctx->fsk.phase = 0; /* start nicely from zero */
- ctx->fsk.remaining_samples = 0; /* so we get initial state change */
+ ctx->fsk.remaining_usamp = 0; /* so we get initial state change */
+
+ /* initialize mode timings */
+ switch (mode) {
+ /*
+ * PD modes
+ */
+ case SSTV_MODE_PD50:
+ ctx->timings.sync_usamp = MICROSAMPLES_FROM_MICROSECONDS(20000, sample_rate);
+ ctx->timings.porch_usamp = MICROSAMPLES_FROM_MICROSECONDS(2080, sample_rate);
+ ctx->timings.pixel_usamp = MICROSAMPLES_FROM_MICROSECONDS(286, sample_rate);
+ break;
+
+ case SSTV_MODE_PD90:
+ ctx->timings.sync_usamp = MICROSAMPLES_FROM_MICROSECONDS(20000, sample_rate);
+ ctx->timings.porch_usamp = MICROSAMPLES_FROM_MICROSECONDS(2080, sample_rate);
+ ctx->timings.pixel_usamp = MICROSAMPLES_FROM_MICROSECONDS(532, sample_rate);
+ break;
+
+ case SSTV_MODE_PD120:
+ ctx->timings.sync_usamp = MICROSAMPLES_FROM_MICROSECONDS(20000, sample_rate);
+ ctx->timings.porch_usamp = MICROSAMPLES_FROM_MICROSECONDS(2080, sample_rate);
+ ctx->timings.pixel_usamp = MICROSAMPLES_FROM_MICROSECONDS(190, sample_rate);
+ break;
+
+ case SSTV_MODE_PD160:
+ ctx->timings.sync_usamp = MICROSAMPLES_FROM_MICROSECONDS(20000, sample_rate);
+ ctx->timings.porch_usamp = MICROSAMPLES_FROM_MICROSECONDS(2080, sample_rate);
+ ctx->timings.pixel_usamp = MICROSAMPLES_FROM_MICROSECONDS(382, sample_rate);
+ break;
+
+ case SSTV_MODE_PD180:
+ ctx->timings.sync_usamp = MICROSAMPLES_FROM_MICROSECONDS(20000, sample_rate);
+ ctx->timings.porch_usamp = MICROSAMPLES_FROM_MICROSECONDS(2080, sample_rate);
+ ctx->timings.pixel_usamp = MICROSAMPLES_FROM_MICROSECONDS(286, sample_rate);
+ break;
+
+ case SSTV_MODE_PD240:
+ ctx->timings.sync_usamp = MICROSAMPLES_FROM_MICROSECONDS(20000, sample_rate);
+ ctx->timings.porch_usamp = MICROSAMPLES_FROM_MICROSECONDS(2080, sample_rate);
+ ctx->timings.pixel_usamp = MICROSAMPLES_FROM_MICROSECONDS(382, sample_rate);
+ break;
+
+ case SSTV_MODE_PD290:
+ ctx->timings.sync_usamp = MICROSAMPLES_FROM_MICROSECONDS(20000, sample_rate);
+ ctx->timings.porch_usamp = MICROSAMPLES_FROM_MICROSECONDS(2080, sample_rate);
+ ctx->timings.pixel_usamp = MICROSAMPLES_FROM_MICROSECONDS(286, sample_rate);
+ break;
+
+ /*
+ * Invalid mode
+ */
+ default:
+ if (sstv_free_user) {
+ sstv_free_user(ctx);
+ }
+ return SSTV_BAD_MODE;
+ }
/* set output */
*out_ctx = ctx;
@@ -157,7 +252,7 @@ sstv_create_encoder(void **out_ctx, sstv_image_t image, sstv_mode_t mode, size_t
sstv_error_t
sstv_delete_encoder(void *ctx)
{
- size_t i;
+ uint32_t i;
if (!ctx) {
return SSTV_BAD_PARAMETER;
@@ -190,9 +285,8 @@ sstv_encode_pd_state_change(sstv_encoder_context_t *context)
/* start communication */
if (context->state == SSTV_ENCODER_STATE_VIS_STOP_BIT) {
context->state = SSTV_ENCODER_STATE_SYNC;
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1200, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(20000, context->sample_rate);
context->extra.scan.curr_line = 0;
+ FSK(context, context->timings.sync_usamp, SYNC_FREQ);
return SSTV_OK;
}
@@ -202,17 +296,15 @@ sstv_encode_pd_state_change(sstv_encoder_context_t *context)
&& (context->extra.scan.curr_line < context->image.height-1))
{
context->state = SSTV_ENCODER_STATE_SYNC;
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1200, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(20000, context->sample_rate);
context->extra.scan.curr_line += 2;
+ FSK(context, context->timings.sync_usamp, SYNC_FREQ);
return SSTV_OK;
}
/* sync->porch */
if (context->state == SSTV_ENCODER_STATE_SYNC) {
context->state = SSTV_ENCODER_STATE_PORCH;
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1500, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(2080, context->sample_rate);
+ FSK(context, context->timings.porch_usamp, PORCH_FREQ);
return SSTV_OK;
}
@@ -227,10 +319,9 @@ sstv_encode_pd_state_change(sstv_encoder_context_t *context)
context->state = SSTV_ENCODER_STATE_Y_EVEN_SCAN;
- size_t pix_offset = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col;
+ uint32_t pix_offset = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col;
uint8_t y = context->image.buffer[pix_offset * 3];
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1500 + y * 800 / 255, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(190, context->sample_rate);
+ FSK(context, context->timings.pixel_usamp, BYTE_TO_FREQ(y));
context->extra.scan.curr_col ++;
return SSTV_OK;
@@ -247,13 +338,12 @@ sstv_encode_pd_state_change(sstv_encoder_context_t *context)
context->state = SSTV_ENCODER_STATE_RY_SCAN;
- size_t pix_offset_l0 = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col;
- size_t pix_offset_l1 = context->image.width * (context->extra.scan.curr_line + 1) + context->extra.scan.curr_col;
+ uint32_t pix_offset_l0 = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col;
+ uint32_t pix_offset_l1 = context->image.width * (context->extra.scan.curr_line + 1) + context->extra.scan.curr_col;
uint8_t r1 = context->image.buffer[pix_offset_l0 * 3 + 2];
uint8_t r2 = context->image.buffer[pix_offset_l1 * 3 + 2];
uint8_t r = (r1 + r2) / 2;
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1500 + r * 800 / 255, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(190, context->sample_rate);
+ FSK(context, context->timings.pixel_usamp, BYTE_TO_FREQ(r));
context->extra.scan.curr_col ++;
return SSTV_OK;
@@ -270,13 +360,12 @@ sstv_encode_pd_state_change(sstv_encoder_context_t *context)
context->state = SSTV_ENCODER_STATE_BY_SCAN;
- size_t pix_offset_l0 = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col;
- size_t pix_offset_l1 = context->image.width * (context->extra.scan.curr_line + 1) + context->extra.scan.curr_col;
+ uint32_t pix_offset_l0 = context->image.width * context->extra.scan.curr_line + context->extra.scan.curr_col;
+ uint32_t pix_offset_l1 = context->image.width * (context->extra.scan.curr_line + 1) + context->extra.scan.curr_col;
uint8_t b1 = context->image.buffer[pix_offset_l0 * 3 + 1];
uint8_t b2 = context->image.buffer[pix_offset_l1 * 3 + 1];
uint8_t b = (b1 + b2) / 2;
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1500 + b * 800 / 255, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(190, context->sample_rate);
+ FSK(context, context->timings.pixel_usamp, BYTE_TO_FREQ(b));
context->extra.scan.curr_col ++;
return SSTV_OK;
@@ -293,10 +382,9 @@ sstv_encode_pd_state_change(sstv_encoder_context_t *context)
context->state = SSTV_ENCODER_STATE_Y_ODD_SCAN;
- size_t pix_offset = context->image.width * (context->extra.scan.curr_line + 1) + context->extra.scan.curr_col;
+ uint32_t pix_offset = context->image.width * (context->extra.scan.curr_line + 1) + context->extra.scan.curr_col;
uint8_t y = context->image.buffer[pix_offset * 3];
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1500 + y * 800 / 255, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(190, context->sample_rate);
+ FSK(context, context->timings.pixel_usamp, BYTE_TO_FREQ(y));
context->extra.scan.curr_col ++;
return SSTV_OK;
@@ -313,32 +401,36 @@ sstv_encode_state_change(sstv_encoder_context_t *context)
/* leader tone #1 */
if (context->state == SSTV_ENCODER_STATE_START) {
context->state = SSTV_ENCODER_STATE_LEADER_TONE_1;
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1900, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(300000, context->sample_rate);
+ FSK(context,
+ MICROSAMPLES_FROM_MICROSECONDS(LEADER_TONE_USEC, context->sample_rate),
+ LEADER_FREQ);
return SSTV_OK;
}
/* break */
if (context->state == SSTV_ENCODER_STATE_LEADER_TONE_1) {
context->state = SSTV_ENCODER_STATE_BREAK;
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1200, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(10000, context->sample_rate);
+ FSK(context,
+ MICROSAMPLES_FROM_MICROSECONDS(BREAK_USEC, context->sample_rate),
+ BREAK_FREQ);
return SSTV_OK;
}
/* leader tone #2 */
if (context->state == SSTV_ENCODER_STATE_BREAK) {
context->state = SSTV_ENCODER_STATE_LEADER_TONE_2;
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1900, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(300000, context->sample_rate);
+ FSK(context,
+ MICROSAMPLES_FROM_MICROSECONDS(LEADER_TONE_USEC, context->sample_rate),
+ LEADER_FREQ);
return SSTV_OK;
}
/* VIS start bit */
if (context->state == SSTV_ENCODER_STATE_LEADER_TONE_2) {
context->state = SSTV_ENCODER_STATE_VIS_START_BIT;
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1200, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(30000, context->sample_rate);
+ FSK(context,
+ MICROSAMPLES_FROM_MICROSECONDS(VIS_BIT_USEC, context->sample_rate),
+ VIS_START_STOP_FREQ);
context->extra.vis.visp = sstv_get_visp_code(context->mode);
context->extra.vis.curr_bit = 0;
return SSTV_OK;
@@ -351,27 +443,31 @@ sstv_encode_state_change(sstv_encoder_context_t *context)
uint8_t bit = (context->extra.vis.visp >> context->extra.vis.curr_bit) & 0x1;
context->state = SSTV_ENCODER_STATE_VIS_BIT;
context->extra.vis.curr_bit ++;
- context->fsk.phase_delta = DPHASE_FROM_FREQ((bit ? 1100 : 1300), context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(30000, context->sample_rate);
+ FSK(context,
+ MICROSAMPLES_FROM_MICROSECONDS(VIS_BIT_USEC, context->sample_rate),
+ (bit ? VIS_HIGH_FREQ : VIS_LOW_FREQ));
return SSTV_OK;
}
/* VIS stop bit */
if (context->state == SSTV_ENCODER_STATE_VIS_BIT) {
context->state = SSTV_ENCODER_STATE_VIS_STOP_BIT;
- context->fsk.phase_delta = DPHASE_FROM_FREQ(1200, context->sample_rate);
- context->fsk.remaining_samples += MILLISAMPLES_FROM_MICROSECONDS(30000, context->sample_rate);
+ FSK(context,
+ MICROSAMPLES_FROM_MICROSECONDS(VIS_BIT_USEC, context->sample_rate),
+ VIS_START_STOP_FREQ);
return SSTV_OK;
}
/* call state change routine for specific mode */
switch (context->mode) {
/* PD modes */
+ case SSTV_MODE_PD50:
case SSTV_MODE_PD90:
case SSTV_MODE_PD120:
case SSTV_MODE_PD160:
case SSTV_MODE_PD180:
case SSTV_MODE_PD240:
+ case SSTV_MODE_PD290:
return sstv_encode_pd_state_change(context);
default:
@@ -395,7 +491,7 @@ sstv_encode(void *ctx, sstv_signal_t *signal)
/* main encoding loop */
while (1) {
/* state change? */
- if (context->fsk.remaining_samples < 1000) {
+ if (context->fsk.remaining_usamp < 1000000) {
rc = sstv_encode_state_change(context);
if (rc != SSTV_OK) {
return rc;
@@ -407,7 +503,7 @@ sstv_encode(void *ctx, sstv_signal_t *signal)
}
/* make sure we don't skip a state */
- if (context->fsk.remaining_samples < 1000) {
+ if (context->fsk.remaining_usamp < 1000000) {
/* this should not happen for a proper sample rate */
return SSTV_INTERNAL_ERROR;
}
@@ -421,7 +517,7 @@ sstv_encode(void *ctx, sstv_signal_t *signal)
}
/* encode sample and continue */
- context->fsk.remaining_samples -= 1000;
+ context->fsk.remaining_usamp -= 1000000;
context->fsk.phase += context->fsk.phase_delta;
switch(signal->type) {
case SSTV_SAMPLE_INT8:
diff --git a/src/libsstv.template.h b/src/libsstv.template.h
index ce4cf26..7338da9 100644
--- a/src/libsstv.template.h
+++ b/src/libsstv.template.h
@@ -8,6 +8,10 @@
#ifndef _LIBSSTV_H_
#define _LIBSSTV_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include <stdint.h>
#include <stddef.h>
@@ -59,11 +63,13 @@ typedef enum {
*/
typedef enum {
/* PD modes */
+ SSTV_MODE_PD50,
SSTV_MODE_PD90,
SSTV_MODE_PD120,
SSTV_MODE_PD160,
SSTV_MODE_PD180,
- SSTV_MODE_PD240
+ SSTV_MODE_PD240,
+ SSTV_MODE_PD290
} sstv_mode_t;
/*
@@ -91,8 +97,8 @@ typedef enum {
*/
typedef struct {
/* image properties */
- size_t width;
- size_t height;
+ uint32_t width;
+ uint32_t height;
sstv_image_format_t format;
/* image buffer */
@@ -116,16 +122,16 @@ typedef struct {
void *buffer;
/* size in bytes */
- size_t size;
+ uint32_t size;
/* sample type */
sstv_sample_type_t type;
/* number of total samples */
- size_t capacity;
+ uint32_t capacity;
/* number of used samples */
- size_t count;
+ uint32_t count;
} sstv_signal_t;
@@ -148,7 +154,7 @@ extern sstv_error_t sstv_init(sstv_malloc_t alloc_func, sstv_free_t dealloc_func
* 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);
+extern sstv_error_t sstv_get_mode_image_props(sstv_mode_t mode, uint32_t *width, uint32_t *height, sstv_image_format_t *format);
/*
* Create an image given an SSTV mode.
@@ -176,7 +182,7 @@ extern sstv_error_t sstv_create_image_from_mode(sstv_image_t *out_img, sstv_mode
* 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);
+extern sstv_error_t sstv_create_image_from_props(sstv_image_t *out_img, uint32_t w, uint32_t h, sstv_image_format_t format);
/*
* Deletes an image.
@@ -212,7 +218,7 @@ extern sstv_error_t sstv_convert_image(sstv_image_t *img, sstv_image_format_t fo
* 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);
+extern sstv_error_t sstv_pack_image(sstv_image_t *out_img, uint32_t width, uint32_t height, sstv_image_format_t format, uint8_t *buffer);
/*
* Pack a signal buffer into a signal structure.
@@ -224,7 +230,7 @@ extern sstv_error_t sstv_pack_image(sstv_image_t *out_img, size_t width, size_t
*
* NOTE: Buffer is managed by user.
*/
-extern sstv_error_t sstv_pack_signal(sstv_signal_t *sig, sstv_sample_type_t type, size_t capacity, void *buffer);
+extern sstv_error_t sstv_pack_signal(sstv_signal_t *sig, sstv_sample_type_t type, uint32_t capacity, void *buffer);
/*
* Create an SSTV encoder.
@@ -241,7 +247,7 @@ extern sstv_error_t sstv_pack_signal(sstv_signal_t *sig, sstv_sample_type_t type
* SSTV_DEFAULT_ENCODER_CONTEXT_COUNT default structures, and once these are
* used up, a SSTV_NO_DEFAULT_ENCODERS error is returned.
*/
-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_create_encoder(void **out_ctx, sstv_image_t image, sstv_mode_t mode, uint32_t sample_rate);
/*
* Deletes an SSTV encoder.
@@ -263,4 +269,8 @@ extern sstv_error_t sstv_delete_encoder(void *ctx);
*/
extern sstv_error_t sstv_encode(void *ctx, sstv_signal_t *signal);
+#ifdef __cplusplus
+}
+#endif
+
#endif \ No newline at end of file
diff --git a/src/sstv.c b/src/sstv.c
index 9a6055e..b4ff28e 100644
--- a/src/sstv.c
+++ b/src/sstv.c
@@ -151,10 +151,16 @@ sstv_convert_image(sstv_image_t *img, sstv_image_format_t format)
}
sstv_error_t
-sstv_get_mode_image_props(sstv_mode_t mode, size_t *width, size_t *height, sstv_image_format_t *format)
+sstv_get_mode_image_props(sstv_mode_t mode, uint32_t *width, uint32_t *height, sstv_image_format_t *format)
{
switch (mode) {
/* PD modes */
+ case SSTV_MODE_PD50:
+ if (width) *width = 320;
+ if (height) *height = 256;
+ if (format) *format = SSTV_FORMAT_YCBCR;
+ break;
+
case SSTV_MODE_PD90:
if (width) *width = 320;
if (height) *height = 256;
@@ -185,6 +191,12 @@ sstv_get_mode_image_props(sstv_mode_t mode, size_t *width, size_t *height, sstv_
if (format) *format = SSTV_FORMAT_YCBCR;
break;
+ case SSTV_MODE_PD290:
+ if (width) *width = 800;
+ if (height) *height = 616;
+ if (format) *format = SSTV_FORMAT_YCBCR;
+ break;
+
default:
return SSTV_BAD_MODE;
}
@@ -195,7 +207,7 @@ sstv_get_mode_image_props(sstv_mode_t mode, size_t *width, size_t *height, sstv_
sstv_error_t
sstv_create_image_from_mode(sstv_image_t *out_img, sstv_mode_t mode)
{
- size_t w, h;
+ uint32_t w, h;
sstv_image_format_t fmt;
sstv_error_t rc;
@@ -208,9 +220,9 @@ sstv_create_image_from_mode(sstv_image_t *out_img, sstv_mode_t mode)
}
sstv_error_t
-sstv_create_image_from_props(sstv_image_t *out_img, size_t w, size_t h, sstv_image_format_t format)
+sstv_create_image_from_props(sstv_image_t *out_img, uint32_t w, uint32_t h, sstv_image_format_t format)
{
- size_t bsize;
+ uint32_t bsize;
if (!out_img) {
return SSTV_BAD_PARAMETER;
@@ -255,7 +267,7 @@ sstv_create_image_from_props(sstv_image_t *out_img, size_t w, size_t h, sstv_ima
}
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)
+sstv_pack_image(sstv_image_t *out_img, uint32_t width, uint32_t height, sstv_image_format_t format, uint8_t *buffer)
{
if (!out_img || !buffer) {
return SSTV_BAD_PARAMETER;
@@ -294,7 +306,7 @@ sstv_delete_image(sstv_image_t *img)
}
sstv_error_t
-sstv_pack_signal(sstv_signal_t *sig, sstv_sample_type_t type, size_t capacity, void *buffer)
+sstv_pack_signal(sstv_signal_t *sig, sstv_sample_type_t type, uint32_t capacity, void *buffer)
{
if (!sig) {
return SSTV_BAD_PARAMETER;
@@ -327,6 +339,9 @@ uint8_t
sstv_get_visp_code(sstv_mode_t mode)
{
switch (mode) {
+ case SSTV_MODE_PD50:
+ return 221;
+
case SSTV_MODE_PD90:
return 99;
@@ -342,6 +357,9 @@ sstv_get_visp_code(sstv_mode_t mode)
case SSTV_MODE_PD240:
return 225;
+ case SSTV_MODE_PD290:
+ return 222;
+
default:
return 0;
}
diff --git a/src/tools/sstv-encode.cpp b/src/tools/sstv-encode.cpp
index 48c6623..fa673b6 100644
--- a/src/tools/sstv-encode.cpp
+++ b/src/tools/sstv-encode.cpp
@@ -13,20 +13,40 @@
#include <Magick++.h>
#include <sndfile.h>
-extern "C" {
#include <libsstv.h>
-}
/*
* Command line flags
*/
-
DEFINE_bool(logtostderr, false, "Only log to stderr");
DEFINE_string(mode, "", "SSTV mode for encoder");
DEFINE_string(input, "", "input image");
DEFINE_string(output, "", "output WAV file");
DEFINE_uint64(sample_rate, 48000, "output audio sample rate");
+sstv_mode_t mode_from_string(std::string mode)
+{
+ std::transform(mode.begin(), mode.end(), mode.begin(), ::toupper);
+
+ if (mode == "PD50") {
+ return SSTV_MODE_PD50;
+ } else if (mode == "PD90") {
+ return SSTV_MODE_PD90;
+ } else if (mode == "PD120") {
+ return SSTV_MODE_PD120;
+ } else if (mode == "PD160") {
+ return SSTV_MODE_PD160;
+ } else if (mode == "PD180") {
+ return SSTV_MODE_PD180;
+ } else if (mode == "PD240") {
+ return SSTV_MODE_PD240;
+ } else if (mode == "PD290") {
+ return SSTV_MODE_PD290;
+ } else {
+ LOG(FATAL) << "Unknown mode '" << mode << "'";
+ }
+}
+
int main(int argc, char **argv)
{
/* Parse command line flags */
@@ -48,10 +68,10 @@ int main(int argc, char **argv)
}
/* TODO: parse SSTV mode */
- sstv_mode_t mode = SSTV_MODE_PD120;
+ sstv_mode_t mode = mode_from_string(FLAGS_mode);
/* get image properties for chosen mode */
- size_t width, height;
+ uint32_t width, height;
sstv_image_format_t format;
if (sstv_get_mode_image_props(mode, &width, &height, &format) != SSTV_OK) {
LOG(FATAL) << "sstv_get_mode_image_props() failed";