commit 6b998b5ed066aeece1146fe245b35965319b3cbd
parent 3ad57ea82389e52c72c310268bde8b8540fa408e
Author: Mattias Andrée <maandree@kth.se>
Date:   Wed, 10 May 2017 16:59:26 +0200
Cleaner code
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat:
37 files changed, 274 insertions(+), 332 deletions(-)
diff --git a/src/blind-arithm.c b/src/blind-arithm.c
@@ -2,11 +2,8 @@
 #include "stream.h"
 #include "util.h"
 
-#include <fcntl.h>
 #include <math.h>
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-axyz] operation right-hand-stream")
 
diff --git a/src/blind-compress.c b/src/blind-compress.c
@@ -2,9 +2,6 @@
 #include "stream.h"
 #include "util.h"
 
-#include <string.h>
-#include <unistd.h>
-
 USAGE("")
 
 static size_t
@@ -33,7 +30,7 @@ main(int argc, char *argv[])
 {
 	struct stream stream;
 	char *buf[2];
-	size_t n, parts, part, off;
+	size_t parts, part, off;
 	int i;
 	size_t *cmp = NULL;
 	size_t cmpsize = 0;
@@ -41,16 +38,15 @@ main(int argc, char *argv[])
 	UNOFLAGS(argc);
 
 	eopen_stream(&stream, NULL);
+	echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
 	fprint_stream_head(stdout, &stream);
 	efflush(stdout, "<stdout>");
 
-	echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, "<stdin>");
-	n = stream.width * stream.height * stream.pixel_size;
-	buf[0] = emalloc(n);
-	buf[1] = ecalloc(1, n);
+	buf[0] = emalloc(stream.frame_size);
+	buf[1] = ecalloc(1, stream.frame_size);
 
-	for (i = 0; eread_frame(&stream, buf[i], n); i ^= 1) {
-		parts = compare(buf[i], buf[i ^ 1], n, &cmp, &cmpsize);
+	for (i = 0; eread_frame(&stream, buf[i]); i ^= 1) {
+		parts = compare(buf[i], buf[i ^ 1], stream.frame_size, &cmp, &cmpsize);
 		for (off = part = 0; part < parts; part += 2) {
 			off += cmp[part];
 			ewriteall(STDOUT_FILENO, cmp + part, 2 * sizeof(size_t), "<stdout>");
diff --git a/src/blind-concat.c b/src/blind-concat.c
@@ -6,11 +6,7 @@
 # include <sys/epoll.h>
 #endif
 #include <sys/mman.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-o output-file [-j jobs]] first-stream ... last-stream")
 
@@ -104,7 +100,7 @@ concat_to_file_parallel(int argc, char *argv[], char *output_file, size_t jobs)
 	struct stream *streams;
 	size_t *ptrs;
 	char head[STREAM_HEAD_MAX];
-	size_t ptr, frame_size, frames = 0, next = 0, j;
+	size_t ptr, frames = 0, next = 0, j;
 	ssize_t headlen;
 	int fd, i, n, pollfd;
 
@@ -127,12 +123,11 @@ concat_to_file_parallel(int argc, char *argv[], char *output_file, size_t jobs)
 
 	SPRINTF_HEAD_ZN(head, frames, streams->width, streams->height, streams->pixfmt, &headlen);
 
-	echeck_frame_size(streams->width, streams->height, streams->pixel_size, 0, output_file);
-	frame_size = streams->width * streams->height * streams->pixel_size;
+	echeck_dimensions(streams, WIDTH | HEIGHT, NULL);
 	ptr = (size_t)headlen;
 	for (i = 0; i < argc; i++) {
 		ptrs[i] = ptr;
-		ptr += streams->frames * frame_size;
+		ptr += streams->frames * streams->frame_size;
 	}
 	if (ftruncate(fd, (off_t)ptr))
 		eprintf("ftruncate %s:", output_file);
diff --git a/src/blind-crop.c b/src/blind-crop.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <fcntl.h>
-#include <inttypes.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-s | -S | -t] width height left top")
 
@@ -16,7 +13,7 @@ main(int argc, char *argv[])
 	char *buf, *image, *p;
 	size_t width = 0, height = 0, left = 0, top = 0;
 	size_t right, right_start, bottom, bottom_start;
-	size_t off, yoff = 0, x, y, irown, orown, ptr, n, m;
+	size_t off, yoff = 0, x, y, irown, orown, ptr, m;
 	int tile = 0, keepsize = 0, keepsize_inv = 0;
 
 	ARGBEGIN {
@@ -56,11 +53,11 @@ main(int argc, char *argv[])
 	}
 	efflush(stdout, "<stdout>");
 
-	echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file);
-	n = stream.height * (irown = stream.width * stream.pixel_size);
-	buf = emalloc(n);
+	echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
+	irown = stream.row_size;
+	buf = emalloc(stream.frame_size);
 	orown = width * stream.pixel_size;
-	m = (tile || keepsize || keepsize_inv) ? n : height * orown;
+	m = (tile || keepsize || keepsize_inv) ? stream.frame_size : height * orown;
 	image = (keepsize || keepsize_inv) ? buf : emalloc(m);
 
 	left *= stream.pixel_size;
@@ -73,7 +70,7 @@ main(int argc, char *argv[])
 	bottom = stream.height - (bottom_start = top  + height);
 	right  = irown         - (right_start  = left + orown);
 
-	while (eread_frame(&stream, buf, n)) {
+	while (eread_frame(&stream, buf)) {
 		if (tile) {
 			for (ptr = y = 0; y < stream.height; y++) {
 				p = buf + ((y + yoff) % height + top) * irown;
diff --git a/src/blind-cut.c b/src/blind-cut.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <limits.h>
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("start-point (end-point | 'end') file")
 
@@ -13,7 +10,7 @@ int
 main(int argc, char *argv[])
 {
 	struct stream stream;
-	size_t frame_size, start = 0, end = 0, ptr, max;
+	size_t start = 0, end = 0, ptr, max;
 	ssize_t r;
 	char buf[BUFSIZ];
 	int to_end = 0;
@@ -36,19 +33,16 @@ main(int argc, char *argv[])
 	else if (end > stream.frames)
 		eprintf("end point is after end of video\n");
 	stream.frames = end - start;
+	echeck_dimensions(&stream, WIDTH | HEIGHT | LENGTH, NULL);
 	fprint_stream_head(stdout, &stream);
 	efflush(stdout, "<stdout>");
-	echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file);
-	frame_size = stream.width * stream.height * stream.pixel_size;
-	if (stream.frames > (size_t)SSIZE_MAX / frame_size)
-		eprintf("%s: video is too large\n", stream.file);
 
 	if (start >= end)
 		eprintf("%s\n", start > end ?
 			"start point is after end point" :
 			"refusing to create video with zero frames");
-	end   = end   * frame_size + stream.headlen;
-	start = start * frame_size + stream.headlen;
+	end   = end   * stream.frame_size + stream.headlen;
+	start = start * stream.frame_size + stream.headlen;
 
 	fadvise_sequential(stream.fd, start, end - start);
 	for (ptr = start; ptr < end; ptr += (size_t)r) {
diff --git a/src/blind-decompress.c b/src/blind-decompress.c
@@ -3,7 +3,6 @@
 #include "util.h"
 
 #include <string.h>
-#include <unistd.h>
 
 USAGE("")
 
@@ -12,35 +11,34 @@ main(int argc, char *argv[])
 {
 	struct stream stream;
 	char *buf;
-	size_t n, m, fptr, sptr, same = 0, diff = 0;
+	size_t m, fptr, sptr, same = 0, diff = 0;
 
 	UNOFLAGS(argc);
 
 	eopen_stream(&stream, NULL);
+	echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
 	fprint_stream_head(stdout, &stream);
 	efflush(stdout, "<stdout>");
 
-	echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, "<stdin>");
-	n = stream.width * stream.height * stream.pixel_size;
-	buf = ecalloc(1, n);
+	buf = ecalloc(1, stream.frame_size);
 
 	fptr = 0;
 	do {
 		sptr = 0;
 	again:
 		while (same) {
-			m = MIN(same, n - fptr);
+			m = MIN(same, stream.frame_size - fptr);
 			ewriteall(STDOUT_FILENO, buf + fptr, m, "<stdout>");
-			fptr = (fptr + m) % n;
+			fptr = (fptr + m) % stream.frame_size;
 			same -= m;
 		}
 
 		while (diff && sptr < stream.ptr) {
-			m = MIN(diff, n - fptr);
+			m = MIN(diff, stream.frame_size - fptr);
 			m = MIN(m, stream.ptr - sptr);
 			memcpy(buf + fptr, stream.buf + sptr, m);
 			ewriteall(STDOUT_FILENO, buf + fptr, m, "<stdout>");
-			fptr = (fptr + m) % n;
+			fptr = (fptr + m) % stream.frame_size;
 			diff -= m;
 			sptr += m;
 		}
diff --git a/src/blind-dissolve.c b/src/blind-dissolve.c
@@ -3,7 +3,6 @@
 #include "util.h"
 
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-r]")
 
diff --git a/src/blind-extend.c b/src/blind-extend.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <fcntl.h>
-#include <inttypes.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-l left] [-r right] [-a above] [-b below] [-t]")
 
@@ -14,7 +11,7 @@ main(int argc, char *argv[])
 {
 	struct stream stream;
 	char *buf, *image;
-	size_t n, m, imgw, imgh, rown;
+	size_t m, imgw, imgh, rown;
 	size_t xoff, yoff, h, x, y;
 	size_t left = 0, right = 0, top = 0, bottom = 0;
 	int tile = 0;
@@ -44,9 +41,8 @@ main(int argc, char *argv[])
 
 	eopen_stream(&stream, NULL);
 
-	echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file);
-	n = stream.height * stream.width * stream.pixel_size;
-	buf = emalloc(n);
+	echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
+	buf = emalloc(stream.frame_size);
 
 	if (stream.width > SIZE_MAX - left)
 		eprintf("<stdout>: output video is too wide\n");
@@ -60,7 +56,7 @@ main(int argc, char *argv[])
 	if (imgh > SIZE_MAX - bottom)
 		eprintf("<stdout>: output video is too tall\n");
 	imgh += bottom;
-	echeck_frame_size(imgw, imgh, stream.pixel_size, "output", "<stdout>");
+	echeck_dimensions_custom(imgw, imgh, 0, stream.pixel_size, "output", "<stdout>");
 	m = imgh * (imgw *= stream.pixel_size);
 	image = tile ? emalloc(m) : ecalloc(1, m);
 
@@ -78,7 +74,7 @@ main(int argc, char *argv[])
 	xoff = (rown          - left % rown)          % rown;
 	yoff = (stream.height - top  % stream.height) % stream.height;
 
-	while (eread_frame(&stream, buf, n)) {
+	while (eread_frame(&stream, buf)) {
 		if (!tile) {
 			for (y = 0; y < stream.height; y++)
 				memcpy(image + left + (y + top) * imgw, buf + y * rown, rown);
diff --git a/src/blind-flip.c b/src/blind-flip.c
@@ -2,31 +2,27 @@
 #include "stream.h"
 #include "util.h"
 
-#include <string.h>
-#include <unistd.h>
-
 USAGE("")
 
 int
 main(int argc, char *argv[])
 {
 	struct stream stream;
-	size_t n, rown, ptr;
+	size_t ptr;
 	char *buf;
 
 	UNOFLAGS(argc);
 
 	eopen_stream(&stream, NULL);
+	echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
 	fprint_stream_head(stdout, &stream);
 	efflush(stdout, "<stdout>");
+	buf = emalloc(stream.frame_size);
 
-	echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file);
-	n = stream.height * (rown = stream.width * stream.pixel_size);
-	buf = emalloc(n);
-
-	while (eread_frame(&stream, buf, n))
-		for (ptr = n; ptr;)
-			ewriteall(STDOUT_FILENO, buf + (ptr -= rown), rown, "<stdout>");
+	while (eread_frame(&stream, buf))
+		for (ptr = stream.frame_size; ptr;)
+			ewriteall(STDOUT_FILENO, buf + (ptr -= stream.row_size),
+				  stream.row_size, "<stdout>");
 	/* ewriteall is faster than writev(3) and vmsplice(3) */
 
 	free(buf);
diff --git a/src/blind-flop.c b/src/blind-flop.c
@@ -2,10 +2,6 @@
 #include "stream.h"
 #include "util.h"
 
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-
 USAGE("")
 
 static struct stream stream;
@@ -14,41 +10,40 @@ static size_t n, m, ps;
 
 #define PROCESS(TYPE)\
 	do {\
-		size_t i, j, pst = ps / sizeof(TYPE);\
-		size_t nt = n / sizeof(TYPE);\
-		size_t mt = m / sizeof(TYPE);\
-		for (i = 0; i < pst; i++)\
-			for (j = 0; j < nt; j += pst)\
-				((TYPE *)image)[mt - j + i] = ((TYPE *)buf)[i + j];\
+		size_t i, j;\
+		for (i = 0; i < ps; i++)\
+			for (j = 0; j < n; j += ps)\
+				((TYPE *)image)[m - j + i] = ((TYPE *)buf)[i + j];\
 	} while (0)
 
-static void process_double(void) {PROCESS(double);}
-static void process_float (void) {PROCESS(float);}
-static void process_char  (void) {PROCESS(char);}
+static void process_long(void) {PROCESS(long);}
+static void process_char(void) {PROCESS(char);}
 
 int
 main(int argc, char *argv[])
 {
-	void (*process)(void);
+	void (*process)(void) = process_char;
 
 	UNOFLAGS(argc);
 
 	eopen_stream(&stream, NULL);
+	echeck_dimensions(&stream, WIDTH, NULL);
 	fprint_stream_head(stdout, &stream);
 	efflush(stdout, "<stdout>");
+	buf   = emalloc(stream.row_size);
+	image = emalloc(stream.row_size);
+
+	m = (n = stream.row_size) - (ps = stream.pixel_size);
+	if (!(stream.pixel_size % sizeof(long))) {
+		process = process_long;
+		m  /= sizeof(long);
+		n  /= sizeof(long);
+		ps /= sizeof(long);
+	}
 
-	echeck_frame_size(stream.width, 1, stream.pixel_size, 0, stream.file);
-	n = stream.width * (ps = stream.pixel_size);
-	buf   = emalloc(n);
-	image = emalloc(n);
-
-	process = !(ps % sizeof(double)) ? process_double :
-		  !(ps % sizeof(float))  ? process_float  : process_char;
-
-	m = n - ps;
-	while (eread_row(&stream, buf, n)) {
+	while (eread_row(&stream, buf)) {
 		process();
-		ewriteall(STDOUT_FILENO, image, n, "<stdout>");
+		ewriteall(STDOUT_FILENO, image, stream.row_size, "<stdout>");
 	}
 
 	free(buf);
diff --git a/src/blind-from-image.c b/src/blind-from-image.c
@@ -3,16 +3,14 @@
 #include "util.h"
 
 #include <arpa/inet.h>
-#include <sys/wait.h>
 #include <inttypes.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-h] [-f | -p]")
 
 static char buf[BUFSIZ];
-static char width[3 * sizeof(size_t) + 1] = {0};
-static char height[3 * sizeof(size_t) + 1] = {0};
+static char width[INTSTRLEN(size_t) + 1] = {0};
+static char height[INTSTRLEN(size_t) + 1] = {0};
 static const char *conv_fail_msg = "convertion failed, if converting a farbfeld file, try -f";
 static size_t pixel_size;
 static double value_max;
@@ -143,7 +141,7 @@ pam_head(int fd, const char *fname)
 				else if (!strcmp(buf, "TUPLTYPE RGB_ALPHA"))
 					with_colour = 1, with_alpha = 1;
 				else
-					eprintf("image uses an unsupported tuple type: %s\n", buf + sizeof("TUPLTYPE"));
+					eprintf("image uses an unsupported tuple type: %s\n", buf + STRLEN("TUPLTYPE "));
 			} else if (!strcmp(buf, "ENDHDR")) {
 				memmove(buf, p, ptr -= (size_t)(p - buf));
 				goto header_done;
diff --git a/src/blind-from-text.c b/src/blind-from-text.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <stdio.h>
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("")
 
diff --git a/src/blind-from-video.c b/src/blind-from-video.c
@@ -4,9 +4,6 @@
 
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 
 USAGE("[-F pixel-format] [-r frame-rate] [-w width -h height] [-dL] input-file output-file")
@@ -135,7 +132,7 @@ convert_segment_xyzaf(char *buf, size_t n, int fd, const char *file)
 static void
 convert(const char *infile, int outfd, const char *outfile, size_t width, size_t height, const char *frame_rate)
 {
-	char geometry[2 * 3 * sizeof(size_t) + 2], buf[BUFSIZ];
+	char geometry[2 * INTSTRLEN(size_t) + 2], buf[BUFSIZ];
 	const char *cmd[13];
 	int status, pipe_rw[2];
 	size_t i = 0, n, ptr;
diff --git a/src/blind-gauss-blur.c b/src/blind-gauss-blur.c
@@ -2,12 +2,8 @@
 #include "stream.h"
 #include "util.h"
 
-#include <fcntl.h>
-#include <limits.h>
 #include <math.h>
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-j jobs] [-s spread | -s 'auto'] [-achvy] sd-stream")
 
@@ -29,15 +25,15 @@ static size_t spread = 0;
  * and smears it out to the other pixels.
  */
 
-#define BLUR_PIXEL_PROLOGUE(DIR)\
+#define BLUR_PIXEL_PROLOGUE(TYPE, DIR)\
 	if (sig[i1][3] == 0)\
 		goto no_blur_##DIR;\
 	if (chroma || measure_y_only) {\
 		k[0] = sig[i1][1] * sig[i1][3];\
 		if (auto_spread)\
-			spread = k[0] > 0 ? (size_t)(k[0] * 3 + 0.5) : 0;\
+			spread = k[0] > 0 ? (size_t)(k[0] * 3 + (TYPE)0.5) : 0;\
 		blur[2] = blur[0] = k[0] > 0;\
-		c[0] = k[0] *= k[0] * 2, c[0] = sqrt(c[0] * M_PI);\
+		c[0] = k[0] *= k[0] * 2, c[0] = sqrt(c[0] * (TYPE)M_PI);\
 		k[0] = 1 / -k[0], c[0] = 1 / c[0];\
 		if (chroma) {\
 			k[2] = k[0];\
@@ -54,10 +50,10 @@ static size_t spread = 0;
 			spread = 0;\
 		for (i = 0; i < 3; i++) {\
 			k[i] = sig[i1][i] * sig[i1][3];\
-			if (auto_spread && k[i] > 0 && spread < (size_t)(k[i] * 3 + 0.5))\
-				spread = (size_t)(k[i] * 3 + 0.5);\
+			if (auto_spread && k[i] > 0 && spread < (size_t)(k[i] * 3 + (TYPE)0.5))\
+				spread = (size_t)(k[i] * 3 + (TYPE)0.5);\
 			blur[i] = k[i] > 0;\
-			c[i] = k[i] *= k[i] * 2, c[i] = sqrt(c[i] * M_PI);\
+			c[i] = k[i] *= k[i] * 2, c[i] = sqrt(c[i] * (TYPE)M_PI);\
 			k[i] = 1 / -k[i], c[i] = 1 / c[i];\
 		}\
 	}\
@@ -93,7 +89,7 @@ static size_t spread = 0;
 			for (LOOP) {\
 				d = (DISTANCE);\
 				d *= d;\
-				m = c[i] * exp(d * k[i]);\
+				m = c[i] * exp##SUFFIX(d * k[i]);\
 				img[i2][i] += clr[i1][i] * m;\
 				img[i2][3] += clr[i1][3] * m / blurred;\
 			}\
@@ -108,15 +104,15 @@ static size_t spread = 0;
 	img[i1][2] = clr[i1][2];\
 	img[i1][3] = clr[i1][3];
 
-#define BLUR(DIR, SETSTART, SETEND, START, LOOP, DISTANCE, SUFFIX)\
+#define BLUR(TYPE, DIR, SETSTART, SETEND, START, LOOP, DISTANCE, SUFFIX)\
 	do {\
-		memset(img, 0, cn);\
+		memset(img, 0, colour->frame_size);\
 		start = 0, end = colour->height;\
 		is_master = efork_jobs(&start, &end, jobs, &children);\
 		i1 = start * colour->width;\
 		for (y1 = start; y1 < end; y1++) {\
 			for (x1 = 0; x1 < colour->width; x1++, i1++) {\
-				BLUR_PIXEL_PROLOGUE(DIR);\
+				BLUR_PIXEL_PROLOGUE(TYPE, DIR);\
 				if (spread) {\
 					SETSTART;\
 					SETEND;\
@@ -168,8 +164,8 @@ static size_t spread = 0;
 				i1 = start * colour->width;\
 				for (y1 = start; y1 < end; y1++) {\
 					for (x1 = 0; x1 < colour->width; x1++, i1++) {\
-						clr[i1][0] = clr[i1][0] / D65_XYZ_X - clr[i1][1];\
-						clr[i1][2] = clr[i1][2] / D65_XYZ_Z - clr[i1][1];\
+						clr[i1][0] = clr[i1][0] / (TYPE)D65_XYZ_X - clr[i1][1];\
+						clr[i1][2] = clr[i1][2] / (TYPE)D65_XYZ_Z - clr[i1][1];\
 						/*
 						 * Explaination:
 						 *   Y is the luma and ((X / Xn - Y / Yn), (Z / Zn - Y / Yn))
@@ -225,7 +221,7 @@ static size_t spread = 0;
 		\
 		/* blur */\
 		if (horizontal)\
-			BLUR(horizontal,\
+			BLUR(TYPE, horizontal,\
 			     x2start = spread > x1 ? 0 : x1 - spread,\
 			     x2end = spread + 1 > colour->width - x1 ? colour->width : x1 + spread + 1,\
 			     i2 = y1 * colour->width + x2start,\
@@ -233,9 +229,9 @@ static size_t spread = 0;
 			     (ssize_t)x1 - (ssize_t)x2,\
 			     SUFFIX);\
 		if (horizontal && vertical)\
-			memcpy(clr, img, cn);\
+			memcpy(clr, img, colour->frame_size);\
 		if (vertical)\
-			BLUR(vertical,\
+			BLUR(TYPE, vertical,\
 			     y2start = spread > y1 ? 0 : y1 - spread,\
 			     y2end = spread + 1 > colour->height - y1 ? colour->height : y1 + spread + 1,\
 			     i2 = y2start * colour->width + x1,\
@@ -251,8 +247,8 @@ static size_t spread = 0;
 			i1 = start * colour->width;\
 			for (y1 = start; y1 < end; y1++) {\
 				for (x1 = 0; x1 < colour->width; x1++, i1++) {\
-					img[i1][0] = (img[i1][0] + img[i1][1]) * D65_XYZ_X;\
-					img[i1][2] = (img[i1][2] + img[i1][1]) * D65_XYZ_Z;\
+					img[i1][0] = (img[i1][0] + img[i1][1]) * (TYPE)D65_XYZ_X;\
+					img[i1][2] = (img[i1][2] + img[i1][1]) * (TYPE)D65_XYZ_Z;\
 				}\
 			}\
 		}\
@@ -280,19 +276,18 @@ static size_t spread = 0;
 		ejoin_jobs(is_master, children);\
 		\
 		(void) sigma;\
-		(void) sn;\
 	} while (0)
 
 static void
 process_xyza(char *restrict output, char *restrict cbuf, char *restrict sbuf,
-	     struct stream *colour, struct stream *sigma, size_t cn, size_t sn)
+	     struct stream *colour, struct stream *sigma)
 {
 	PROCESS(double,);
 }
 
 static void
 process_xyzaf(char *restrict output, char *restrict cbuf, char *restrict sbuf,
-	     struct stream *colour, struct stream *sigma, size_t cn, size_t sn)
+	     struct stream *colour, struct stream *sigma)
 {
 	PROCESS(float, f);
 }
@@ -303,7 +298,7 @@ main(int argc, char *argv[])
 	struct stream colour, sigma;
 	char *arg;
 	void (*process)(char *restrict output, char *restrict cbuf, char *restrict sbuf,
-			struct stream *colour, struct stream *sigma, size_t cn, size_t sn);
+			struct stream *colour, struct stream *sigma);
 
 	ARGBEGIN {
 	case 'a':
diff --git a/src/blind-invert-luma.c b/src/blind-invert-luma.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <fcntl.h>
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-iw] mask-stream")
 
diff --git a/src/blind-next-frame.c b/src/blind-next-frame.c
@@ -2,9 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <inttypes.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-f frames] width height pixel-format ...")
 
diff --git a/src/blind-read-head.c b/src/blind-read-head.c
@@ -3,7 +3,6 @@
 #include "util.h"
 
 #include <ctype.h>
-#include <unistd.h>
 
 USAGE("")
 
@@ -27,7 +26,7 @@ main(int argc, char *argv[])
 		goto bad_format;
 
 	p = buf;
-	for (i = 0; i < 5; i++)
+	for (i = 0; i < ELEMENTSOF(magic); i++)
 		if (!eread(STDIN_FILENO, &b, 1, "<stdin>") || b != magic[i])
 			goto bad_format;
 
diff --git a/src/blind-repeat.c b/src/blind-repeat.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <errno.h>
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("(count | 'inf') file")
 
diff --git a/src/blind-reverse.c b/src/blind-reverse.c
@@ -2,21 +2,18 @@
 #include "stream.h"
 #include "util.h"
 
-#include <limits.h>
-#include <unistd.h>
-
 USAGE("[-i] file")
 
 static void
-to_stdout(struct stream *stream, size_t frame_size)
+to_stdout(struct stream *stream)
 {
 	size_t ptr, end, n;
 	char buf[BUFSIZ];
 	ssize_t r;
 
 	while (stream->frames--) {
-		ptr = stream->frames * frame_size + stream->headlen;
-		end = ptr + frame_size;
+		ptr = stream->frames * stream->frame_size + stream->headlen;
+		end = ptr + stream->frame_size;
 		while (ptr < end) {
 			if (!(r = epread(stream->fd, buf, MIN(sizeof(buf), end - ptr), ptr, stream->file)))
 				eprintf("%s: file is shorter than expected\n", stream->file);
@@ -35,39 +32,39 @@ elseek_set(int fd, off_t offset, const char *fname)
 }
 
 static void
-epread_frame(struct stream *stream, char *buf, off_t off, size_t n)
+epread_frame(struct stream *stream, char *buf, off_t off)
 {
 	stream->ptr = stream->xptr = 0;
 	elseek_set(stream->fd, off, stream->file);
-	eread_frame(stream, buf, n);
+	eread_frame(stream, buf);
 }
 
 static void
-epwrite_frame(struct stream *stream, char *buf, off_t off, size_t n)
+epwrite_frame(struct stream *stream, char *buf, off_t off)
 {
 	elseek_set(stream->fd, off, stream->file);
-	ewriteall(stream->fd, buf, n, stream->file);
+	ewriteall(stream->fd, buf, stream->frame_size, stream->file);
 }
 
 static void
-in_place(struct stream *stream, size_t frame_size)
+in_place(struct stream *stream)
 {
 	size_t f, fm = stream->frames - 1;
 	off_t pa, pb;
 	char *bufa, *bufb;
 
-	bufa = emalloc(frame_size);
-	bufb = emalloc(frame_size);
+	bufa = emalloc(stream->frame_size);
+	bufb = emalloc(stream->frame_size);
 
 	for (f = 0; f < stream->frames >> 1; f++) {
-		pa = f        * frame_size + stream->headlen;
-		pb = (fm - f) * frame_size + stream->headlen;
+		pa = f        * stream->frame_size + stream->headlen;
+		pb = (fm - f) * stream->frame_size + stream->headlen;
 
-		epread_frame(stream, bufa, pa, frame_size);
-		epread_frame(stream, bufb, pb, frame_size);
+		epread_frame(stream, bufa, pa);
+		epread_frame(stream, bufb, pb);
 
-		epwrite_frame(stream, bufa, pb, frame_size);
-		epwrite_frame(stream, bufb, pa, frame_size);
+		epwrite_frame(stream, bufa, pb);
+		epwrite_frame(stream, bufb, pa);
 	}
 
 	free(bufa);
@@ -78,7 +75,6 @@ int
 main(int argc, char *argv[])
 {
 	struct stream stream;
-	size_t frame_size;
 	int inplace = 0;
 
 	ARGBEGIN {
@@ -99,17 +95,15 @@ main(int argc, char *argv[])
 		fprint_stream_head(stdout, &stream);
 		efflush(stdout, "<stdout>");
 	}
-	echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file);
-	frame_size = stream.width * stream.height * stream.pixel_size;
-	if (stream.frames > (size_t)SSIZE_MAX / frame_size ||
-	    stream.frames * frame_size > (size_t)SSIZE_MAX - stream.headlen)
+	echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
+	if (stream.frames * stream.frame_size > (size_t)SSIZE_MAX - stream.headlen)
 		eprintf("%s: video is too large\n", stream.file);
 
 #if defined(POSIX_FADV_RANDOM)
 	posix_fadvise(stream.fd, 0, 0, POSIX_FADV_RANDOM);
 #endif
 
-	(inplace ? in_place : to_stdout)(&stream, frame_size);
+	(inplace ? in_place : to_stdout)(&stream);
 	close(stream.fd);
 	return 0;
 }
diff --git a/src/blind-rewrite-head.c b/src/blind-rewrite-head.c
@@ -4,11 +4,7 @@
 
 #include <sys/mman.h>
 #include <sys/stat.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <inttypes.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-h] file [(frames | 'auto') [(width | 'same') (height | 'same') [format | 'same']]]")
 
@@ -17,20 +13,19 @@ rewrite(struct stream *stream, int frames_auto)
 {
 	char head[STREAM_HEAD_MAX];
 	ssize_t headlen;
-	size_t frame_size, frame_count, length;
+	size_t frame_count, length;
 	struct stat st;
 	char *data;
 
-	echeck_frame_size(stream->width, stream->height, stream->pixel_size, 0, stream->file);
-	frame_size = stream->width * stream->height * stream->pixel_size;
+	echeck_dimensions(stream, WIDTH | HEIGHT, NULL);
 
 	if (fstat(stream->fd, &st))
 		eprintf("fstat %s:", stream->file);
 	if (!S_ISREG(st.st_mode))
 		eprintf("%s: not a regular file\n", stream->file);
 
-	frame_count = (size_t)(st.st_size) / frame_size;
-	if (frame_count * frame_size != (size_t)(st.st_size) - stream->headlen)
+	frame_count = (size_t)(st.st_size) / stream->frame_size;
+	if (frame_count * stream->frame_size != (size_t)(st.st_size) - stream->headlen)
 		eprintf("%s: given the select width and height, "
 			"the file has an incomplete frame\n", stream->file);
 	if (frames_auto)
@@ -40,7 +35,7 @@ rewrite(struct stream *stream, int frames_auto)
 
 	SPRINTF_HEAD_ZN(head, stream->frames, stream->width, stream->height, stream->pixfmt, &headlen);
 
-	length = stream->frames * frame_size;
+	length = stream->frames * stream->frame_size;
 	if (length > (size_t)SSIZE_MAX || (size_t)headlen > (size_t)SSIZE_MAX - length)
 		eprintf("%s: video is too long\n", stream->file);
 
diff --git a/src/blind-set-alpha.c b/src/blind-set-alpha.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <fcntl.h>
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-i] alpha-stream")
 
diff --git a/src/blind-set-luma.c b/src/blind-set-luma.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <fcntl.h>
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("luma-stream")
 
diff --git a/src/blind-set-saturation.c b/src/blind-set-saturation.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <fcntl.h>
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-w] saturation-stream")
 
diff --git a/src/blind-single-colour.c b/src/blind-single-colour.c
@@ -2,9 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <inttypes.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-f frames | -f 'inf'] [-F pixel-format] -w width -h height (X Y Z | Y) [alpha]")
 
diff --git a/src/blind-skip-pattern.c b/src/blind-skip-pattern.c
@@ -2,20 +2,18 @@
 #include "stream.h"
 #include "util.h"
 
-#include <inttypes.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("(skipped-frames | +included-frames) ...")
 
 static int
-process_frame(struct stream *stream, int include, size_t rown)
+process_frame(struct stream *stream, int include)
 {
 	size_t h, n, m;
 	int anything = 0;
 
 	for (h = stream->height; h; h--) {
-		for (n = rown; n; n -= m, anything = 1) {
+		for (n = stream->row_size; n; n -= m, anything = 1) {
 			if (!stream->ptr && !eread_stream(stream, n))
 				goto done;
 			m = MIN(stream->ptr, n);
@@ -37,7 +35,7 @@ main(int argc, char *argv[])
 {
 	struct stream stream;
 	int i, include;
-	size_t f, n, rown, total = 0;
+	size_t f, n, total = 0;
 	char *includes;
 	size_t *ns;
 
@@ -64,16 +62,15 @@ main(int argc, char *argv[])
 			total += (size_t)include;
 	}
 
-	echeck_frame_size(stream.width, 1, stream.pixel_size, 0, stream.file);
-	rown = stream.width * stream.pixel_size;
 	stream.frames = total;
+	echeck_dimensions(&stream, WIDTH, NULL);
 	fprint_stream_head(stdout, &stream);
 	efflush(stdout, "<stdout>");
 
 	for (i = 0;; i = (i + 1) % argc) {
 		include = (int)includes[i];
 		for (n = ns[i]; n--;)
-			if (!process_frame(&stream, include, rown))
+			if (!process_frame(&stream, include))
 				goto done;
 	}
 
diff --git a/src/blind-split.c b/src/blind-split.c
@@ -3,11 +3,7 @@
 #include "util.h"
 
 #include <alloca.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-L] (file (end-point | 'end')) ...")
 
@@ -15,7 +11,7 @@ int
 main(int argc, char *argv[])
 {
 	struct stream stream;
-	size_t *ends, i, parts, ptr, end, frame_size, n;
+	size_t *ends, i, parts, ptr, end, n;
 	char *to_end;
 	FILE *fp;
 	int fd, unknown_length = 0;
@@ -32,10 +28,7 @@ main(int argc, char *argv[])
 		usage();
 
 	eopen_stream(&stream, NULL);
-	echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file);
-	frame_size = stream.width * stream.height * stream.pixel_size;
-	if (stream.frames > (size_t)SSIZE_MAX / frame_size)
-		eprintf("%s: video is too large\n", stream.file);
+	echeck_dimensions(&stream, WIDTH | HEIGHT | LENGTH, NULL);
 
 	parts = (size_t)argc / 2;
 	ends = alloca(parts * sizeof(*ends));
@@ -66,7 +59,7 @@ main(int argc, char *argv[])
 		fprint_stream_head(fp, &stream);
 		efflush(fp, argv[i * 2]);
 
-		for (end = to_end[i] ? SIZE_MAX : ends[i] * frame_size; ptr < end; ptr += n) {
+		for (end = to_end[i] ? SIZE_MAX : ends[i] * stream.frame_size; ptr < end; ptr += n) {
 			n = end - ptr;
 			if (stream.ptr) {
 				n = MIN(stream.ptr, n);
@@ -75,7 +68,7 @@ main(int argc, char *argv[])
 			} else if ((n = eread_stream(&stream, n))) {
 				ewriteall(fd, stream.buf, n, argv[i * 2]);
 				stream.ptr = 0;
-			} else if (ptr % frame_size) {
+			} else if (ptr % stream.frame_size) {
 				eprintf("%s: incomplete frame\n", stream.file);
 			} else if (!unknown_length || !to_end[i]) {
 				eprintf("%s: file is shorter than expected\n", stream.file);
diff --git a/src/blind-stack.c b/src/blind-stack.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <fcntl.h>
-#include <inttypes.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-b] bottom-stream ... top-stream")
 
diff --git a/src/blind-time-blur.c b/src/blind-time-blur.c
@@ -15,11 +15,11 @@ static int first = 1;
 		pixel_t *restrict clr = (pixel_t *)cbuf;\
 		pixel_t *restrict alf = (pixel_t *)abuf;\
 		pixel_t *img = (pixel_t *)output;\
-		size_t i, n = cn / sizeof(pixel_t);\
+		size_t i, n = colour->frame_size / sizeof(pixel_t);\
 		TYPE a1, a2;\
 		\
 		if (first) {\
-			memcpy(output, cbuf, cn);\
+			memcpy(output, cbuf, colour->frame_size);\
 			first = 0;\
 			return;\
 		}\
@@ -36,19 +36,18 @@ static int first = 1;
 		\
 		(void) colour;\
 		(void) alpha;\
-		(void) an;\
 	} while (0)
 
 static void
 process_xyza(char *output, char *restrict cbuf, char *restrict abuf,
-	     struct stream *colour, struct stream *alpha, size_t cn, size_t an)
+	     struct stream *colour, struct stream *alpha)
 {
 	PROCESS(double);
 }
 
 static void
 process_xyzaf(char *output, char *restrict cbuf, char *restrict abuf,
-	      struct stream *colour, struct stream *alpha, size_t cn, size_t an)
+	      struct stream *colour, struct stream *alpha)
 {
 	PROCESS(float);
 }
@@ -58,7 +57,7 @@ main(int argc, char *argv[])
 {
 	struct stream colour, alpha;
 	void (*process)(char *restrict output, char *restrict cbuf, char *restrict abuf,
-			struct stream *colour, struct stream *alpha, size_t cn, size_t an);
+			struct stream *colour, struct stream *alpha);
 
 	ARGBEGIN {
 	default:
@@ -79,7 +78,6 @@ main(int argc, char *argv[])
 		eprintf("pixel format %s is not supported, try xyza\n", colour.pixfmt);
 
 	echeck_compat(&colour, &alpha);
-
 	fprint_stream_head(stdout, &colour);
 	efflush(stdout, "<stdout>");
 	process_each_frame_two_streams(&colour, &alpha, STDOUT_FILENO, "<stdout>", process);
diff --git a/src/blind-to-image.c b/src/blind-to-image.c
@@ -3,11 +3,7 @@
 #include "util.h"
 
 #include <arpa/inet.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-d depth | -f]")
 
diff --git a/src/blind-to-text.c b/src/blind-to-text.c
@@ -2,9 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <stdint.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("")
 
diff --git a/src/blind-to-video.c b/src/blind-to-video.c
@@ -66,7 +66,7 @@ int
 main(int argc, char *argv[])
 {
 	struct stream stream;
-	char geometry[2 * 3 * sizeof(size_t) + 2];
+	char geometry[2 * INTSTRLEN(size_t) + 2];
 	char *frame_rate;
 	const char **cmd;
 	size_t n = 0;
diff --git a/src/blind-translate.c b/src/blind-translate.c
@@ -2,10 +2,7 @@
 #include "stream.h"
 #include "util.h"
 
-#include <inttypes.h>
-#include <math.h>
 #include <string.h>
-#include <unistd.h>
 
 USAGE("[-wp] translation-stream")
 
@@ -29,25 +26,24 @@ next_pixel(struct stream *stream, size_t *ptr)
 }
 
 static int
-process_frame(struct stream *stream, char *buf, size_t n,
-	      size_t above, size_t below, size_t left, size_t right)
+process_frame(struct stream *stream, char *buf, size_t above, size_t below, size_t left, size_t right)
 {
 #define ZEROES(N) ewritezeroes(STDOUT_FILENO, zeroes, sizeof(zeroes), N, "<stdout>")
 
-	size_t i, w = n - left - right;
+	size_t i, w = stream->row_size - left - right;
 	int first = 1;
 
-	if (!eread_row(stream, buf, n))
+	if (!eread_row(stream, buf))
 		return 0;
 
 	for (i = 0; i < above; i++)
-		ZEROES(n);
+		ZEROES(stream->row_size);
 	for (i = 0; i < below; i++, first = 0)
-		if (!first && !eread_row(stream, buf, n))
+		if (!first && !eread_row(stream, buf))
 			goto eof;
 
 	for (i = above + below; i < stream->height; i++, first = 0) {
-		if (!first && !eread_row(stream, buf, n))
+		if (!first && !eread_row(stream, buf))
 			goto eof;
 		ZEROES((size_t)left);
 		ewriteall(STDOUT_FILENO, buf + right, w, "<stdout>");
@@ -55,9 +51,9 @@ process_frame(struct stream *stream, char *buf, size_t n,
 	}
 
 	for (i = 0; i < below; i++)
-		ZEROES(n);
+		ZEROES(stream->row_size);
 	for (i = 0; i < above; i++, first = 0)
-		if (!first && !eread_row(stream, buf, n))
+		if (!first && !eread_row(stream, buf))
 			goto eof;
 
 	return 1;
@@ -70,16 +66,15 @@ static void
 process(struct stream *stream, struct stream *trstream)
 {
 	char *buf;
-	size_t n, p = 0;
+	size_t p = 0;
 	double *trans, tmp;
 	ssize_t trx = 0, try = 0;
 	size_t above = 0, below = 0, left = 0, right = 0;
 
 	memset(zeroes, 0, sizeof(zeroes));
 
-	echeck_frame_size(stream->width, 1, stream->pixel_size, 0, stream->file);
-	n = stream->width * stream->pixel_size;
-	buf = emalloc(n);
+	echeck_dimensions(stream, WIDTH, NULL);
+	buf = emalloc(stream->row_size);
 
 	do {
 		if ((trans = next_pixel(trstream, &p))) {
@@ -93,10 +88,10 @@ process(struct stream *stream, struct stream *trstream)
 
 			above = MIN(above, stream->height);
 			below = MIN(below, stream->height);
-			left  = MIN(left,  n);
-			right = MIN(right, n);
+			left  = MIN(left,  stream->row_size);
+			right = MIN(right, stream->row_size);
 		}
-	} while (process_frame(stream, buf, n, above, below, left, right));
+	} while (process_frame(stream, buf, above, below, left, right));
 
 	free(buf);
 }
@@ -105,16 +100,15 @@ static void
 process_wrap(struct stream *stream, struct stream *trstream)
 {
 	char *buf, *row;
-	size_t n, rown, p = 0;
+	size_t p = 0;
 	double *trans, tmp;
 	ssize_t trx = 0, try = 0, py;
 	size_t off = 0, y;
 
-	echeck_frame_size(stream->width, stream->height, stream->pixel_size, 0, "<stdin>");
-	n = stream->height * (rown = stream->width * stream->pixel_size);
-	buf = emalloc(n);
+	echeck_dimensions(stream, WIDTH | HEIGHT, NULL);
+	buf = emalloc(stream->frame_size);
 
-	while (eread_frame(stream, buf, n)) {
+	while (eread_frame(stream, buf)) {
 		if ((trans = next_pixel(trstream, &p))) {
 			trx = (ssize_t)(tmp = round(invtrans ? -trans[0] : trans[0]));
 			try = (ssize_t)(tmp = round(invtrans ? -trans[1] : trans[1]));
@@ -129,8 +123,8 @@ process_wrap(struct stream *stream, struct stream *trstream)
 			py = ((ssize_t)y - try) % (ssize_t)stream->height;
 			if (py < 0)
 				py += (ssize_t)stream->height;
-			row = buf + (size_t)py * rown;
-			ewriteall(STDOUT_FILENO, row + off, rown - off, "<stdout>");
+			row = buf + (size_t)py * stream->row_size;
+			ewriteall(STDOUT_FILENO, row + off, stream->row_size - off, "<stdout>");
 			ewriteall(STDOUT_FILENO, row, off, "<stdout>");
 		}
 	}
diff --git a/src/blind-transpose.c b/src/blind-transpose.c
@@ -2,11 +2,6 @@
 #include "stream.h"
 #include "util.h"
 
-#include <fcntl.h>
-#include <inttypes.h>
-#include <string.h>
-#include <unistd.h>
-
 USAGE("")
 
 static size_t srcw, srch, srcwps, srchps, ps;
@@ -23,38 +18,33 @@ static size_t srcw, srch, srcwps, srchps, ps;
 		}\
 	} while (0)
 
-static void process_double(char *row, char *col) {PROCESS(double);}
-static void process_float (char *row, char *col) {PROCESS(float);}
-static void process_char  (char *row, char *col) {PROCESS(char);}
+static void process_long(char *row, char *col) {PROCESS(long);}
+static void process_char(char *row, char *col) {PROCESS(char);}
 
 int
 main(int argc, char *argv[])
 {
 	struct stream stream;
 	char *buf, *image;
-	size_t n, y;
+	size_t y;
 	void (*process)(char *row, char *col);
 
 	UNOFLAGS(argc);
 
 	eopen_stream(&stream, NULL);
-	srch = stream.height;
-	stream.height = srcw = stream.width;
-	stream.width = srch;
+	echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
+	srch = stream.height, srchps = stream.col_size;
+	srcw = stream.width,  srcwps = stream.row_size;
+	stream.height = srcw;
+	stream.width  = srch;
 	fprint_stream_head(stdout, &stream);
 	efflush(stdout, "<stdout>");
 
-	echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file);
-	n = stream.height * stream.width * (ps = stream.pixel_size);
-	srchps = srch * ps;
-	srcwps = srcw * ps;
-	buf   = emalloc(n);
+	buf   = emalloc(stream.frame_size);
 	image = emalloc(srchps);
 
-	process = !(ps % sizeof(double)) ? process_double :
-		  !(ps % sizeof(float))  ? process_float  : process_char;
-
-	while (eread_frame(&stream, buf, n)) {
+	process = ps % sizeof(long) ? process_char : process_long;
+	while (eread_frame(&stream, buf)) {
 		for (y = 0; y < srcwps; y += ps) {
 			process(image, buf + y);
 			ewriteall(STDOUT_FILENO, image, srchps, "<stdout>");
diff --git a/src/stream.c b/src/stream.c
@@ -110,6 +110,9 @@ set_pixel_size(struct stream *stream)
 		stream->pixel_size = 4 * sizeof(float);
 	else
 		return -1;
+	stream->row_size   = stream->pixel_size * stream->width;
+	stream->col_size   = stream->pixel_size * stream->height;
+	stream->frame_size = stream->pixel_size * stream->height * stream->width;
 	return 0;
 }
 
@@ -152,27 +155,49 @@ eninf_check_fd(int status, int fd, const char *file)
 }
 
 
-int
-check_frame_size(size_t width, size_t height, size_t pixel_size)
-{
-	if (!height)
-		return !width || !pixel_size || !(width > SIZE_MAX / pixel_size);
-	if (!width)
-		return !height || !pixel_size || !(height > SIZE_MAX / pixel_size);
-	if (!pixel_size)
-		return 1;
-	if (width > SIZE_MAX / height)
-		return 0;
-	return !(width * height > SIZE_MAX / pixel_size);
-}
-
 void
-encheck_frame_size(int status, size_t width, size_t height, size_t pixel_size, const char *prefix, const char *fname)
+encheck_dimensions(int status, const struct stream *stream, enum dimension dimensions, const char *prefix)
 {
-	if (!check_frame_size(width, height, pixel_size))
-		enprintf(status, "%s: %s%svideo frame is too %s\n",
-			 fname, prefix ? prefix : "", (prefix && *prefix) ? " " : "",
-			 width <= 1 ? "tall" : height <= 1 ? "wide" : "large");
+	size_t n;
+
+	if (!stream->pixel_size)
+		enprintf(status, "%s: %s%svideo frame doesn't have a pixel size\n",
+			 stream->file, prefix ? prefix : "",
+			 (prefix && *prefix) ? " " : "");
+
+	n = SIZE_MAX / stream->pixel_size;
+
+	if ((dimensions & WIDTH) && stream->width > n)
+		enprintf(status, "%s: %s%svideo frame is too wide\n",
+			 stream->file, prefix ? prefix : "",
+			 (prefix && *prefix) ? " " : "");
+
+	if ((dimensions & HEIGHT) && stream->height > n)
+		enprintf(status, "%s: %s%svideo frame is too wide\n",
+			 stream->file, prefix ? prefix : "",
+			 (prefix && *prefix) ? " " : "");
+
+	if (!stream->width || !stream->height)
+		return;
+
+	if ((dimensions & (WIDTH | HEIGHT)) == (WIDTH | HEIGHT)) {
+		if (stream->width > n / stream->height)
+			enprintf(status, "%s: %s%svideo frame is too large\n",
+				 stream->file, prefix ? prefix : "",
+				 (prefix && *prefix) ? " " : "");
+	}
+
+	if (!(dimensions & LENGTH))
+		return;
+	if (dimensions & WIDTH)
+		n /= stream->width;
+	if (dimensions & HEIGHT)
+		n /= stream->height;
+
+	if (stream->frames > n)
+		enprintf(status, "%s: %s%svideo is too large\n",
+			 stream->file, prefix ? prefix : "",
+			 (prefix && *prefix) ? " " : "");
 }
 
 
@@ -220,7 +245,7 @@ get_pixel_format(const char *specified, const char *current)
 
 
 int
-enread_frame(int status, struct stream *stream, void *buf, size_t n)
+enread_segment(int status, struct stream *stream, void *buf, size_t n)
 {
 	char *buffer = buf;
 	ssize_t r;
@@ -267,13 +292,10 @@ void
 nprocess_each_frame_segmented(int status, struct stream *stream, int output_fd, const char* output_fname,
 			      void (*process)(struct stream *stream, size_t n, size_t frame))
 {
-	size_t frame_size, frame, r, n;
-
-	encheck_frame_size(status, stream->width, stream->height, stream->pixel_size, 0, stream->file);
-	frame_size = stream->height * stream->width * stream->pixel_size;
-
+	size_t frame, r, n;
+	encheck_dimensions(status, stream, WIDTH | HEIGHT, NULL);
 	for (frame = 0; frame < stream->frames; frame++) {
-		for (n = frame_size; n; n -= r) {
+		for (n = stream->frame_size; n; n -= r) {
 			if (stream->ptr < n && !enread_stream(status, stream, SIZE_MAX))
 				enprintf(status, "%s: file is shorter than expected\n", stream->file);
 			r = stream->ptr - (stream->ptr % stream->pixel_size);
@@ -386,39 +408,38 @@ nprocess_multiple_streams(int status, struct stream *streams, size_t n_streams, 
 void
 nprocess_each_frame_two_streams(int status, struct stream *left, struct stream *right, int output_fd, const char* output_fname,
 				void (*process)(char *restrict output, char *restrict lbuf, char *restrict rbuf,
-						struct stream *left, struct stream *right, size_t ln, size_t rn))
+						struct stream *left, struct stream *right))
 {
-	size_t lframe_size, rframe_size;
 	char *lbuf, *rbuf, *image;
 
-	encheck_frame_size(status, left->width,  left->height,  left->pixel_size,  0, left->file);
-	encheck_frame_size(status, right->width, right->height, right->pixel_size, 0, right->file);
-	lframe_size = left->height  * left->width  * left->pixel_size;
-	rframe_size = right->height * right->width * right->pixel_size;
+	encheck_dimensions(status, left,  WIDTH | HEIGHT, NULL);
+	encheck_dimensions(status, right, WIDTH | HEIGHT, NULL);
 
-	if (lframe_size > SIZE_MAX - lframe_size || 2 * lframe_size > SIZE_MAX - rframe_size)
+	if (left->frame_size > SIZE_MAX - left->frame_size ||
+	    2 * left->frame_size > SIZE_MAX - right->frame_size)
 		enprintf(status, "video frame is too large\n");
 
-	image = mmap(0, 2 * lframe_size + lframe_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+	image = mmap(0, 2 * left->frame_size + right->frame_size,
+		     PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
 	if (image == MAP_FAILED)
 		enprintf(status, "mmap:");
-	lbuf = image + 1 * lframe_size;
-	rbuf = image + 2 * lframe_size;
+	lbuf = image + 1 * left->frame_size;
+	rbuf = image + 2 * left->frame_size;
 
 	for (;;) {
-		if (!enread_frame(status, left, lbuf, lframe_size)) {
+		if (!enread_frame(status, left, lbuf)) {
 			close(left->fd);
 			left->fd = -1;
 			break;
 		}
-		if (!enread_frame(status, right, rbuf, rframe_size)) {
+		if (!enread_frame(status, right, rbuf)) {
 			close(right->fd);
 			right->fd = -1;
 			break;
 		}
 
-		process(image, lbuf, rbuf, left, right, lframe_size, rframe_size);
-		enwriteall(status, output_fd, image, lframe_size, output_fname);
+		process(image, lbuf, rbuf, left, right);
+		enwriteall(status, output_fd, image, left->frame_size, output_fname);
 	}
 
 	if (right->fd >= 0)
@@ -426,9 +447,9 @@ nprocess_each_frame_two_streams(int status, struct stream *left, struct stream *
 
 	if (left->fd >= 0) {
 		memcpy(image, lbuf, left->ptr);
-		while (enread_frame(status, left, lbuf, lframe_size))
-			enwriteall(status, output_fd, image, lframe_size, output_fname);
+		while (enread_frame(status, left, lbuf))
+			enwriteall(status, output_fd, image, left->frame_size, output_fname);
 	}
 
-	munmap(image, 2 * lframe_size + rframe_size);
+	munmap(image, 2 * left->frame_size + right->frame_size);
 }
diff --git a/src/stream.h b/src/stream.h
@@ -3,7 +3,7 @@
 #include <stddef.h>
 #include <stdio.h>
 
-#define STREAM_HEAD_MAX (3 * 3 * sizeof(size_t) + sizeof(((struct stream *)0)->pixfmt) + 10)
+#define STREAM_HEAD_MAX (3 * INTSTRLEN(size_t) + sizeof(((struct stream *)0)->pixfmt) + 10)
 
 #define SPRINTF_HEAD_ZN(BUF, FRAMES, WIDTH, HEIGHT, PIXFMT, LENP)\
 	sprintf(BUF, "%zu %zu %zu %s\n%cuivf%zn",\
@@ -21,17 +21,17 @@
 	fprintf(FP, FFRAMES" "FWIDTH" "FHEIGHT" %s\n%cuivf",\
 		FRAMES, WIDTH, HEIGHT, PIXFMT, 0)
 
-#define einit_stream(...)      eninit_stream(1, __VA_ARGS__)
-#define eopen_stream(...)      enopen_stream(1, __VA_ARGS__)
-#define eset_pixel_size(...)   enset_pixel_size(1, __VA_ARGS__)
-#define eread_stream(...)      enread_stream(1, __VA_ARGS__)
-#define einf_check_fd(...)     eninf_check_fd(1, __VA_ARGS__)
-#define echeck_frame_size(...) encheck_frame_size(1, __VA_ARGS__)
-#define echeck_compat(...)     encheck_compat(1, __VA_ARGS__)
-#define eread_frame(...)       enread_frame(1, __VA_ARGS__)
-
-#define enread_row(...) enread_frame(__VA_ARGS__)
-#define eread_row(...)  eread_frame(__VA_ARGS__)
+#define einit_stream(...)             eninit_stream(1, __VA_ARGS__)
+#define eopen_stream(...)             enopen_stream(1, __VA_ARGS__)
+#define eset_pixel_size(...)          enset_pixel_size(1, __VA_ARGS__)
+#define eread_stream(...)             enread_stream(1, __VA_ARGS__)
+#define einf_check_fd(...)            eninf_check_fd(1, __VA_ARGS__)
+#define echeck_dimensions(...)        encheck_dimensions(1, __VA_ARGS__)
+#define echeck_dimensions_custom(...) encheck_dimensions_custom(1, __VA_ARGS__)
+#define echeck_compat(...)            encheck_compat(1, __VA_ARGS__)
+#define eread_segment(...)            enread_segment(1, __VA_ARGS__)
+#define eread_frame(...)              enread_frame(1, __VA_ARGS__)
+#define eread_row(...)                enread_row(1, __VA_ARGS__)
 
 #define process_stream(...)                 nprocess_stream(1, __VA_ARGS__)
 #define process_each_frame_segmented(...)   nprocess_each_frame_segmented(1, __VA_ARGS__)
@@ -39,6 +39,12 @@
 #define process_multiple_streams(...)       nprocess_multiple_streams(1, __VA_ARGS__)
 #define process_each_frame_two_streams(...) nprocess_each_frame_two_streams(1, __VA_ARGS__)
 
+enum dimension {
+	WIDTH = 1,
+	HEIGHT = 2,
+	LENGTH = 4
+};
+
 struct stream {
 	size_t frames;
 	size_t width;
@@ -54,6 +60,9 @@ struct stream {
 	char buf[BUFSIZ];
 	const char *file;
 	size_t headlen;
+	size_t row_size;
+	size_t col_size;
+	size_t frame_size;
 };
 
 void eninit_stream(int status, struct stream *stream);
@@ -63,11 +72,10 @@ void enset_pixel_size(int status, struct stream *stream);
 void fprint_stream_head(FILE *fp, struct stream *stream);
 size_t enread_stream(int status, struct stream *stream, size_t n);
 void eninf_check_fd(int status, int fd, const char *file);
-int check_frame_size(size_t width, size_t height, size_t pixel_size);
-void encheck_frame_size(int status, size_t width, size_t height, size_t pixel_size, const char *prefix, const char *fname);
+void encheck_dimensions(int status, const struct stream *stream, enum dimension dimensions, const char *prefix);
 void encheck_compat(int status, const struct stream *a, const struct stream *b);
 const char *get_pixel_format(const char *specified, const char *current);
-int enread_frame(int status, struct stream *stream, void *buf, size_t n);
+int enread_segment(int status, struct stream *stream, void *buf, size_t n);
 
 void nprocess_stream(int status, struct stream *stream, void (*process)(struct stream *stream, size_t n));
 
@@ -82,4 +90,33 @@ void nprocess_multiple_streams(int status, struct stream *streams, size_t n_stre
 
 void nprocess_each_frame_two_streams(int status, struct stream *left, struct stream *right, int output_fd, const char* output_fname,
 				     void (*process)(char *restrict output, char *restrict lbuf, char *restrict rbuf,
-						     struct stream *left, struct stream *right, size_t ln, size_t rn));
+						     struct stream *left, struct stream *right));
+
+static inline int
+enread_frame(int status, struct stream *stream, void *buf)
+{
+	return enread_segment(status, stream, buf, stream->frame_size);
+}
+
+static inline int
+enread_row(int status, struct stream *stream, void *buf)
+{
+	return enread_segment(status, stream, buf, stream->row_size);
+}
+
+static inline void
+encheck_dimensions_custom(int status, size_t width, size_t height, size_t frames,
+			  size_t pixel_size, const char *prefix, const char *fname)
+{
+	enum dimension dims = 0;
+	struct stream stream;
+	dims |= width  ? WIDTH  : 0;
+	dims |= height ? HEIGHT : 0;
+	dims |= frames ? LENGTH : 0;
+	stream.width      = width;
+	stream.height     = height;
+	stream.frames     = frames;
+	stream.pixel_size = pixel_size;
+	stream.file       = fname;
+	encheck_dimensions(status, &stream, dims, prefix);
+}
diff --git a/src/util.c b/src/util.c
@@ -234,8 +234,8 @@ int
 xenopen(int status, const char *path, int flags, int mode, ...)
 {
 	int fd;
-	if (!strncmp(path, "/dev/fd/", sizeof("/dev/fd/") - 1)) {
-		if (!toi(path + sizeof("/dev/fd/") - 1, 0, INT_MAX, &fd))
+	if (!strncmp(path, "/dev/fd/", STRLEN("/dev/fd/"))) {
+		if (!toi(path + STRLEN("/dev/fd/"), 0, INT_MAX, &fd))
 			return fd;
 	} else if (!strcmp(path, "/dev/stdin")) {
 		return STDIN_FILENO;
diff --git a/src/util.h b/src/util.h
@@ -5,6 +5,8 @@
 #define MIN(A, B)         ((A) < (B) ? (A) : (B))
 #define MAX(A, B)         ((A) > (B) ? (A) : (B))
 #define CLIP(A, B, C)     ((B) < (A) ? (A) : (B) > (C) ? (C) : (B))
+#define STRLEN(STR)       (sizeof(STR) - 1)
+#define INTSTRLEN(TYPE)   ((sizeof(TYPE) == 1 ? 3 : (5 * sizeof(TYPE) / 2)) + (TYPE)-1 < 0)
 
 #define USAGE(SYNOPSIS)\
 	static void usage(void)\