blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | LICENSE

commit 1d6f31b2f6092e05056dc6a3d97b03a251f110e1
parent edc0a1ca9c1c85a77ac04eb78c8fa208e0c5b24f
Author: Mattias Andrée <maandree@kth.se>
Date:   Fri, 14 Jul 2017 17:38:11 +0200

Add blind-multiply-matrices

Signed-off-by: Mattias Andrée <maandree@kth.se>

Diffstat:
Makefile | 1+
README | 3+++
man/blind-matrix-orthoproject.1 | 3++-
man/blind-matrix-reflect.1 | 3++-
man/blind-matrix-rotate.1 | 3++-
man/blind-matrix-scale.1 | 3++-
man/blind-matrix-shear.1 | 3++-
man/blind-matrix-translate.1 | 3++-
man/blind-matrix-transpose.1 | 3++-
man/blind-multiply-matrices.1 | 43+++++++++++++++++++++++++++++++++++++++++++
man/blind-stack.1 | 2+-
man/blind.7 | 3+++
src/blind-multiply-matrices.c | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13 files changed, 203 insertions(+), 8 deletions(-)

diff --git a/Makefile b/Makefile @@ -50,6 +50,7 @@ BIN =\ blind-matrix-transpose\ blind-mosaic\ blind-mosaic-edges\ + blind-multiply-matrices\ blind-next-frame\ blind-norm\ blind-quaternion-product\ diff --git a/README b/README @@ -144,6 +144,9 @@ UTILITIES blind-mosaic-edges(1) Find edges in a mosaic video + blind-multiply-matrices(1) + Multiply matrix-vidoes + blind-next-frame(1) Extracts the next frame from a video diff --git a/man/blind-matrix-orthoproject.1 b/man/blind-matrix-orthoproject.1 @@ -37,7 +37,8 @@ channels in stdout. .BR blind-matrix-scale (1), .BR blind-matrix-shear (1), .BR blind-matrix-translate (1), -.BR blind-matrix-transpose (1) +.BR blind-matrix-transpose (1), +.BR blind-multiply-matrices (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-matrix-reflect.1 b/man/blind-matrix-reflect.1 @@ -37,7 +37,8 @@ channels in stdout. .BR blind-matrix-scale (1), .BR blind-matrix-shear (1), .BR blind-matrix-translate (1), -.BR blind-matrix-transpose (1) +.BR blind-matrix-transpose (1), +.BR blind-multiply-matrices (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-matrix-rotate.1 b/man/blind-matrix-rotate.1 @@ -39,7 +39,8 @@ grows upwards rather than downwards. .BR blind-matrix-scale (1), .BR blind-matrix-shear (1), .BR blind-matrix-translate (1), -.BR blind-matrix-transpose (1) +.BR blind-matrix-transpose (1), +.BR blind-multiply-matrices (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-matrix-scale.1 b/man/blind-matrix-scale.1 @@ -37,7 +37,8 @@ channels in stdout. .BR blind-matrix-rotate (1), .BR blind-matrix-shear (1), .BR blind-matrix-translate (1), -.BR blind-matrix-transpose (1) +.BR blind-matrix-transpose (1), +.BR blind-multiply-matrices (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-matrix-shear.1 b/man/blind-matrix-shear.1 @@ -52,7 +52,8 @@ other. .BR blind-matrix-rotate (1), .BR blind-matrix-scale (1), .BR blind-matrix-translate (1), -.BR blind-matrix-transpose (1) +.BR blind-matrix-transpose (1), +.BR blind-multiply-matrices (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-matrix-translate.1 b/man/blind-matrix-translate.1 @@ -41,7 +41,8 @@ Y-axis grows upwards rather than downwards. .BR blind-matrix-rotate (1), .BR blind-matrix-scale (1), .BR blind-matrix-shear (1), -.BR blind-matrix-transpose (1) +.BR blind-matrix-transpose (1), +.BR blind-multiply-matrices (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-matrix-transpose.1 b/man/blind-matrix-transpose.1 @@ -37,7 +37,8 @@ channels in stdout. .BR blind-matrix-rotate (1), .BR blind-matrix-scale (1), .BR blind-matrix-shear (1), -.BR blind-matrix-translate (1) +.BR blind-matrix-translate (1), +.BR blind-multiply-matrices (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-multiply-matrices.1 b/man/blind-multiply-matrices.1 @@ -0,0 +1,43 @@ +.TH BLIND-MULTIPLY-MATRICES 1 blind +.SH NAME +blind-multiply-matrices - Multiply matrix-vidoes +.SH SYNOPSIS +.B blind-multiply-matrices +[-en] +.I leftmost-stream +.RI "... " rightmost-stream +.SH DESCRIPTION +.B blind-multiply-matrices +reads videos representing matrices from the files +specified via the arguments +.I leftmost-stream +to +.IR rightmost-stream , +and multiples them, frame by frame, from right to +left, and prints the resulting video to stdout. +Each frame in a video contains one matrix per +channel, made up from the values on a channel +of each pixel. +.SH OPTIONS +.TP +.B -e +Apply optimisation that assumes all channels +are identical. +.TP +.B -n +Reverse the order of each specified files, +so that the transformations are applied in +the order they are specified rather than +in reverse order. +.SH SEE ALSO +.BR blind (7), +.BR blind-matrix-orthoproject (1), +.BR blind-matrix-reflect (1), +.BR blind-matrix-rotate (1), +.BR blind-matrix-scale (1), +.BR blind-matrix-shear (1), +.BR blind-matrix-translate (1), +.BR blind-matrix-transpose (1) +.SH AUTHORS +Mattias Andrée +.RI < maandree@kth.se > diff --git a/man/blind-stack.1 b/man/blind-stack.1 @@ -4,7 +4,7 @@ blind-stack - Overlay videos .SH SYNOPSIS .B blind-stack [-bs] -.IR bottom-stream +.I bottom-stream .RI "... " top-stream .SH DESCRIPTION .B blind-stack diff --git a/man/blind.7 b/man/blind.7 @@ -160,6 +160,9 @@ Redraw each frame in video as a mosaic .BR blind-mosaic-edges (1) Find edges in a mosaic video .TP +.BR blind-multiply-matrices (1) +Multiply matrix-vidoes +.TP .BR blind-next-frame (1) Extracts the next frame from a video .TP diff --git a/src/blind-multiply-matrices.c b/src/blind-multiply-matrices.c @@ -0,0 +1,138 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("[-en] leftmost-stream ... rightmost-stream") + +static int equal = 0; +static size_t max_frame_size; + +#define PROCESS(TYPE)\ + do {\ + typedef TYPE pixel_t[4];\ + pixel_t *res, *left, *right, *tmp;\ + size_t i, j, w, h, h2, x, y, k, r;\ + res = emalloc(max_frame_size);\ + left = emalloc(max_frame_size);\ + right = emalloc(max_frame_size);\ + \ + while (eread_frame(streams + (n_streams - 1), res)) {\ + w = streams[n_streams - 1].width;\ + h = streams[n_streams - 1].height;\ + for (i = n_streams - 1; i--;) {\ + tmp = res, res = right, right = tmp;\ + if (!eread_frame(streams + i, left))\ + goto done;\ + h2 = streams[i].height;\ + memset(res, 0, w * h2 * streams->pixel_size);\ + \ + /* XXX Is there any significant performance to be gained by transposing `right`? */\ + if (equal) {\ + for (y = r = 0; y < h2; y++) {\ + for (x = 0; x < w; x++, r++) {\ + for (k = 0; k < h; k++) \ + res[r][1] += left[y * h + k][1] * right[k * w + x][1];\ + res[r][3] = res[r][2] = res[r][0] = res[r][1];\ + }\ + }\ + } else {\ + for (y = r = 0; y < h2; y++)\ + for (x = 0; x < w; x++, r++) \ + for (k = 0; k < h; k++)\ + for (j = 0; j < 4; j++)\ + res[r][j] += left[y * h + k][j] * right[k * w + x][j];\ + }\ + \ + h = h2;\ + }\ + ewriteall(STDOUT_FILENO, res, streams->frame_size, "<stdout>");\ + }\ + \ + done:\ + free(res);\ + free(left);\ + free(right);\ + } while (0) + +static void process_lf(struct stream *streams, size_t n_streams) { PROCESS(double); } +static void process_f (struct stream *streams, size_t n_streams) { PROCESS(float); } + +int +main(int argc, char *argv[]) +{ + struct stream *streams; + size_t n_streams, i, frames = 0; + int natural = 0, j; + char **rev_argv; + size_t max_width = 0, max_height = 0; + size_t width = 0, height = 0, w, h; + void (*process)(struct stream *streams, size_t n_streams); + + ARGBEGIN { + case 'e': + equal = 1; + break; + case 'n': + natural = 1; + break; + default: + usage(); + } ARGEND; + + if (argc < 2) + usage(); + + if (natural) { + rev_argv = alloca(argc * sizeof(*rev_argv)); + for (j = 0; j < argc; j++) + rev_argv[j] = argv[argc - 1 - j]; + argv = rev_argv; + } + + n_streams = (size_t)argc; + streams = ecalloc(n_streams, sizeof(*streams)); + + for (i = 0; i < n_streams; i++) { + eopen_stream(streams + i, argv[i]); + if (streams[i].frames && streams[i].frames < frames) + frames = streams[i].frames; + if (streams->width > max_width) + max_width = streams->width; + if (streams->height > max_height) + max_height = streams->height; + } + for (i = 1; i < n_streams; i++) + if (strcmp(streams->pixfmt, streams[i].pixfmt)) + eprintf("videos use incompatible pixel formats\n"); + + width = streams[n_streams - 1].width; + height = streams[n_streams - 1].height; + for (i = n_streams - 1; i--;) { + if (streams[i].width != height) + eprintf("videos do not have the compatible geometry\n"); + height = streams[i].height; + } + + if (!strcmp(streams->pixfmt, "xyza")) + process = process_lf; + else if (!strcmp(streams->pixfmt, "xyza f")) + process = process_f; + else + eprintf("pixel format %s is not supported, try xyza\n", streams->pixfmt); + + w = streams->width, streams->width = max_width; + h = streams->height, streams->height = max_height; + echeck_dimensions(streams, WIDTH | HEIGHT, NULL); + streams->width = width; + streams->height = height; + streams->frames = frames; + fprint_stream_head(stdout, streams); + streams->width = w; + streams->height = h; + efflush(stdout, "<stdout>"); + max_frame_size = max_width * max_height * streams->pixel_size; + + process(streams, n_streams); + + free(streams); + return 0; +}