commit 0804a80954bf9b8c11392d77a4933ec0a4ff635b
parent 478b53f935264bdfe4efe394f8d804a1361a6770
Author: Mattias Andrée <maandree@kth.se>
Date: Sat, 8 Apr 2017 23:02:48 +0200
Add blind-translate and fix errors
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat:
16 files changed, 279 insertions(+), 17 deletions(-)
diff --git a/Makefile b/Makefile
@@ -34,6 +34,7 @@ BIN =\
blind-to-image\
blind-to-text\
blind-to-video\
+ blind-translate\
blind-transpose\
blind-write-head
diff --git a/TODO b/TODO
@@ -13,7 +13,6 @@ blind-affine-colour apply an affine transformation to the colour of each pixel,
-a for ignoring the alpha channel,
-l for linear transformation,
-p for transforming each pixel with their own transformation.
-blind-translate animated translation
blind-invert-chroma invert the chroma
blind-skip-pattern discard frames according to pattern, e.g. every other frame
blind-from-sent convert a sent presentation to a one-frame-per-slide blind video
diff --git a/man/blind-arithm.1 b/man/blind-arithm.1
@@ -21,7 +21,7 @@ on the two videos.
.P
If stdin is longer than
.IR right-hand-stream ,
-the remainder or stdin is printed without any changes.
+the remainder of stdin is printed without any changes.
If stdin is shorter than
.IR right-hand-stream ,
the remainder of
diff --git a/man/blind-crop.1 b/man/blind-crop.1
@@ -66,7 +66,8 @@ has not been optimised for memory usage, but instead
for code simplicity.
.SH SEE ALSO
.BR blind (7),
-.BR blind-extend (1)
+.BR blind-extend (1),
+.BR blind-translate (1)
.SH AUTHORS
Mattias Andrée
.RI < maandree@kth.se >
diff --git a/man/blind-extend.1 b/man/blind-extend.1
@@ -63,7 +63,8 @@ has not been optimised for memory usage, but instead
for code simplicity.
.SH SEE ALSO
.BR blind (7),
-.BR blind-crop (1)
+.BR blind-crop (1),
+.BR blind-translate (1)
.SH AUTHORS
Mattias Andrée
.RI < maandree@kth.se >
diff --git a/man/blind-gauss-blur.1 b/man/blind-gauss-blur.1
@@ -29,7 +29,7 @@ deviation is 0, the pixel is not blurred.
.P
If stdin is longer than
.IR sd-stream ,
-the remainder or stdin is printed without any changes.
+the remainder of stdin is printed without any changes.
If stdin is shorter than
.IR sd-stream ,
the remainder of
diff --git a/man/blind-invert-luma.1 b/man/blind-invert-luma.1
@@ -19,7 +19,7 @@ linearly extrapolated.
.P
If stdin is longer than
.IR mask-stream ,
-the remainder or stdin is printed without any changes.
+the remainder of stdin is printed without any changes.
If stdin is shorter than
.IR mask-stream ,
the remainder of
diff --git a/man/blind-set-alpha.1 b/man/blind-set-alpha.1
@@ -16,7 +16,7 @@ the mask video.
.P
If stdin is longer than
.IR alpha-stream ,
-the remainder or stdin is printed without any changes.
+the remainder of stdin is printed without any changes.
If stdin is shorter than
.IR alpha-stream ,
the remainder of
diff --git a/man/blind-set-luma.1 b/man/blind-set-luma.1
@@ -15,7 +15,7 @@ pixel and frame in the mask video.
.P
If stdin is longer than
.IR luma-stream ,
-the remainder or stdin is printed without any changes.
+the remainder of stdin is printed without any changes.
If stdin is shorter than
.IR luma-stream ,
the remainder of
diff --git a/man/blind-set-saturation.1 b/man/blind-set-saturation.1
@@ -16,7 +16,7 @@ pixel and frame in the mask video.
.P
If stdin is longer than
.IR saturation-stream ,
-the remainder or stdin is printed without any changes.
+the remainder of stdin is printed without any changes.
If stdin is shorter than
.IR saturation-stream ,
the remainder of
diff --git a/man/blind-time-blur.1 b/man/blind-time-blur.1
@@ -18,7 +18,7 @@ in the mask video, and then printed stdout.
.P
If stdin is longer than
.IR alpha-stream ,
-the remainder or stdin is printed without any changes.
+the remainder of stdin is printed without any changes.
If stdin is shorter than
.IR alpha-stream ,
the remainder of
diff --git a/man/blind-translate.1 b/man/blind-translate.1
@@ -0,0 +1,50 @@
+.TH BLIND-TRANSLATE 1 blind
+.SH NAME
+blind-translate - Perform framewise translate of a video
+.SH SYNOPSIS
+.B blind-translate
+[-pw]
+.I translation-stream
+.SH DESCRIPTION
+.B blind-translate
+reads a video from stdin and translation operands from
+.IR translation-stream ,
+and perform framewise translation of the video and
+prints the resulting video to stdout.
+.P
+.I translation-stream
+is a video that is 1 pixel wide and 1 pixel high.
+The first pixel value in a frame is used as the
+translation value for the X-axis in the same frame
+in the video, and the second pixel value is used
+as the translation value for the Y-axis. The
+remaining two pixel values are ignored.
+.P
+If stdin is longer than
+.IR translation-stream ,
+the remainder of stdin is printed with the last translation
+or no translation if
+.I translation-stream
+does not contain any translations. If stdin is shorter than
+.IR translation-stream ,
+the remainder of
+.I translation-stream
+is ignored but may be partially read.
+.SH OPTIONS
+.TP
+.B -w
+Wrap video around the edges.
+.TP
+.B -p
+The values in
+.I translation-stream
+is to be treat as the position, measured form the
+top-left corner, in the input video that shall be
+used at the top-left corner of the output video.
+.SH SEE ALSO
+.BR blind (7),
+.BR blind-crop (1),
+.BR blind-extend (1)
+.SH AUTHORS
+Mattias Andrée
+.RI < maandree@kth.se >
diff --git a/src/blind-translate.c b/src/blind-translate.c
@@ -0,0 +1,184 @@
+/* See LICENSE file for copyright and license details. */
+#include "stream.h"
+#include "util.h"
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <math.h>
+#include <string.h>
+#include <unistd.h>
+
+USAGE("[-wp] translation-stream")
+
+static int invtrans = 0;
+static char zeroes[BUFSIZ];
+
+static void*
+next_pixel(struct stream *stream, size_t *ptr)
+{
+ void *ret;
+ if (*ptr + stream->pixel_size >= stream->ptr) {
+ memmove(stream->buf, stream->buf + *ptr, stream->ptr -= *ptr);
+ *ptr = 0;
+ while (stream->ptr < stream->pixel_size)
+ if (!eread_stream(stream, SIZE_MAX))
+ return NULL;
+ }
+ ret = stream->buf + *ptr;
+ *ptr += stream->pixel_size;
+ return ret;
+}
+
+static int
+process_frame(struct stream *stream, char *buf, size_t n,
+ 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;
+ int first = 1;
+
+ if (!eread_row(stream, buf, n))
+ return 0;
+
+ for (i = 0; i < above; i++)
+ ZEROES(n);
+ for (i = 0; i < below; i++, first = 0)
+ if (!first && !eread_row(stream, buf, n))
+ goto eof;
+
+ for (i = above + below; i < stream->height; i++, first = 0) {
+ if (!first && !eread_row(stream, buf, n))
+ goto eof;
+ ZEROES((size_t)left);
+ ewriteall(STDOUT_FILENO, buf + right, w, "<stdout>");
+ ZEROES((size_t)right);
+ }
+
+ for (i = 0; i < below; i++)
+ ZEROES(n);
+ for (i = 0; i < above; i++, first = 0)
+ if (!first && !eread_row(stream, buf, n))
+ goto eof;
+
+ return 1;
+eof:
+ eprintf("%s: file is shorter than expected\n", stream->file);
+ return 0;
+
+#undef ZEROES
+}
+
+static void
+process(struct stream *stream, struct stream *trstream)
+{
+ char *buf;
+ size_t n, p = 0;
+ double *trans;
+ ssize_t trx = 0, try = 0;
+ size_t above = 0, below = 0, left = 0, right = 0;
+
+ memset(zeroes, 0, sizeof(zeroes));
+
+ if (!check_frame_size(stream->width, 1, stream->pixel_size))
+ eprintf("%s: video frame is too wide\n", stream->file);
+ n = stream->width * stream->pixel_size;
+ buf = emalloc(n);
+
+ do {
+ if ((trans = next_pixel(trstream, &p))) {
+ trx = (ssize_t)round(invtrans ? -trans[0] : trans[0]);
+ try = (ssize_t)round(invtrans ? -trans[1] : trans[1]);
+
+ above = try > 0 ? (size_t)try : 0;
+ below = try < 0 ? (size_t)-try : 0;
+ left = (trx > 0 ? (size_t)trx : 0) * stream->pixel_size;
+ right = (trx < 0 ? (size_t)-trx : 0) * stream->pixel_size;
+
+ above = above < stream->height ? above : stream->height;
+ below = below < stream->height ? below : stream->height;
+ left = left < n ? left : n;
+ right = right < n ? right : n;
+ }
+ } while (process_frame(stream, buf, n, above, below, left, right));
+
+ free(buf);
+}
+
+static void
+process_wrap(struct stream *stream, struct stream *trstream)
+{
+ char *buf, *row;
+ size_t n, rown, p = 0;
+ double *trans;
+ 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);
+
+ while (eread_frame(stream, buf, n)) {
+ if ((trans = next_pixel(trstream, &p))) {
+ trx = (ssize_t)round(invtrans ? -trans[0] : trans[0]);
+ try = (ssize_t)round(invtrans ? -trans[1] : trans[1]);
+ trx %= (ssize_t)stream->width;
+ if (trx < 0)
+ trx += (ssize_t)stream->width;
+ off = (stream->width - (size_t)trx) % stream->width;
+ off = off * stream->pixel_size;
+ }
+
+ for (y = 0; y < stream->height; y++) {
+ 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>");
+ ewriteall(STDOUT_FILENO, row, off, "<stdout>");
+ }
+ }
+
+ free(buf);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stream stream;
+ struct stream trstream;
+ int wrap = 0;
+
+ ARGBEGIN {
+ case 'w':
+ wrap = 1;
+ break;
+ case 'p':
+ invtrans = 1;
+ break;
+ } ARGEND;
+
+ if (argc != 1)
+ usage();
+
+ stream.file = "<stdin>";
+ stream.fd = STDIN_FILENO;
+ einit_stream(&stream);
+ fprint_stream_head(stdout, &stream);
+ efflush(stdout, "<stdout>");
+
+ trstream.file = argv[0];
+ trstream.fd = eopen(trstream.file, O_RDONLY);
+ einit_stream(&trstream);
+
+ if (trstream.width != 1 || trstream.height != 1)
+ eprintf("translation-stream does not have 1x1 geometry\n");
+
+ if (strcmp(trstream.pixfmt, "xyza"))
+ eprintf("pixel format of translation-stream %s "
+ "is not supported, try xyza\n", trstream.pixfmt);
+
+ (wrap ? process_wrap : process)(&stream, &trstream);
+ close(trstream.fd);
+ return 0;
+}
diff --git a/src/stream.c b/src/stream.c
@@ -161,7 +161,7 @@ encheck_frame_size(int status, size_t width, size_t height, size_t pixel_size, c
{
if (!check_frame_size(width, height, pixel_size))
enprintf(status, "%s: %s%svideo frame is too large\n",
- prefix ? prefix : "", (prefix && *prefix) ? " " : "", fname);
+ fname, prefix ? prefix : "", (prefix && *prefix) ? " " : "");
}
@@ -218,9 +218,10 @@ nprocess_each_frame_segmented(int status, struct stream *stream, int output_fd,
for (frame = 0; frame < stream->frames; frame++) {
for (n = frame_size; n; n -= r) {
- if (!enread_stream(status, stream, n))
+ 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);
+ r = r < n ? r : n;
(process)(stream, r, frame);
enwriteall(status, output_fd, stream->buf, r, output_fname);
memmove(stream->buf, stream->buf + r, stream->ptr -= r);
@@ -301,6 +302,8 @@ nprocess_multiple_streams(int status, struct stream *streams, size_t n_streams,
if (streams[i].ptr && streams[i].ptr < n)
n = streams[i].ptr;
}
+ if (n == SIZE_MAX)
+ break;
n -= n % streams->pixel_size;
process(streams, n_streams, n);
@@ -308,13 +311,14 @@ nprocess_multiple_streams(int status, struct stream *streams, size_t n_streams,
closed = SIZE_MAX;
for (i = 0; i < n_streams; i++) {
- memmove(streams[i].buf, streams[i].buf + n, streams[i].ptr -= n);
+ if (streams[i].ptr)
+ memmove(streams[i].buf, streams[i].buf + n, streams[i].ptr -= n);
if (streams[i].ptr < streams->pixel_size && streams[i].fd < 0 && closed == SIZE_MAX)
closed = i;
}
if (closed != SIZE_MAX) {
for (i = (j = closed) + 1; i < n_streams; i++)
- if (streams[i].ptr < streams->pixel_size && streams[i].fd < 0)
+ if (streams[i].ptr >= streams->pixel_size || streams[i].fd >= 0)
streams[j++] = streams[i];
n_streams = j;
}
diff --git a/src/util.c b/src/util.c
@@ -157,6 +157,18 @@ pwriteall(int fd, void *buf, size_t n, size_t ptr)
return 0;
}
+int
+writezeroes(int fd, void *buf, size_t bufsize, size_t n)
+{
+ size_t p, m;
+ for (p = 0; p < n; p += m) {
+ m = bufsize < n - p ? bufsize : n - p;
+ if (writeall(fd, buf, m))
+ return -1;
+ }
+ return 0;
+}
+
static inline pid_t
enfork(int status)
diff --git a/src/util/io.h b/src/util/io.h
@@ -1,8 +1,9 @@
/* See LICENSE file for copyright and license details. */
-#define ewriteall(...) enwriteall(1, __VA_ARGS__)
-#define ereadall(...) enreadall(1, __VA_ARGS__)
-#define epwriteall(...) enpwriteall(1, __VA_ARGS__)
+#define ewriteall(...) enwriteall(1, __VA_ARGS__)
+#define ereadall(...) enreadall(1, __VA_ARGS__)
+#define epwriteall(...) enpwriteall(1, __VA_ARGS__)
+#define ewritezeroes(...) enwritezeroes(1, __VA_ARGS__)
int writeall(int fd, void *buf, size_t n);
@@ -32,3 +33,12 @@ enpwriteall(int status, int fd, void *buf, size_t n, size_t ptr, const char *fna
if (pwriteall(fd, buf, n, ptr))
enprintf(status, "pwrite %s:", fname);
}
+
+int writezeroes(int fd, void *buf, size_t bufsize, size_t n);
+
+static inline void
+enwritezeroes(int status, int fd, void *buf, size_t bufsize, size_t n, const char *fname)
+{
+ if (writezeroes(fd, buf, bufsize, n))
+ enprintf(status, "write %s:", fname);
+}