commit b518ce8977c0b97dd2236fc8cbc7dad1dd70511b
parent afb5da1566586f6f8f53a8b7e443b8bca70542fe
Author: Mattias Andrée <maandree@kth.se>
Date: Fri, 2 Jun 2017 21:00:47 +0200
Add blind-disperse, blind-split-rows, and blind-split-cols
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat:
7 files changed, 226 insertions(+), 14 deletions(-)
diff --git a/Makefile b/Makefile
@@ -11,6 +11,7 @@ BIN =\
blind-crop\
blind-cut\
blind-decompress\
+ blind-disperse\
blind-dissolve\
blind-extend\
blind-flip\
@@ -34,6 +35,8 @@ BIN =\
blind-single-colour\
blind-skip-pattern\
blind-split\
+ blind-split-cols\
+ blind-split-rows\
blind-stack\
blind-tee\
blind-time-blur\
diff --git a/TODO b/TODO
@@ -1,3 +1,9 @@
+Write manpages for:
+ blind-disperse inverse of blind-interleave
+ Useful for processing a video on multiple computers
+ blind-split-rows split stream into multiple streams by splitting video horizontally
+ blind-split-cols split stream into multiple streams by splitting video vertically
+
blind-transform affine transformation by matrix multiplication, -t for tiling, -s for
improve quality on downscaling (pixels' neighbours must not change).
blind-chroma-key replace a chroma with transparency.
@@ -17,8 +23,6 @@ blind-affine-colour apply an affine transformation to the colour of each pixel,
blind-invert-chroma invert the chroma
blind-from-sent convert a sent presentation to a one-frame-per-slide blind video.
blind-interleave framewise interleave videos
-blind-disperse inverse of blind-interleave
- Useful for processing a video on multiple computers
blind-kirsch https://en.wikipedia.org/wiki/Kirsch_operator
blind-gaussian-noise https://en.wikipedia.org/wiki/Gaussian_noise
@@ -44,8 +48,6 @@ blind-mean mean of multiple streams
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-split-rows split stream into multiple streams by splitting video horizontally
-blind-split-cols split stream into multiple streams by splitting video vertically
blind-cat-rows merge video by vertically stacking streams (inverse of blind-split-rows)
blind-cat-cols merge video by putting streams beside each other (inverse of blind-split-cols)
diff --git a/src/blind-disperse.c b/src/blind-disperse.c
@@ -0,0 +1,48 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("(file frames) ...")
+
+int
+main(int argc, char *argv[])
+{
+ struct stream stream;
+ size_t *frames, *framecount, period = 0, parts, i, n;
+ int *fds;
+
+ UNOFLAGS(argc % 2 || !argc);
+
+ eopen_stream(&stream, NULL);
+
+ parts = (size_t)argc / 2;
+ frames = alloca(parts * sizeof(*frames));
+ framecount = alloca(parts * sizeof(*framecount));
+ fds = alloca(parts * sizeof(*fds));
+
+ for (i = 0; i < parts; i++) {
+ fds[i] = eopen(argv[i * 2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ frames[i] = etozu_arg("frames", argv[i * 2 + 1], 1, SIZE_MAX);
+ }
+ for (i = 0; i < parts; i++) {
+ if (frames[i] > SIZE_MAX - period)
+ eprintf("the sum of selected frame intervals exceeds %zu\n", SIZE_MAX);
+ period += frames[i];
+ }
+ for (n = stream.frames / period, i = 0; i < parts; i++)
+ framecount[i] = n * frames[i];
+ for (n = stream.frames % period, i = 0; i < parts; i++) {
+ framecount[i] += MIN(n, frames[i]);
+ n -= MIN(n, frames[i]);
+ }
+
+ for (i = 0; i < parts; i++)
+ if (DPRINTF_HEAD(fds[i], framecount[i], stream.width, stream.height, stream.pixfmt) < 0)
+ eprintf("dprintf %s:", argv[i * 2]);
+ for (i = 0; i < parts; i++, i = i == parts ? 0 : i)
+ if (esend_frames(&stream, fds[i], frames[i], argv[i * 2]) != frames[i])
+ break;
+ for (i = 0; i < parts; i++)
+ close(fds[i]);
+
+ return 0;
+}
diff --git a/src/blind-split-cols.c b/src/blind-split-cols.c
@@ -0,0 +1,47 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("(file columns) ...")
+
+int
+main(int argc, char *argv[])
+{
+ struct stream stream;
+ size_t *cols, period = 0, parts, i;
+ int *fds;
+
+ UNOFLAGS(argc % 2 || !argc);
+
+ eopen_stream(&stream, NULL);
+
+ parts = (size_t)argc / 2;
+ cols = alloca(parts * sizeof(*cols));
+ fds = alloca(parts * sizeof(*fds));
+
+ for (i = 0; i < parts; i++) {
+ fds[i] = eopen(argv[i * 2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ cols[i] = etozu_arg("columns", argv[i * 2 + 1], 1, SIZE_MAX);
+ }
+ for (i = 0; i < parts; i++) {
+ if (cols[i] > SIZE_MAX - period)
+ goto bad_col_count;
+ period += cols[i];
+ }
+ if (period != stream.width)
+ goto bad_col_count;
+
+ for (i = 0; i < parts; i++)
+ if (DPRINTF_HEAD(fds[i], stream.frames, cols[i], stream.height, stream.pixfmt) < 0)
+ eprintf("dprintf %s:", argv[i * 2]);
+ for (i = 0; i < parts; i++, i = i == parts ? 0 : i)
+ if (esend_pixels(&stream, fds[i], cols[i], argv[i * 2]) != cols[i])
+ break;
+ for (i = 0; i < parts; i++)
+ close(fds[i]);
+
+ return 0;
+
+bad_col_count:
+ eprintf("the sum of all columns must add up to the width of the input video\n");
+ return 1;
+}
diff --git a/src/blind-split-rows.c b/src/blind-split-rows.c
@@ -0,0 +1,47 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+USAGE("(file rows) ...")
+
+int
+main(int argc, char *argv[])
+{
+ struct stream stream;
+ size_t *rows, period = 0, parts, i;
+ int *fds;
+
+ UNOFLAGS(argc % 2 || !argc);
+
+ eopen_stream(&stream, NULL);
+
+ parts = (size_t)argc / 2;
+ rows = alloca(parts * sizeof(*rows));
+ fds = alloca(parts * sizeof(*fds));
+
+ for (i = 0; i < parts; i++) {
+ fds[i] = eopen(argv[i * 2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ rows[i] = etozu_arg("rows", argv[i * 2 + 1], 1, SIZE_MAX);
+ }
+ for (i = 0; i < parts; i++) {
+ if (rows[i] > SIZE_MAX - period)
+ goto bad_row_count;
+ period += rows[i];
+ }
+ if (period != stream.height)
+ goto bad_row_count;
+
+ for (i = 0; i < parts; i++)
+ if (DPRINTF_HEAD(fds[i], stream.frames, stream.width, rows[i], stream.pixfmt) < 0)
+ eprintf("dprintf %s:", argv[i * 2]);
+ for (i = 0; i < parts; i++, i = i == parts ? 0 : i)
+ if (esend_rows(&stream, fds[i], rows[i], argv[i * 2]) != rows[i])
+ break;
+ for (i = 0; i < parts; i++)
+ close(fds[i]);
+
+ return 0;
+
+bad_row_count:
+ eprintf("the sum of all rows must add up to the height of the input video\n");
+ return 1;
+}
diff --git a/src/stream.c b/src/stream.c
@@ -270,8 +270,7 @@ enread_segment(int status, struct stream *stream, void *buf, size_t n)
size_t
ensend_frames(int status, struct stream *stream, int outfd, size_t frames, const char *outfname)
{
- size_t h, w, p, n;
- size_t ret = 0;
+ size_t h, w, p, n, ret;
for (ret = 0; ret < frames; ret++) {
for (p = stream->pixel_size; p; p--) {
@@ -295,6 +294,54 @@ done:
}
+size_t
+ensend_rows(int status, struct stream *stream, int outfd, size_t rows, const char *outfname)
+{
+ size_t w, p, n, ret;
+
+ for (ret = 0; ret < rows; ret++) {
+ for (p = stream->pixel_size; p; p--) {
+ for (w = stream->width; w; w -= n, stream->ptr -= n) {
+ if (!stream->ptr && !enread_stream(status, stream, w))
+ goto done;
+ n = MIN(stream->ptr, w);
+ if (outfd >= 0)
+ enwriteall(status, outfd, stream->buf, n, outfname);
+ }
+ }
+ }
+
+ return ret;
+done:
+ if (p != stream->pixel_size || w != stream->width)
+ enprintf(status, "%s: incomplete row", stream->file);
+ return ret;
+}
+
+
+size_t
+ensend_pixels(int status, struct stream *stream, int outfd, size_t pixels, const char *outfname)
+{
+ size_t p, n, ret;
+
+ for (ret = 0; ret < pixels; ret++) {
+ for (p = stream->pixel_size; p; p -= n, stream->ptr -= n) {
+ if (!stream->ptr && !enread_stream(status, stream, p))
+ goto done;
+ n = MIN(stream->ptr, p);
+ if (outfd >= 0)
+ enwriteall(status, outfd, stream->buf, n, outfname);
+ }
+ }
+
+ return ret;
+done:
+ if (p != stream->pixel_size)
+ enprintf(status, "%s: incomplete pixel", stream->file);
+ return ret;
+}
+
+
int
ensend_stream(int status, struct stream *stream, int outfd, const char *outfname)
{
diff --git a/src/stream.h b/src/stream.h
@@ -5,21 +5,35 @@
#define STREAM_HEAD_MAX (3 * INTSTRLEN(size_t) + sizeof(((struct stream *)0)->pixfmt) + 10)
+#define XPRINTF_HEAD_FMT "%zu %zu %zu %s\n%cuivf"
+#define XPRINTF_HEAD_ARGS(FRAMES, WIDTH, HEIGHT, PIXFMT)\
+ (size_t)(FRAMES), (size_t)(WIDTH), (size_t)(HEIGHT), (PIXFMT), 0
+
+#define XPRINTF_HEAD_FMT_FMT(FFRAMES, FWIDTH, FHEIGHT)\
+ FFRAMES" "FWIDTH" "FHEIGHT" %s\n%cuivf"
+#define XPRINTF_HEAD_FMT_ARGS(FRAMES, WIDTH, HEIGHT, PIXFMT)\
+ (FRAMES), (WIDTH), (HEIGHT), (PIXFMT), 0
+
#define SPRINTF_HEAD_ZN(BUF, FRAMES, WIDTH, HEIGHT, PIXFMT, LENP)\
- sprintf(BUF, "%zu %zu %zu %s\n%cuivf%zn",\
- (size_t)(FRAMES), (size_t)(WIDTH), (size_t)(HEIGHT), PIXFMT, 0, LENP)
+ sprintf(BUF, XPRINTF_HEAD_FMT"%zn", XPRINTF_HEAD_ARGS(FRAMES, WIDTH, HEIGHT, PIXFMT), LENP)
#define SPRINTF_HEAD(BUF, FRAMES, WIDTH, HEIGHT, PIXFMT)\
- sprintf(BUF, "%zu %zu %zu %s\n%cuivf",\
- (size_t)(FRAMES), (size_t)(WIDTH), (size_t)(HEIGHT), PIXFMT, 0)
+ sprintf(BUF, XPRINTF_HEAD_FMT, XPRINTF_HEAD_ARGS(FRAMES, WIDTH, HEIGHT, PIXFMT))
#define FPRINTF_HEAD(FP, FRAMES, WIDTH, HEIGHT, PIXFMT)\
- fprintf(FP, "%zu %zu %zu %s\n%cuivf",\
- (size_t)(FRAMES), (size_t)(WIDTH), (size_t)(HEIGHT), PIXFMT, 0)
+ fprintf(FP, XPRINTF_HEAD_FMT, XPRINTF_HEAD_ARGS(FRAMES, WIDTH, HEIGHT, PIXFMT))
+
+#define DPRINTF_HEAD(FD, FRAMES, WIDTH, HEIGHT, PIXFMT)\
+ dprintf(FD, XPRINTF_HEAD_FMT, XPRINTF_HEAD_ARGS(FRAMES, WIDTH, HEIGHT, PIXFMT))
+
+#define SPRINTF_HEAD_FMT(BUF, FFRAMES, FRAMES, FWIDTH, WIDTH, FHEIGHT, HEIGHT, PIXFMT)\
+ sprintf(BUF, XPRINTF_HEAD_FMT_FMT(FFRAMES, FWIDTH, FHEIGHT), XPRINTF_HEAD_FMT_ARGS(FRAMES, WIDTH, HEIGHT, PIXFMT))
#define FPRINTF_HEAD_FMT(FP, FFRAMES, FRAMES, FWIDTH, WIDTH, FHEIGHT, HEIGHT, PIXFMT)\
- fprintf(FP, FFRAMES" "FWIDTH" "FHEIGHT" %s\n%cuivf",\
- FRAMES, WIDTH, HEIGHT, PIXFMT, 0)
+ fprintf(FP, XPRINTF_HEAD_FMT_FMT(FFRAMES, FWIDTH, FHEIGHT), XPRINTF_HEAD_FMT_ARGS(FRAMES, WIDTH, HEIGHT, PIXFMT))
+
+#define DPRINTF_HEAD_FMT(FD, FFRAMES, FRAMES, FWIDTH, WIDTH, FHEIGHT, HEIGHT, PIXFMT)\
+ dprintf(FD, XPRINTF_HEAD_FMT_FMT(FFRAMES, FWIDTH, FHEIGHT), XPRINTF_HEAD_FMT_ARGS(FRAMES, WIDTH, HEIGHT, PIXFMT))
#define einit_stream(...) eninit_stream(1, __VA_ARGS__)
#define eopen_stream(...) enopen_stream(1, __VA_ARGS__)
@@ -33,6 +47,8 @@
#define eread_frame(...) enread_frame(1, __VA_ARGS__)
#define eread_row(...) enread_row(1, __VA_ARGS__)
#define esend_frames(...) ensend_frames(1, __VA_ARGS__)
+#define esend_rows(...) ensend_rows(1, __VA_ARGS__)
+#define esend_pixels(...) ensend_pixels(1, __VA_ARGS__)
#define esend_stream(...) ensend_stream(1, __VA_ARGS__)
#define process_stream(...) nprocess_stream(1, __VA_ARGS__)
@@ -79,6 +95,8 @@ 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_segment(int status, struct stream *stream, void *buf, size_t n);
size_t ensend_frames(int status, struct stream *stream, int outfd, size_t frames, const char *outfname);
+size_t ensend_rows(int status, struct stream *stream, int outfd, size_t rows, const char *outfname);
+size_t ensend_pixels(int status, struct stream *stream, int outfd, size_t pixels, const char *outfname);
int ensend_stream(int status, struct stream *stream, int outfd, const char *outfname);
void nprocess_stream(int status, struct stream *stream, void (*process)(struct stream *stream, size_t n));