commit b518ce8977c0b97dd2236fc8cbc7dad1dd70511b
Author:     Mattias Andrée <[email protected]>
AuthorDate: Fri Jun 2 21:00:47 2017 +0200
Commit:     Mattias Andrée <[email protected]>
CommitDate: Fri Jun 2 21:08:58 2017 +0200

    Add blind-disperse, blind-split-rows, and blind-split-cols
    
    Signed-off-by: Mattias Andrée <[email protected]>

diff --git a/Makefile b/Makefile
index bd0ecc7..f7de021 100644
--- 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
index e621a3c..82a1fed 100644
--- 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
new file mode 100644
index 0000000..b42e53c
--- /dev/null
+++ 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
new file mode 100644
index 0000000..e8b4185
--- /dev/null
+++ 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
new file mode 100644
index 0000000..3ad1e3d
--- /dev/null
+++ 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
index 1f361a4..6c9dc72 100644
--- 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
index c77d4aa..d15ce8d 100644
--- 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));

Reply via email to