aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blind-arithm.c115
-rw-r--r--src/blind-kernel.c36
-rw-r--r--src/blind-spatial-arithm.c94
-rw-r--r--src/blind-spatial-mean.c142
-rw-r--r--src/blind-stack.c1
-rw-r--r--src/blind-temporal-arithm.c94
-rw-r--r--src/blind-temporal-mean.c63
-rw-r--r--src/stream.c2
-rw-r--r--src/util.c5
9 files changed, 448 insertions, 104 deletions
diff --git a/src/blind-arithm.c b/src/blind-arithm.c
index 494977b..4c6ca14 100644
--- a/src/blind-arithm.c
+++ b/src/blind-arithm.c
@@ -1,67 +1,71 @@
/* See LICENSE file for copyright and license details. */
#include "common.h"
-USAGE("[-axyz] operation right-hand-stream")
+USAGE("[-axyz] operation right-hand-stream ...")
-static int skip_a = 0;
-static int skip_x = 0;
-static int skip_y = 0;
-static int skip_z = 0;
+static int skip_ch[4] = {0, 0, 0, 0};
/* Because the syntax for a function returning a function pointer is disgusting. */
-typedef void (*process_func)(struct stream *left, struct stream *right, size_t n);
+typedef void (*process_func)(struct stream *streams, size_t n_streams, size_t n);
#define LIST_OPERATORS(PIXFMT, TYPE)\
- X(add, *lh += rh, PIXFMT, TYPE)\
- X(sub, *lh -= rh, PIXFMT, TYPE)\
- X(mul, *lh *= rh, PIXFMT, TYPE)\
- X(div, *lh /= rh, PIXFMT, TYPE)\
- X(mod, *lh = posmod(*lh, rh), PIXFMT, TYPE)\
- X(exp, *lh = pow(*lh, rh), PIXFMT, TYPE)\
- X(log, *lh = log2(*lh) / log2(rh), PIXFMT, TYPE)\
- X(min, *lh = MIN(*lh, rh), PIXFMT, TYPE)\
- X(max, *lh = MAX(*lh, rh), PIXFMT, TYPE)\
- X(abs, *lh = abs(*lh - rh) + rh, PIXFMT, TYPE)
+ X(add, 0, *lh += rh, PIXFMT, TYPE)\
+ X(sub, 0, *lh -= rh, PIXFMT, TYPE)\
+ X(mul, 0, *lh *= rh, PIXFMT, TYPE)\
+ X(div, 0, *lh /= rh, PIXFMT, TYPE)\
+ X(mod, 0, *lh = posmod(*lh, rh), PIXFMT, TYPE)\
+ X(exp, 1, *lh = pow(*lh, rh), PIXFMT, TYPE)\
+ X(log, 0, *lh = log2(*lh) / log2(rh), PIXFMT, TYPE)\
+ X(min, 0, *lh = MIN(*lh, rh), PIXFMT, TYPE)\
+ X(max, 0, *lh = MAX(*lh, rh), PIXFMT, TYPE)\
+ X(abs, 0, *lh = abs(*lh - rh) + rh, PIXFMT, TYPE)
-#define C(CH, CHI, ALGO, TYPE)\
- (!skip_##CH ? ((lh = ((TYPE *)(left->buf + i)) + (CHI),\
- rh = ((TYPE *)(right->buf + i))[CHI],\
- (ALGO)), 0) : 0)
+#define P(L, R, ALGO, TYPE)\
+ (lh = (TYPE *)(streams[L].buf + k),\
+ rh = *((TYPE *)(streams[R].buf + k)),\
+ (ALGO))
-#define X(NAME, ALGO, PIXFMT, TYPE)\
+#define X(NAME, RTL, ALGO, PIXFMT, TYPE)\
static void\
- process_##PIXFMT##_##NAME(struct stream *left, struct stream *right, size_t n)\
+ process_##PIXFMT##_##NAME(struct stream *streams, size_t n_streams, size_t n)\
{\
- size_t i;\
+ size_t i, j, k;\
TYPE *lh, rh;\
- for (i = 0; i < n; i += 4 * sizeof(TYPE)) {\
- C(x, 0, ALGO, TYPE);\
- C(y, 1, ALGO, TYPE);\
- C(z, 2, ALGO, TYPE);\
- C(a, 3, ALGO, TYPE);\
+ if (RTL) {\
+ for (i = 0; i < streams->n_chan; i++)\
+ if (!skip_ch[i])\
+ for (j = n_streams; --j;)\
+ for (k = i * sizeof(TYPE); k < n; k += 4 * sizeof(TYPE))\
+ P(j - 1, j, ALGO, TYPE);\
+ } else {\
+ for (i = 0; i < streams->n_chan; i++)\
+ if (!skip_ch[i])\
+ for (j = 1; j < n_streams; j++)\
+ for (k = i * sizeof(TYPE); k < n; k += 4 * sizeof(TYPE))\
+ P(0, j, ALGO, TYPE);\
}\
}
-LIST_OPERATORS(xyza, double)
-LIST_OPERATORS(xyzaf, float)
+LIST_OPERATORS(lf, double)
+LIST_OPERATORS(f, float)
#undef X
static process_func
-get_process_xyza(const char *operation)
+get_process_lf(const char *operation)
{
-#define X(NAME, ALGO, PIXFMT, TYPE)\
+#define X(NAME, _RTL, _ALGO, PIXFMT, _TYPE)\
if (!strcmp(operation, #NAME)) return process_##PIXFMT##_##NAME;
- LIST_OPERATORS(xyza, double)
+ LIST_OPERATORS(lf, double)
#undef X
eprintf("algorithm not recognised: %s\n", operation);
return NULL;
}
static process_func
-get_process_xyzaf(const char *operation)
+get_process_f(const char *operation)
{
-#define X(NAME, ALGO, PIXFMT, TYPE)\
+#define X(NAME, _RTL, _ALGO, PIXFMT, _TYPE)\
if (!strcmp(operation, #NAME)) return process_##PIXFMT##_##NAME;
- LIST_OPERATORS(xyzaf, float)
+ LIST_OPERATORS(f, float)
#undef X
eprintf("algorithm not recognised: %s\n", operation);
return NULL;
@@ -70,41 +74,46 @@ get_process_xyzaf(const char *operation)
int
main(int argc, char *argv[])
{
- struct stream left, right;
+ struct stream *streams;
process_func process;
+ const char *operation;
+ size_t frames = SIZE_MAX, tmp;
+ int i;
ARGBEGIN {
case 'a':
- skip_a = 1;
+ skip_ch[3] = 1;
break;
case 'x':
- skip_x = 1;
- break;
case 'y':
- skip_y = 1;
- break;
case 'z':
- skip_z = 1;
+ skip_ch[ARGC() - 'x'] = 1;
break;
default:
usage();
} ARGEND;
- if (argc != 2)
+ if (argc < 2)
usage();
- eopen_stream(&left, NULL);
- eopen_stream(&right, argv[1]);
+ operation = *argv;
+ streams = alloca((size_t)argc * sizeof(*streams));
+ *argv = NULL;
+ for (i = 0; i < argc; i++) {
+ eopen_stream(streams + i, argv[i]);
+ if (streams[i].frames && streams[i].frames < frames)
+ frames = streams[i].frames;
+ }
- if (!strcmp(left.pixfmt, "xyza"))
- process = get_process_xyza(argv[0]);
- else if (!strcmp(left.pixfmt, "xyza f"))
- process = get_process_xyzaf(argv[0]);
+ if (streams->encoding == DOUBLE)
+ process = get_process_lf(operation);
else
- eprintf("pixel format %s is not supported, try xyza\n", left.pixfmt);
+ process = get_process_f(operation);
- fprint_stream_head(stdout, &left);
+ tmp = streams->frames, streams->frames = frames;
+ fprint_stream_head(stdout, streams);
efflush(stdout, "<stdout>");
- process_two_streams(&left, &right, STDOUT_FILENO, "<stdout>", process);
+ streams->frames = tmp;
+ process_multiple_streams(streams, (size_t)argc, STDOUT_FILENO, "<stdout>", 1, process);
return 0;
}
diff --git a/src/blind-kernel.c b/src/blind-kernel.c
index 7bf1a60..ae66b24 100644
--- a/src/blind-kernel.c
+++ b/src/blind-kernel.c
@@ -3,7 +3,7 @@
USAGE("[-xyza] kernel [parameter] ...")
-#define SUBUSAGE(FORMAT) "usage: %s [-xyza] " FORMAT, argv0
+#define SUBUSAGE(FORMAT) "usage: %s [-xyza] " FORMAT "\n", argv0
#define STRCASEEQ3(A, B1, B2, B3) (!strcasecmp(A, B1) || !strcasecmp(A, B2) || !strcasecmp(A, B3))
#define LIST_KERNELS\
@@ -37,7 +37,7 @@ kernel_kirsch(int argc, char *argv[], size_t *rows, size_t *cols, double **free_
if (STRCASEEQ3(argv[0], "6", "SE", "ES")) return matrices[5];
if (STRCASEEQ3(argv[0], "7", "E", "E")) return matrices[6];
if (STRCASEEQ3(argv[0], "8", "NE", "EN")) return matrices[7];
- eprintf("Unrecognised direction: %s\n", argv[0]);
+ eprintf("unrecognised direction: %s\n", argv[0]);
return NULL;
}
@@ -129,6 +129,7 @@ static const double *
kernel_gaussian(int argc, char *argv[], size_t *rows, size_t *cols, double **free_this)
{
size_t spread = 0, y, x;
+ ssize_t xx, yy;
int unsharpen = 0;
double sigma, value, c, k;
char *arg;
@@ -160,29 +161,17 @@ kernel_gaussian(int argc, char *argv[], size_t *rows, size_t *cols, double **fre
*free_this = emalloc3(*rows, *cols, sizeof(double));
- k = sigma * sigma * 2;
+ k = sigma * sigma * 2.;
c = M_PI * k;
- c = sqrt(c);
c = 1.0 / c;
k = 1.0 / -k;
-
- for (x = 0; x <= spread; x++) {
- value = (double)(spread - x);
- value *= value * k;
- value = exp(value) * c;
- for (y = 0; y < *rows; y++) {
+ for (y = 0; y < 2 * spread + 1; y++) {
+ yy = (ssize_t)spread - (ssize_t)y, yy *= yy;
+ for (x = 0; x < 2 * spread + 1; x++) {
+ xx = (ssize_t)spread - (ssize_t)x, xx *= xx;
+ value = (double)(xx + yy) * k;
+ value = exp(value) * c;
(*free_this)[y * *cols + x] = value;
- (*free_this)[y + 1 * *cols + *cols - 1 - x] = value;
- }
- }
-
- for (y = 0; y <= spread; y++) {
- value = (double)(spread - y);
- value *= value * k;
- value = exp(value) * c;
- for (x = 0; x < *cols; x++) {
- (*free_this)[y * *cols + x] *= value;
- (*free_this)[y + 1 * *cols + *cols - 1 - x] *= value;
}
}
@@ -235,13 +224,16 @@ main(int argc, char *argv[])
usage();
} ARGEND;
+ if (!argc)
+ usage();
+
if (null_x && null_y && null_z && null_a)
null_x = null_y = null_z = null_a = 0;
if (0);
#define X(FUNC, NAME)\
else if (!strcmp(argv[0], NAME))\
- kernel = FUNC(argc, argv + 1, &rows, &cols, &free_this);
+ kernel = FUNC(argc - 1, argv + 1, &rows, &cols, &free_this);
LIST_KERNELS
#undef X
else
diff --git a/src/blind-spatial-arithm.c b/src/blind-spatial-arithm.c
new file mode 100644
index 0000000..b63dc89
--- /dev/null
+++ b/src/blind-spatial-arithm.c
@@ -0,0 +1,94 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("operation")
+
+/* Because the syntax for a function returning a function pointer is disgusting. */
+typedef void (*process_func)(struct stream *stream);
+
+#define LIST_OPERATORS(PIXFMT, TYPE)\
+ X(add, img[j & 3] + *buf, PIXFMT, TYPE)\
+ X(mul, img[j & 3] * *buf, PIXFMT, TYPE)\
+ X(min, MIN(img[j & 3], *buf), PIXFMT, TYPE)\
+ X(max, MAX(img[j & 3], *buf), PIXFMT, TYPE)
+
+#define X(NAME, ALGO, PIXFMT, TYPE)\
+ static void\
+ process_##PIXFMT##_##NAME(struct stream *stream)\
+ {\
+ TYPE img[4], *buf;\
+ size_t i, n, j = 0, m = stream->frame_size / sizeof(*img);\
+ int first = 1;\
+ do {\
+ n = stream->ptr / stream->pixel_size * stream->n_chan;\
+ buf = (TYPE *)(stream->buf);\
+ for (i = 0; i < n; i++, buf++, j++, j %= m) {\
+ if (!j) {\
+ if (!first)\
+ ewriteall(STDOUT_FILENO, img, sizeof(img), "<stdout>");\
+ first = 0;\
+ img[0] = *buf++;\
+ img[1] = *buf++;\
+ img[2] = *buf++;\
+ img[3] = *buf;\
+ i += 3;\
+ j = 3;\
+ } else {\
+ img[j & 3] = ALGO;\
+ }\
+ }\
+ n *= sizeof(TYPE);\
+ memmove(stream->buf, stream->buf + n, stream->ptr -= n);\
+ } while (eread_stream(stream, SIZE_MAX));\
+ if (!first)\
+ ewriteall(STDOUT_FILENO, img, sizeof(img), "<stdout>");\
+ }
+LIST_OPERATORS(lf, double)
+LIST_OPERATORS(f, float)
+#undef X
+
+static process_func
+get_process_lf(const char *operation)
+{
+#define X(NAME, _ALGO, PIXFMT, TYPE)\
+ if (!strcmp(operation, #NAME)) return process_##PIXFMT##_##NAME;
+ LIST_OPERATORS(lf, double)
+#undef X
+ eprintf("algorithm not recognised: %s\n", operation);
+ return NULL;
+}
+
+static process_func
+get_process_f(const char *operation)
+{
+#define X(NAME, _ALGO, PIXFMT, TYPE)\
+ if (!strcmp(operation, #NAME)) return process_##PIXFMT##_##NAME;
+ LIST_OPERATORS(f, float)
+#undef X
+ eprintf("algorithm not recognised: %s\n", operation);
+ return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stream stream;
+ process_func process;
+
+ UNOFLAGS(argc != 1);
+
+ eopen_stream(&stream, NULL);
+ echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
+
+ if (stream.encoding == DOUBLE)
+ process = get_process_lf(argv[0]);
+ else
+ process = get_process_f(argv[0]);
+
+ if (DPRINTF_HEAD(STDOUT_FILENO, stream.frames, 1, 1, stream.pixfmt) < 0)
+ eprintf("dprintf:");
+ process(&stream);
+ if (stream.ptr)
+ eprintf("%s: incomplete frame\n", stream.file);
+ return 0;
+}
diff --git a/src/blind-spatial-mean.c b/src/blind-spatial-mean.c
new file mode 100644
index 0000000..848af2d
--- /dev/null
+++ b/src/blind-spatial-mean.c
@@ -0,0 +1,142 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("[-g | -h | -l power | -p power | -v]")
+/* TODO add [-w weight-stream] for -l */
+
+/* Because the syntax for a function returning a function pointer is disgusting. */
+typedef void (*process_func)(struct stream *stream);
+
+/*
+ * X-parameter 1: method enum value
+ * X-parameter 2: identifier-friendly name
+ * X-parameter 3: initial assignments
+ * X-parameter 4: initial value
+ * X-parameter 5: subcell processing
+ * X-parameter 6: subcell finalisation
+ */
+#define LIST_MEANS(TYPE)\
+ /* [default] arithmetic mean */\
+ X(ARITHMETIC, arithmetic,, 0, img[j & 3] += *buf, img[j & 3] /= pixels)\
+ /* geometric mean */\
+ X(GEOMETRIC, geometric,, 1, img[j & 3] *= *buf, img[j & 3] = nnpow(img[j & 3], 1 / pixels))\
+ /* harmonic mean */\
+ X(HARMONIC, harmonic,, 0, img[j & 3] += (TYPE)1 / *buf, img[j & 3] = pixels / img[j & 3])\
+ /* Lehmer mean */\
+ X(LEHMER, lehmer, (a = (TYPE)power, b = a - (TYPE)1), 0,\
+ (img[j & 3] += nnpow(*buf, a), aux[j & 3] += nnpow(*buf, b)), img[j & 3] /= aux[j & 3])\
+ /* power mean (Hölder mean) (m = 2 for root square mean; m = 3 for cubic mean) */\
+ X(POWER, power, a = (TYPE)power, 0, img[j & 3] += nnpow(*buf, a),\
+ img[j & 3] = nnpow(img[j & 3], (TYPE)(1. / power)) / pixels)\
+ /* variance */\
+ X(VARIANCE, variance,, 0, (img[j & 3] += *buf * *buf, aux[j & 3] += *buf),\
+ img[j & 3] = (img[j & 3] - aux[j & 3] * aux[j & 3] / pixels) / pixels)
+
+#define X(V, ...) V,
+enum method { LIST_MEANS() };
+#undef X
+
+static double power;
+
+#define MAKE_PROCESS(PIXFMT, TYPE,\
+ _1, NAME, INIT, INITIAL, PROCESS_SUBCELL, FINALISE_SUBCELL)\
+ static void\
+ process_##PIXFMT##_##NAME(struct stream *stream)\
+ {\
+ TYPE img[4], aux[4], *buf, a, b;\
+ TYPE pixels = (TYPE)(stream->frame_size / sizeof(img));\
+ size_t i, n, j = 0, m = stream->frame_size / sizeof(*img);\
+ int first = 1;\
+ INIT;\
+ do {\
+ n = stream->ptr / stream->pixel_size * stream->n_chan;\
+ buf = (TYPE *)(stream->buf);\
+ for (i = 0; i < n; i++, buf++, j++, j %= m) {\
+ if (!j) {\
+ if (!first) {\
+ for (j = 0; j < ELEMENTSOF(img); j++)\
+ FINALISE_SUBCELL;\
+ j = 0;\
+ ewriteall(STDOUT_FILENO, img, sizeof(img), "<stdout>");\
+ }\
+ first = 0;\
+ img[0] = aux[0] = INITIAL;\
+ img[1] = aux[1] = INITIAL;\
+ img[2] = aux[2] = INITIAL;\
+ img[3] = aux[3] = INITIAL;\
+ }\
+ PROCESS_SUBCELL;\
+ }\
+ n *= sizeof(TYPE);\
+ memmove(stream->buf, stream->buf + n, stream->ptr -= n);\
+ } while (eread_stream(stream, SIZE_MAX));\
+ if (!first) {\
+ for (j = 0; j < ELEMENTSOF(img); j++)\
+ FINALISE_SUBCELL;\
+ ewriteall(STDOUT_FILENO, img, sizeof(img), "<stdout>");\
+ }\
+ (void) aux, (void) a, (void) b, (void) pixels;\
+ }
+#define X(...) MAKE_PROCESS(lf, double, __VA_ARGS__)
+LIST_MEANS(double)
+#undef X
+#define X(...) MAKE_PROCESS(f, float, __VA_ARGS__)
+LIST_MEANS(float)
+#undef X
+#undef MAKE_PROCESS
+
+#define X(ID, NAME, ...) [ID] = process_lf_##NAME,
+static const process_func process_functions_lf[] = { LIST_MEANS() };
+#undef X
+
+#define X(ID, NAME, ...) [ID] = process_f_##NAME,
+static const process_func process_functions_f[] = { LIST_MEANS() };
+#undef X
+
+int
+main(int argc, char *argv[])
+{
+ struct stream stream;
+ process_func process;
+ enum method method = ARITHMETIC;
+
+ ARGBEGIN {
+ case 'g':
+ method = GEOMETRIC;
+ break;
+ case 'h':
+ method = HARMONIC;
+ break;
+ case 'l':
+ method = LEHMER;
+ power = etolf_flag('l', UARGF());
+ break;
+ case 'p':
+ method = POWER;
+ power = etolf_flag('p', UARGF());
+ break;
+ case 'v':
+ method = VARIANCE;
+ break;
+ default:
+ usage();
+ } ARGEND;
+
+ if (argc)
+ usage();
+
+ eopen_stream(&stream, NULL);
+
+ if (stream.encoding == DOUBLE)
+ process = process_functions_lf[method];
+ else
+ process = process_functions_f[method];
+
+
+ if (DPRINTF_HEAD(STDOUT_FILENO, stream.frames, 1, 1, stream.pixfmt) < 0)
+ eprintf("dprintf:");
+ process(&stream);
+ if (stream.ptr)
+ eprintf("%s: incomplete frame\n", stream.file);
+ return 0;
+}
diff --git a/src/blind-stack.c b/src/blind-stack.c
index e74b62d..29e20b0 100644
--- a/src/blind-stack.c
+++ b/src/blind-stack.c
@@ -52,6 +52,7 @@ main(int argc, char *argv[])
break;
case 's':
shortest = 1;
+ frames = SIZE_MAX;
break;
default:
usage();
diff --git a/src/blind-temporal-arithm.c b/src/blind-temporal-arithm.c
new file mode 100644
index 0000000..f9f7b51
--- /dev/null
+++ b/src/blind-temporal-arithm.c
@@ -0,0 +1,94 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("operation")
+
+/* Because the syntax for a function returning a function pointer is disgusting. */
+typedef void (*process_func)(struct stream *stream, void *image);
+
+#define LIST_OPERATORS(PIXFMT, TYPE)\
+ X(add, *img + *buf, PIXFMT, TYPE)\
+ X(mul, *img * *buf, PIXFMT, TYPE)\
+ X(min, MIN(*img, *buf), PIXFMT, TYPE)\
+ X(max, MAX(*img, *buf), PIXFMT, TYPE)
+
+#define X(NAME, ALGO, PIXFMT, TYPE)\
+ static void\
+ process_##PIXFMT##_##NAME(struct stream *stream, void *image)\
+ {\
+ TYPE *buf, *img = image;\
+ size_t i, n, j = 0, m = stream->frame_size / sizeof(TYPE);\
+ do {\
+ n = stream->ptr / sizeof(TYPE);\
+ buf = (TYPE *)(stream->buf);\
+ for (i = 0; i < n; i++, buf++) {\
+ *img = ALGO;\
+ if (++j == m) {\
+ j = 0;\
+ img = image;\
+ } else {\
+ img++;\
+ }\
+ }\
+ n *= sizeof(TYPE);\
+ memmove(stream->buf, stream->buf + n, stream->ptr -= n);\
+ } while (eread_stream(stream, SIZE_MAX));\
+ }
+LIST_OPERATORS(lf, double)
+LIST_OPERATORS(f, float)
+#undef X
+
+static process_func
+get_process_lf(const char *operation)
+{
+#define X(NAME, _ALGO, PIXFMT, TYPE)\
+ if (!strcmp(operation, #NAME)) return process_##PIXFMT##_##NAME;
+ LIST_OPERATORS(lf, double)
+#undef X
+ eprintf("algorithm not recognised: %s\n", operation);
+ return NULL;
+}
+
+static process_func
+get_process_f(const char *operation)
+{
+#define X(NAME, _ALGO, PIXFMT, TYPE)\
+ if (!strcmp(operation, #NAME)) return process_##PIXFMT##_##NAME;
+ LIST_OPERATORS(f, float)
+#undef X
+ eprintf("algorithm not recognised: %s\n", operation);
+ return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stream stream;
+ process_func process;
+ char *img;
+
+ UNOFLAGS(argc != 1);
+
+ eopen_stream(&stream, NULL);
+
+ if (stream.encoding == DOUBLE)
+ process = get_process_lf(argv[0]);
+ else
+ process = get_process_f(argv[0]);
+
+ echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
+ img = emalloc(stream.frame_size);
+ if (!eread_frame(&stream, img))
+ eprintf("video has no frames\n");
+
+ process(&stream, img);
+ if (stream.ptr)
+ eprintf("%s: incomplete frame\n", stream.file);
+
+ stream.frames = 1;
+ fprint_stream_head(stdout, &stream);
+ efflush(stdout, "<stdout>");
+ ewriteall(STDOUT_FILENO, img, stream.frame_size, "<stdout>");
+ free(img);
+ return 0;
+}
diff --git a/src/blind-temporal-mean.c b/src/blind-temporal-mean.c
index b80d2d3..12d0cad 100644
--- a/src/blind-temporal-mean.c
+++ b/src/blind-temporal-mean.c
@@ -1,8 +1,8 @@
/* See LICENSE file for copyright and license details. */
#include "common.h"
-USAGE("[-g | -h | -l power | -p power]")
-/* TODO add -w weight-stream */
+USAGE("[-g | -h | -l power | -p power | -v]")
+/* TODO add [-w weight-stream] for -l */
/* Because the syntax for a function returning a function pointer is disgusting. */
typedef void (*process_func)(struct stream *stream, void *buffer, void *image, size_t frame);
@@ -20,20 +20,23 @@ typedef void (*process_func)(struct stream *stream, void *buffer, void *image, s
#define LIST_MEANS(TYPE)\
/* [default] arithmetic mean */\
X(ARITHMETIC, arithmetic, 1, COPY_FRAME,, *img1 += *buf,\
- a = (TYPE)1.0 / (TYPE)frame, *img1 *= a)\
+ a = (TYPE)1 / (TYPE)frame, *img1 *= a)\
/* geometric mean */\
X(GEOMETRIC, geometric, 1, COPY_FRAME,, *img1 *= *buf,\
- a = (TYPE)1.0 / (TYPE)frame, *img1 = nnpow(*img1, a))\
+ a = (TYPE)1 / (TYPE)frame, *img1 = nnpow(*img1, a))\
/* harmonic mean */\
X(HARMONIC, harmonic, 1, ZERO_AND_PROCESS_FRAME,, *img1 += (TYPE)1 / *buf,\
a = (TYPE)frame, *img1 = a / *img1)\
- /* lehmer mean */\
+ /* Lehmer mean */\
X(LEHMER, lehmer, 2, ZERO_AND_PROCESS_FRAME, (a = (TYPE)power, b = a - (TYPE)1),\
(*img1 += nnpow(*buf, a), *img2 += nnpow(*buf, b)),, *img1 /= *img2)\
/* power mean (Hölder mean) (m = 2 for root square mean; m = 3 for cubic mean) */\
X(POWER, power, 1, ZERO_AND_PROCESS_FRAME, a = (TYPE)power,\
- *img1 += nnpow(*buf, a), (a = (TYPE)1 / (TYPE)frame, b = (TYPE)(1.0 / power)),\
- *img1 = a * nnpow(*img1, b))
+ *img1 += nnpow(*buf, a), (a = (TYPE)1 / (TYPE)frame, b = (TYPE)(1. / power)), \
+ *img1 = a * nnpow(*img1, b))\
+ /* variance */\
+ X(VARIANCE, variance, 2, ZERO_AND_PROCESS_FRAME,, (*img1 += *buf * *buf, *img2 += *buf),\
+ a = (TYPE)1 / (TYPE)frame, *img1 = (*img1 - *img2 * *img2 * a) * a)
enum first_frame_action {
COPY_FRAME,
@@ -54,34 +57,37 @@ static double power;
{\
TYPE *buf = buffer, *img1 = image, a, b;\
TYPE *img2 = (TYPE *)(((char *)image) + stream->frame_size);\
- size_t x, y;\
- if (!stream) {\
+ size_t x, y, z;\
+ if (!buf) {\
PRE_FINALISE;\
- for (y = 0; y < stream->height; y++)\
- for (x = 0; x < stream->width; x++, img1++, img2++, buf++)\
- FINALISE_SUBCELL;\
+ for (z = 0; z < stream->n_chan; z++)\
+ for (y = 0; y < stream->height; y++)\
+ for (x = 0; x < stream->width; x++, img1++, img2++)\
+ FINALISE_SUBCELL;\
} else {\
PRE_PROCESS;\
- for (y = 0; y < stream->height; y++)\
- for (x = 0; x < stream->width; x++, img1++, img2++, buf++)\
- PROCESS_SUBCELL;\
+ for (z = 0; z < stream->n_chan; z++)\
+ for (y = 0; y < stream->height; y++)\
+ for (x = 0; x < stream->width; x++, img1++, img2++, buf++) {\
+ PROCESS_SUBCELL;\
+ }\
}\
(void) img2, (void) a, (void) b, (void) frame;\
}
-#define X(...) MAKE_PROCESS(xyza, double, __VA_ARGS__)
+#define X(...) MAKE_PROCESS(lf, double, __VA_ARGS__)
LIST_MEANS(double)
#undef X
-#define X(...) MAKE_PROCESS(xyzaf, float, __VA_ARGS__)
+#define X(...) MAKE_PROCESS(f, float, __VA_ARGS__)
LIST_MEANS(float)
#undef X
#undef MAKE_PROCESS
-#define X(ID, NAME, ...) [ID] = process_xyza_##NAME,
-static const process_func process_functions_xyza[] = { LIST_MEANS() };
+#define X(ID, NAME, ...) [ID] = process_lf_##NAME,
+static const process_func process_functions_lf[] = { LIST_MEANS() };
#undef X
-#define X(ID, NAME, ...) [ID] = process_xyzaf_##NAME,
-static const process_func process_functions_xyzaf[] = { LIST_MEANS() };
+#define X(ID, NAME, ...) [ID] = process_f_##NAME,
+static const process_func process_functions_f[] = { LIST_MEANS() };
#undef X
int
@@ -109,6 +115,9 @@ main(int argc, char *argv[])
method = POWER;
power = etolf_flag('p', UARGF());
break;
+ case 'v':
+ method = VARIANCE;
+ break;
default:
usage();
} ARGEND;
@@ -130,12 +139,10 @@ main(int argc, char *argv[])
eopen_stream(&stream, NULL);
- if (!strcmp(stream.pixfmt, "xyza"))
- process = process_functions_xyza[method];
- else if (!strcmp(stream.pixfmt, "xyza f"))
- process = process_functions_xyzaf[method];
+ if (stream.encoding == DOUBLE)
+ process = process_functions_lf[method];
else
- eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt);
+ process = process_functions_f[method];
stream.frames = 1;
echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
@@ -149,14 +156,14 @@ main(int argc, char *argv[])
frames = 0;
if (first_frame_action == COPY_FRAME) {
- if (!eread_frame(&stream, buf))
+ if (!eread_frame(&stream, img))
eprintf("video is no frames\n");
frames++;
}
for (; eread_frame(&stream, buf); frames++)
process(&stream, buf, img, frames);
if (!frames)
- eprintf("video is no frames\n");
+ eprintf("video has no frames\n");
process(&stream, NULL, img, frames);
ewriteall(STDOUT_FILENO, img, stream.frame_size, "<stdout>");
diff --git a/src/stream.c b/src/stream.c
index 46fed64..b69f9a5 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -487,7 +487,7 @@ nprocess_multiple_streams(int status, struct stream *streams, size_t n_streams,
while (n_streams) {
n = SIZE_MAX;
for (i = 0; i < n_streams; i++) {
- if (streams[i].ptr < sizeof(streams->buf) && !enread_stream(status, streams + i, SIZE_MAX)) {
+ if (streams[i].ptr < streams->pixel_size && !enread_stream(status, streams + i, SIZE_MAX)) {
close(streams[i].fd);
streams[i].fd = -1;
if (shortest)
diff --git a/src/util.c b/src/util.c
index 3fc3716..41d8104 100644
--- a/src/util.c
+++ b/src/util.c
@@ -32,6 +32,11 @@ tollu(const char *s, unsigned long long int min, unsigned long long int max, uns
errno = ERANGE;
return -1;
}
+ if (!isdigit(s[*s == 'x' || *s == 'X' || *s == '#']) ||
+ (*s == '0' && !isdigit(s[1 + (*s == 'x' || *s == 'o' || *s == 'b')]))) {
+ errno = EINVAL;
+ return -1;
+ }
if (tolower(*s) == 'x' || *s == '#')
*out = strtoull(s + 1, &end, 16);
else if (*s == '0' && tolower(s[1]) == 'x')