(wrong string) ée

From: <git_AT_suckless.org>
Date: Tue, 25 Jul 2017 22:13:02 +0200 (CEST)

commit 835df7bd1e81852062dd70ce1a054fc9b510e50f
Author: Mattias Andrée <maandree_AT_kth.se>
AuthorDate: Tue Jul 25 22:12:23 2017 +0200
Commit: Mattias Andrée <maandree_AT_kth.se>
CommitDate: Tue Jul 25 22:12:23 2017 +0200

    Fix blind-kernel and blind-temporal-mean,d add blind-{spatial,temporal}-arithm and blind-spatial-mean, and add support for multiple streams in blind-arithm
    
    Signed-off-by: Mattias Andrée <maandree_AT_kth.se>

diff --git a/Makefile b/Makefile
index 8f6426b..1bc0f16 100644
--- a/Makefile
+++ b/Makefile
_AT_@ -43,6 +43,7 @@ BIN =\
         blind-interleave\
         blind-invert-luma\
         blind-invert-matrix\
+ blind-kernel\
         blind-linear-gradient\
         blind-make-kernel\
         blind-matrix-orthoproject\
_AT_@ -76,6 +77,8 @@ BIN =\
         blind-sinc-wave\
         blind-sine-wave\
         blind-skip-pattern\
+ blind-spatial-arithm\
+ blind-spatial-mean\
         blind-spectrum\
         blind-spiral-gradient\
         blind-split\
_AT_@ -85,6 +88,8 @@ BIN =\
         blind-square-gradient\
         blind-stack\
         blind-tee\
+ blind-temporal-arithm\
+ blind-temporal-mean\
         blind-time-blur\
         blind-triangular-wave\
         blind-to-image\
_AT_@ -97,13 +102,7 @@ BIN =\
         blind-triangle-tessellation\
         blind-unpremultiply\
         blind-vector-projection\
- blind-write-head\
- blind-kernel\
- blind-temporal-mean
-
-# TODO Not tested yet (and doesn't have any manpages):
-# blind-kernel
-# blind-temporal-mean
+ blind-write-head
 
 SH_SCRIPTS =\
         blind-rotate-90\
diff --git a/README b/README
index 8da87c7..f844730 100644
--- a/README
+++ b/README
_AT_@ -126,6 +126,9 @@ UTILITIES
        blind-invert-matrix(1)
               Invert matrix-video
 
+ blind-kernel(1)
+ Create a convolution matrix
+
        blind-linear-gradient(1)
               Generate a video with a linear gradient
 
_AT_@ -240,6 +243,12 @@ UTILITIES
        blind-skip-pattern(1)
               Skips frames in a video according to pattern
 
+ blind-spatial-arithm(1)
+ Perform simple arithmetic over all pixels for each frame in a video
+
+ blind-spatial-mean(1)
+ Calculate the mean over all pixel for each frame in a video
+
        blind-spectrum(1)
               Transform a gradient into a spectrum
 
_AT_@ -267,6 +276,12 @@ UTILITIES
        blind-tee(1)
               /dev/fd/ aware tee(1) implementation
 
+ blind-temporal-arithm(1)
+ Perform simple arithmetic over all frames in a video for each pixel
+
+ blind-temporal-mean(1)
+ Calculate the mean over all frames in a video for each pixel
+
        blind-time-blur(1)
               Draw new frames on top of old frames with partial alpha
 
diff --git a/TODO b/TODO
index ec222b4..fb62d11 100644
--- a/TODO
+++ b/TODO
_AT_@ -31,7 +31,6 @@ blind-mean mean of multiple streams
                         https://en.wikipedia.org/wiki/Identric_mean
                         https://en.wikipedia.org/wiki/Logarithmic_mean
                         https://en.wikipedia.org/wiki/Stolarsky_mean
-blind-temporal-arithm blind-arithm but over all frames in a video instead of over all streams
 blind-apply-icc apply ICC profile to video
 blind-convex-gradient create a gradient in the shape of a convex lens
 blind-concave-gradient create a gradient in the shape of a concave lens
_AT_@ -51,8 +50,6 @@ blind-from-video: add options to:
 
 blind-cone-gradient: add ability to make gradient superelliptic
 
-blind-arithm: add support for multiple streams
-
 Add [-j jobs] to blind-from-video and blind-to-video.
 
 long double is slightly faster than long.
diff --git a/man/blind-apply-kernel.1 b/man/blind-apply-kernel.1
index f09cc6e..a4c28f1 100644
--- a/man/blind-apply-kernel.1
+++ b/man/blind-apply-kernel.1
_AT_@ -63,6 +63,7 @@ A frame or row requires 32 bytes per pixel it contains.
 .SH SEE ALSO
 .BR blind (7),
 .BR blind-make-kernel (1),
+.BR blind-kernel (1),
 .BR blind-gauss-blur (1)
 .SH AUTHORS
 Mattias Andrée
diff --git a/man/blind-arithm.1 b/man/blind-arithm.1
index 6df053a..22d7fd7 100644
--- a/man/blind-arithm.1
+++ b/man/blind-arithm.1
_AT_@ -5,7 +5,7 @@ blind-arithm - Perform simple arithmetic on a video
 .B blind-arithm
 [-axyz]
 .I operation
-.I right-hand-stream
+.IR right-hand-stream \ ...
 .SH DESCRIPTION
 .B blind-arithm
 reads left-hand operands from stdin, and right-hand
_AT_@ -27,6 +27,16 @@ If stdin is shorter than
 the remainder of
 .I right-hand-stream
 is ignored but may be partially read.
+.P
+IF multiple
+.I right-hand-stream
+are specified, they are applied from left to right,
+with the exception for if
+.I operation
+is
+.BR exp ,
+in which case they are applied from right to left with
+stdin applied last.
 .SH OPERATIONS
 .TP
 .B add
_AT_@ -86,6 +96,10 @@ Do not modify the Z channel (the third channel).
 .BR blind-cross-product (1),
 .BR blind-quaternion-product (1),
 .BR blind-vector-projection (1),
+.BR blind-spatial-mean (1),
+.BR blind-spatial-arithm (1),
+.BR blind-temporal-mean (1),
+.BR blind-temporal-arithm (1),
 .BR blind-single-colour (1),
 .BR blind-set-alpha (1),
 .BR blind-set-luma (1),
diff --git a/man/blind-gauss-blur.1 b/man/blind-gauss-blur.1
index e0e84a9..7b92045 100644
--- a/man/blind-gauss-blur.1
+++ b/man/blind-gauss-blur.1
_AT_@ -81,6 +81,7 @@ memory. A frame requires 32 bytes per pixel it contains.
 .BR blind-single-colour (1),
 .BR blind-time-blur (1),
 .BR blind-make-kernel (1),
+.BR blind-kernel (1),
 .BR blind-apply-kernel (1)
 .SH AUTHORS
 Mattias Andrée
diff --git a/man/blind-kernel.1 b/man/blind-kernel.1
new file mode 100644
index 0000000..df789cc
--- /dev/null
+++ b/man/blind-kernel.1
_AT_@ -0,0 +1,116 @@
+.TH BLIND-KERNEL 1 blind
+.SH NAME
+blind-kernel - Create a convolution matrix
+.SH SYNOPSIS
+.B blind-kernel
+[-xyza]
+.I kernel
+.RI [ parameter ]\ ...
+.SH DESCRIPTION
+.B blind-kernel
+creates a convolution matrix that can be applied to
+a video using
+.BR blind-apply-kernel (1).
+The convolution matrix is created from a set
+of standard formulae. The formula is selected
+using the
+.I kernel
+argument and is tuned with
+.IR kernel -specific
+.IR parameter s.
+.SH KERNELS
+.TP
+.BI kirsch\ direction
+Create a Kirsch kernel with the specified
+.IR direction .
+The
+.I direction
+must be
+.B 1
+or
+.BR N ;
+.BR 2 ,
+.BR NW ,
+or
+.BR WN ;
+.BR 3
+or
+.BR W ;
+.BR 4 ,
+.BR SW ,
+or
+.BR WS ;
+.BR 5
+or
+.BR S ;
+.BR 6 ,
+.BR SE ,
+or
+.BR ES ;
+.BR 7
+or
+.BR E ;
+or
+.BR 8 ,
+.BR NE ,
+or
+.BR EN .
+.TP
+.RI ' \fBbox\ blur\fP '\ [-w\ weight ]\ [ spread \ |\ x-spread \ y-spread ]
+Creates a box blur kernel. Unless
+.B -w
+is used, the kernel is unweighted, otherwise it has the specified
+.IR weight .
+The kernel will have the spread 1, the specified
+.IR spread ,
+or
+.I x-spread
+as the horizontal spread and
+.I y-spread
+as the vertical spread.
+.TP
+.BR sharpen \ [-i]
+Creates a sharpen kernel. If
+.B -i
+is used, an intensified sharpen kernel is created.
+.TP
+.RI \fBgaussian\fP\ [-s\ spread ]\ [-u]\ standard-deviation
+Creates a Gaussian blur kernel with the standard deviation
+.IR standard-deviation .
+If
+.B -u
+is used, the a Gaussian unsharpen kernel is created. If
+.B -s
+is specified, the specified
+.I spread
+will be used, otherwise the spread will be selected automatically.
+.SH OPTIONS
+.TP
+.B -a
+Apply the values to the alpha channel, set the
+values for all unselected channels to zero.
+.TP
+.B -x
+Apply the values to the X channel, set the values
+for all unselected channels to zero.
+.TP
+.B -y
+Apply the values to the Y channel, set the values
+for all unselected channels to zero.
+.TP
+.B -z
+Apply the values to the Z channel, set the values
+for all unselected channels to zero.
+.SH NOTES
+.B blind-make-kernel
+Create a single frame, to that it can be stored to
+disc. When applying it to a video, you want to use
+.BR blind-repeat (1).
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-apply-kernel (1),
+.BR blind-kernel (1),
+.BR blind-repeat (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree_AT_kth.se >
diff --git a/man/blind-make-kernel.1 b/man/blind-make-kernel.1
index 903f489..69e3739 100644
--- a/man/blind-make-kernel.1
+++ b/man/blind-make-kernel.1
_AT_@ -73,11 +73,12 @@ for all unselected channels to zero.
 .SH NOTES
 .B blind-make-kernel
 Create a single frame, to that it can be stored to
-disk. When applying it to a video, you want to use
+disc. When applying it to a video, you want to use
 .BR blind-repeat (1).
 .SH SEE ALSO
 .BR blind (7),
 .BR blind-apply-kernel (1),
+.BR blind-kernel (1),
 .BR blind-repeat (1)
 .SH AUTHORS
 Mattias Andrée
diff --git a/man/blind-spatial-arithm.1 b/man/blind-spatial-arithm.1
new file mode 100644
index 0000000..f512944
--- /dev/null
+++ b/man/blind-spatial-arithm.1
_AT_@ -0,0 +1,35 @@
+.TH BLIND-SPATIAL-ARITHM 1 blind
+.SH NAME
+blind-spatial-arithm - Perform simple arithmetic over all pixels for each frame in a video
+.SH SYNOPSIS
+.B blind-spatial-arithm
+.I operation
+.SH DESCRIPTION
+.B blind-spatial-arithm
+reads a video from stdin and applies an arithmetic
+operation over all pixels, for each frame in the
+video, and prints the resulting video, with one
+pixel in each frame, to stdout.
+.SH OPERATIONS
+.TP
+.B add
+Calculate the sum of the operands.
+.TP
+.B mul
+Calculate the product of the operands.
+.TP
+.B min
+Select the lowest operand.
+.TP
+.B max
+Select the highest operand.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-temporal-arithm (1),
+.BR blind-arithm (1),
+.BR blind-spatial-mean (1),
+.BR blind-temporal-mean (1),
+.BR blind-rewrite-head (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree_AT_kth.se >
diff --git a/man/blind-spatial-mean.1 b/man/blind-spatial-mean.1
new file mode 100644
index 0000000..74ffa53
--- /dev/null
+++ b/man/blind-spatial-mean.1
_AT_@ -0,0 +1,48 @@
+.TH BLIND-SPATIAL-MEAN 1 blind
+.SH NAME
+blind-spatial-mean - Calculate the mean over all pixel for each frame in a video
+.SH SYNOPSIS
+.B blind-spatial-mean
+[-g | -h | -l
+.I power
+| -p
+.I power
+| -v]
+.SH DESCRIPTION
+.B blind-spatial-mean
+reads a video from stdin and calculates the mean
+over all pixels for frames, and outputs a
+video with one pixel in each frame, to stdout with
+the mean for each frame.
+.P
+Unless otherwise specified, the arithmetic mean
+is calculated.
+.SH OPTIONS
+.TP
+.B -g
+Calculate the geometric mean.
+.TP
+.B -h
+Calculate the harmonic mean.
+.TP
+.BR -l \ \fIpower\fP
+Calculate the Lehmer mean with the specified
+.IR power .
+.TP
+.BR -p \ \fIpower\fP
+Calculate the power mean (Hölder mean) with
+the specified
+.IR power .
+.TP
+.B -v
+Calculate the variance.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-temporal-arithm (1),
+.BR blind-spatial-arithm (1),
+.BR blind-arithm (1),
+.BR blind-temporal-mean (1),
+.BR blind-rewrite-head (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree_AT_kth.se >
diff --git a/man/blind-temporal-arithm.1 b/man/blind-temporal-arithm.1
new file mode 100644
index 0000000..1ccfc2a
--- /dev/null
+++ b/man/blind-temporal-arithm.1
_AT_@ -0,0 +1,39 @@
+.TH BLIND-TEMPORAL-ARITHM 1 blind
+.SH NAME
+blind-temporal-arithm - Perform simple arithmetic over all frames in a video for each pixel
+.SH SYNOPSIS
+.B blind-temporal-arithm
+.I operation
+.SH DESCRIPTION
+.B blind-temporal-arithm
+reads a video from stdin and applies an arithmetic
+operation over all frames in the video, for each
+pixel, and prints the resulting single-frame video
+to stdout.
+.SH OPERATIONS
+.TP
+.B add
+Calculate the sum of the operands.
+.TP
+.B mul
+Calculate the product of the operands.
+.TP
+.B min
+Select the lowest operand.
+.TP
+.B max
+Select the highest operand.
+.SH REQUIREMENTS
+.B blind-temporal-arithm
+requires enough free memory to load one full frames memory.
+A frame requires 32 bytes per pixel it contains.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-temporal-mean (1),
+.BR blind-spatial-arithm (1),
+.BR blind-spatial-mean (1),
+.BR blind-arithm (1),
+.BR blind-rewrite-head (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree_AT_kth.se >
diff --git a/man/blind-temporal-mean.1 b/man/blind-temporal-mean.1
new file mode 100644
index 0000000..88e0d0c
--- /dev/null
+++ b/man/blind-temporal-mean.1
_AT_@ -0,0 +1,60 @@
+.TH BLIND-TEMPORAL-MEAN 1 blind
+.SH NAME
+blind-temporal-mean - Calculate the mean over all frames in a video for each pixel
+.SH SYNOPSIS
+.B blind-temporal-mean
+[-g | -h | -l
+.I power
+| -p
+.I power
+| -v]
+.SH DESCRIPTION
+.B blind-temporal-mean
+reads a video from stdin and calculates the mean
+over all frames for each pixel, and outputs a
+single frame video to stdout with the mean for
+each pixel.
+.P
+Unless otherwise specified, the arithmetic mean
+is calculated.
+.SH OPTIONS
+.TP
+.B -g
+Calculate the geometric mean.
+.TP
+.B -h
+Calculate the harmonic mean.
+.TP
+.BR -l \ \fIpower\fP
+Calculate the Lehmer mean with the specified
+.IR power .
+.TP
+.BR -p \ \fIpower\fP
+Calculate the power mean (Hölder mean) with
+the specified
+.IR power .
+.TP
+.B -v
+Calculate the variance.
+.SH REQUIREMENTS
+.B blind-temporal-mean
+requires enough free memory to load two full frames memory.
+A frame requires 32 bytes per pixel it contains. If
+.B -l
+or
+.B -v
+is used, enough free memory to load three full frames
+memory is required.
+.P
+.B blind-temporal-mean
+is optimised for simplicity rather than memory usage.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-temporal-arithm (1),
+.BR blind-spatial-arithm (1),
+.BR blind-arithm (1),
+.BR blind-spatial-mean (1),
+.BR blind-rewrite-head (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree_AT_kth.se >
diff --git a/man/blind.7 b/man/blind.7
index acc4bb5..2e32b5e 100644
--- a/man/blind.7
+++ b/man/blind.7
_AT_@ -144,6 +144,9 @@ Invert the luminosity of a video
 .BR blind-invert-matrix (1)
 Invert matrix-video
 .TP
+.BR blind-kernel (1)
+Create a convolution matrix
+.TP
 .BR blind-linear-gradient (1)
 Generate a video with a linear gradient
 .TP
_AT_@ -255,6 +258,12 @@ Apply sine-wave repetition to gradient
 .BR blind-skip-pattern (1)
 Skips frames in a video according to pattern
 .TP
+.BR blind-spatial-arithm (1)
+Perform simple arithmetic over all pixels for each frame in a video
+.TP
+.BR blind-spatial-mean (1)
+Calculate the mean over all pixel for each frame in a video
+.TP
 .BR blind-spectrum (1)
 Transform a gradient into a spectrum
 .TP
_AT_@ -284,6 +293,12 @@ Overlay videos
 .BR tee (1)
 implementation
 .TP
+.BR blind-temporal-arithm (1)
+Perform simple arithmetic over all frames in a video for each pixel
+.TP
+.BR blind-temporal-mean (1)
+Calculate the mean over all frames in a video for each pixel
+.TP
 .BR blind-time-blur (1)
 Draw new frames on top of old frames with partial alpha
 .TP
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
_AT_@ -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;
_AT_@ -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
_AT_@ -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\
_AT_@ -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;
 }
 
_AT_@ -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;
_AT_@ -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;
                 }
         }
 
_AT_@ -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
_AT_@ -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
_AT_@ -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
_AT_@ -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
_AT_@ -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
_AT_@ -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);
_AT_@ -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,
_AT_@ -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
_AT_@ -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;
_AT_@ -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);
_AT_@ -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
_AT_@ -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
_AT_@ -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')
Received on Tue Jul 25 2017 - 22:13:02 CEST

This archive was generated by hypermail 2.3.0 : Tue Jul 25 2017 - 22:25:38 CEST