blind

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

commit fa20f84e2d12bf9998591ce4e464180586d957ff
parent 0a034f2bd5a44c3cc0c033eacc940bb3bf73662c
Author: Mattias Andrée <maandree@kth.se>
Date:   Thu, 20 Jul 2017 20:03:52 +0200

Add blind-affine-colour and blind-split-chans

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

Diffstat:
Makefile | 2++
README | 6++++++
TODO | 25++++++++++++-------------
man/blind-affine-colour.1 | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
man/blind-arithm.1 | 3++-
man/blind-invert-matrix.1 | 3++-
man/blind-multiply-matrices.1 | 3++-
man/blind-rewrite-head.1 | 3++-
man/blind-split-chans.1 | 47+++++++++++++++++++++++++++++++++++++++++++++++
man/blind.7 | 6++++++
src/blind-affine-colour.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/blind-split-chans.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12 files changed, 335 insertions(+), 17 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,6 +3,7 @@ include $(CONFIGFILE) BIN =\ + blind-affine-colour\ blind-apply-palette\ blind-arithm\ blind-cat-cols\ @@ -76,6 +77,7 @@ BIN =\ blind-spectrum\ blind-spiral-gradient\ blind-split\ + blind-split-chans\ blind-split-cols\ blind-split-rows\ blind-square-gradient\ diff --git a/README b/README @@ -12,6 +12,9 @@ DESCRIPTION storing the video without first convert it with blind-to-video(1). UTILITIES + blind-affine-colour(1) + Apply an affine transformation to the colours in a video + blind-arithm(1) Perform simple arithmetic on a video @@ -234,6 +237,9 @@ UTILITIES blind-split(1) Split a video, by frame, into multiple videos + blind-split-chans(1) + Split colour channels into separate videos + blind-split-cols(1) Split a video vertically into multiple videos diff --git a/TODO b/TODO @@ -1,22 +1,17 @@ Fix blind-from-named without command -blind-transform affine transformation by matrix multiplication, -t for tiling, -s for - improve quality on downscaling (pixels' neighbours must not change). -blind-primary-key replace a primary with transparency, -g for greyscaled images. -blind-primaries given three selectable primaries split the video into three side-by-side which - only one primary active. -blind-apply-map remap pixels (distortion) using the X and Y values, -t for tiling, -s for - improve quality on downscaling (pixels' neighbours must not change). +blind-transform affine transformation by matrix multiplication, -[xy] for tiling, -s for + improve quality on downscaling (pixels' neighbours must not change) +blind-primary-key replace a primary with transparency, -g for greyscaled images +blind-colour-matrix create colour space conversion matrix +blind-apply-map remap pixels (distortion) using the X and Y values, -[xy] for tiling, -s for + improve quality on downscaling (pixels' neighbours must not change) blind-apply-kernel apply a convolution matrix. blind-find-frame a graphical tool for locating frames, should highlight key frames, and - play audio. Should support both regular videos files and uivf. + play audio. Should support both regular videos files and uivf finding key frames: ffprobe -show_frames (lists all frames) -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-invert-chroma invert the chroma -blind-from-sent convert a sent presentation to a one-frame-per-slide blind video. +blind-from-sent convert a sent presentation to a one-frame-per-slide blind video blind-kirsch https://en.wikipedia.org/wiki/Kirsch_operator blind-gaussian-noise https://en.wikipedia.org/wiki/Gaussian_noise @@ -43,6 +38,10 @@ blind-mean mean of multiple streams 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-apply-icc apply ICC profile to video +blind-convex-gradient create a gradient in the shape of a convex lens +blind-concave-gradient create a gradient in the shape of a concave lens + (convexo-concave gradient is not necessary is blind-convex-gradient + or blind-concave-gradient can be combined with blind-arithm for this) blind-from-video: add options to: * just run ffmpeg just print the output diff --git a/man/blind-affine-colour.1 b/man/blind-affine-colour.1 @@ -0,0 +1,71 @@ +.TH BLIND-AFFINE-COLOUR 1 blind +.SH NAME +blind-affine-colour - Apply an affine transformation to the colours in a video +.SH SYNOPSIS +.B blind-affine-colour +[-alp] +.I matrix-stream +.SH DESCRIPTION +.B blind-affine-colour +reads a video from stdin and a matrix video from +.I matrix-stream +and multiplies colours from stdin with matrices from +.I matrix-stream +and prints the resulting video to stdout. +.P +Each frame in +.I matrix-stream +is a matrix and shall have the width and height 5. +Each pixel in a frame is a cell in the matrix, +the pixels luma is multiples by its alpha value +to determine the value of the matrix cell. +.SH OPTIONS +.TP +.B -a +The width and height of the matrix shall be 4 +instead of 5 (reduced by 1) and the alpha values +of the pixels shall not be modified. +.TP +.B -l +The width and height of the matrix shall be 4 +instead of 5 (reduced by 1) making the transformation +linear instead of affine. +.TP +.B -p +Each frame in +.I matrix-stream +shall contain one matrix per pixel in a frame in +stdin. The video in +.I matrix-stream +shall be 5, 4, or 3, depending on whether +.B -a +and +.B -l +are specified, times are wide and tall as the +video in stdin. +.SH NOTES +If both +.B -a +and +.B -l +are specified, the matrices shall have the +width and height 3 instead of 5. +.SH REQUIREMENTS +.B blind-affine-colour +requires enough free memory to load 5, 4, or 3, +depending on whether +.B -a +and +.B -l +are specified, full rows from +.I matrix-stream +into memory. A frame requires 32 bytes per pixel +it contains. +.SH SEE ALSO +.BR blind (7), +.BR blind-arithm (1), +.BR blind-invert-matrix (1), +.BR blind-multiply-matrice (1) +.SH AUTHORS +Mattias Andrée +.RI < maandree@kth.se > diff --git a/man/blind-arithm.1 b/man/blind-arithm.1 @@ -90,7 +90,8 @@ Do not modify the Z channel (the third channel). .BR blind-set-alpha (1), .BR blind-set-luma (1), .BR blind-invert-luma (1), -.BR blind-set-saturation (1) +.BR blind-set-saturation (1), +.BR blind-affine-colour (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-invert-matrix.1 b/man/blind-invert-matrix.1 @@ -29,7 +29,8 @@ are identical. .BR blind-flop (1), .BR blind-rotate-90 (1), .BR blind-rotate-180 (1), -.BR blind-rotate-270 (1) +.BR blind-rotate-270 (1), +.BR blind-rewrite-head (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-multiply-matrices.1 b/man/blind-multiply-matrices.1 @@ -44,7 +44,8 @@ in reverse order. .BR blind-flop (1), .BR blind-rotate-90 (1), .BR blind-rotate-180 (1), -.BR blind-rotate-270 (1) +.BR blind-rotate-270 (1), +.BR blind-rewrite-head (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-rewrite-head.1 b/man/blind-rewrite-head.1 @@ -72,7 +72,8 @@ two copies of on disc. .BR blind-from-video (1), .BR blind-split (1), .BR blind-read-head (1), -.BR blind-write-head (1) +.BR blind-write-head (1), +.BR blind-transpose (1) .SH AUTHORS Mattias Andrée .RI < maandree@kth.se > diff --git a/man/blind-split-chans.1 b/man/blind-split-chans.1 @@ -0,0 +1,47 @@ +.TH BLIND-SPLIT-CHANS 1 blind +.SH NAME +blind-split-chans - Split colour channels into separate videos +.SH SYNOPSIS +.B blind-split-chans +.I X-file +.I Y-file +.I Z-file +.RI [ alpha-file ] +.SH DESCRIPTION +.B blind-split-chans +reads a video from stdin and prints +it to +.I X-file +with the values of the first channel +(the X channel) in written to all +channels, to +.I Y-file +with the values of the second channel +(the Y channel) in written to all +channels, to +.I Z-file +with the values of the third channel +(the Z channel) in written to all +channels, and to +.I alpha-file +with the values of the fourth channel +(the alpha channel) in written to all +channels. +.P +If +.I alpha-file +is omitted, values of the alpha channel +are instead written to the alpha channels +in +.IR X-file , +.IR Y-file , +and +.IR Z-file . +.SH SEE ALSO +.BR blind (7), +.BR blind-arithm (1), +.BR blind-cat-cols (1), +.BR blind-cat-rows (1) +.SH AUTHORS +Mattias Andrée +.RI < maandree@kth.se > diff --git a/man/blind.7 b/man/blind.7 @@ -19,6 +19,9 @@ first convert it with .BR blind-to-video (1). .SH UTILITIES .TP +.BR blind-affine-colour (1) +Apply an affine transformation to the colours in a video +.TP .BR blind-arithm (1) Perform simple arithmetic on a video .TP @@ -247,6 +250,9 @@ Generate a video with a spiral gradient .BR blind-split (1) Split a video, by frame, into multiple videos .TP +.BR blind-split-chans (1) +Split colour channels into separate videos +.TP .BR blind-split-cols (1) Split a video vertically into multiple videos .TP diff --git a/src/blind-affine-colour.c b/src/blind-affine-colour.c @@ -0,0 +1,118 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TYPE +#include "common.h" + +USAGE("[-alp] matrix-stream") + +static int skip_alpha = 0; +static int linear = 0; +static int per_pixel = 0; +static size_t dim; + +#define FILE "blind-affine-colour.c" +#include "define-functions.h" + +int +main(int argc, char *argv[]) +{ + struct stream colour, matrix; + void (*process)(struct stream *colour, struct stream *matrix); + size_t h; + + ARGBEGIN { + case 'a': + skip_alpha = 1; + break; + case 'l': + linear = 1; + break; + case 'p': + per_pixel = 1; + break; + default: + usage(); + } ARGEND; + + if (argc != 1) + usage(); + + eopen_stream(&colour, NULL); + eopen_stream(&matrix, argv[0]); + + SELECT_PROCESS_FUNCTION(&colour); + + if (strcmp(colour.pixfmt, matrix.pixfmt)) + eprintf("videos use incompatible pixel formats\n"); + + dim = colour.n_chan - (size_t)skip_alpha + (size_t)!linear; + h = matrix.height, matrix.height = dim; + echeck_dimensions(&matrix, WIDTH | HEIGHT, "matrix"); + matrix.height = h; + + if (per_pixel) { + if (matrix.height != dim * colour.height || matrix.width != dim * colour.width) + eprintf("the matrice should have the size %zux%zu, but are %zux%zu", + dim * colour.height, dim * colour.width, matrix.height, matrix.width); + } else { + if (matrix.height != dim || matrix.width != dim) + eprintf("the matrice should have the size %zux%zu, but are %zux%zu", + dim, dim, matrix.height, matrix.width); + } + + fprint_stream_head(stdout, &colour); + efflush(stdout, "<stdout>"); + process(&colour, &matrix); + return 0; +} + +#else + +static void +PROCESS(struct stream *colour, struct stream *matrix) +{ + char *mbuf; + TYPE *mat, *pixel, V[5], M[ELEMENTSOF(V)][ELEMENTSOF(V)]; + size_t ptr, i, j, w, x = 0, y = 0, cn; + + mbuf = emalloc2(dim, matrix->row_size); + mat = (TYPE *)mbuf; + w = matrix->width * matrix->n_chan; + cn = colour->n_chan - (size_t)skip_alpha; + + memset(M, 0, sizeof(M)); + for (i = 0; i < ELEMENTSOF(V); i++) + M[i][i] = V[i] = 1; + + do { + for (ptr = 0; ptr + colour->pixel_size <= colour->ptr; x = (x + 1) % colour->width, ptr += colour->pixel_size) { + if (!x) { + if (!y && !eread_segment(matrix, mbuf, dim * matrix->row_size)) + break; + if (!per_pixel) + y = (y + 1) % colour->height; + } + if (per_pixel) { + mat = (TYPE *)(mbuf + x * dim * matrix->pixel_size); + for (i = 0; i < dim; i++, mat += w) + for (j = 0; j < dim; j++) + M[i][j] = mat[j * matrix->n_chan + 1] * mat[(j + 1) * matrix->n_chan - 1]; + } + pixel = (TYPE *)(colour->buf + ptr); + for (i = 0; i < dim; i++) { + V[i] = 0; + for (j = 0; j < cn; j++) + V[i] += M[i][j] * pixel[j]; + for (; j < dim; j++) + V[i] += M[i][j]; + } + for (i = 0; i < cn; i++) + pixel[i] = V[i] / V[cn]; + } + ewriteall(STDOUT_FILENO, colour->buf, ptr, "<stdout>"); + memmove(colour->buf, colour->buf + ptr, colour->ptr -= ptr); + } while (eread_stream(colour, SIZE_MAX)); + if (colour->ptr) + eprintf("%s: incomplete frame\n", colour->file); +} + +#endif diff --git a/src/blind-split-chans.c b/src/blind-split-chans.c @@ -0,0 +1,65 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +USAGE("X-file Y-file Z-file [alpha-file]") + +int +main(int argc, char *argv[]) +{ + struct stream stream; + char xbuf[BUFSIZ], ybuf[BUFSIZ], zbuf[BUFSIZ], abuf[BUFSIZ]; + int xfd, yfd, zfd, afd = -1; + size_t i, n, ptr; + + UNOFLAGS(argc != 3 && argc != 4); + + eopen_stream(&stream, NULL); + + xfd = eopen(argv[0], O_WRONLY | O_CREAT | O_TRUNC, 0666); + yfd = eopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0666); + zfd = eopen(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (argc == 4) + afd = eopen(argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0666); + + if (DPRINTF_HEAD(xfd, stream.frames, stream.width, stream.height, stream.pixfmt) < 0) + eprintf("dprintf %s:", argv[0]); + if (DPRINTF_HEAD(yfd, stream.frames, stream.width, stream.height, stream.pixfmt) < 0) + eprintf("dprintf %s:", argv[1]); + if (DPRINTF_HEAD(zfd, stream.frames, stream.width, stream.height, stream.pixfmt) < 0) + eprintf("dprintf %s:", argv[2]); + if (afd >= 0 && DPRINTF_HEAD(afd, stream.frames, stream.width, stream.height, stream.pixfmt) < 0) + eprintf("dprintf %s:", argv[3]); + + n = (stream.n_chan - (afd < 0)) * stream.chan_size; + do { + for (ptr = 0; ptr + stream.pixel_size <= stream.ptr; ptr += stream.pixel_size) { + for (i = 0; i < n; i += stream.chan_size) { + memcpy(xbuf + ptr + i, stream.buf + ptr + 0 * stream.chan_size, stream.chan_size); + memcpy(ybuf + ptr + i, stream.buf + ptr + 1 * stream.chan_size, stream.chan_size); + memcpy(zbuf + ptr + i, stream.buf + ptr + 2 * stream.chan_size, stream.chan_size); + if (afd >= 0) + memcpy(abuf + ptr + i, stream.buf + ptr + 3 * stream.chan_size, stream.chan_size); + } + if (afd < 0) { + memcpy(xbuf + ptr + n, stream.buf + ptr + 3 * stream.chan_size, stream.chan_size); + memcpy(ybuf + ptr + n, stream.buf + ptr + 3 * stream.chan_size, stream.chan_size); + memcpy(zbuf + ptr + n, stream.buf + ptr + 3 * stream.chan_size, stream.chan_size); + } + } + ewriteall(xfd, xbuf, ptr, argv[0]); + ewriteall(yfd, ybuf, ptr, argv[1]); + ewriteall(zfd, zbuf, ptr, argv[2]); + if (afd >= 0) + ewriteall(afd, abuf, ptr, argv[3]); + memmove(stream.buf, stream.buf + ptr, stream.ptr -= ptr); + } while (eread_stream(&stream, SIZE_MAX)); + if (stream.ptr) + eprintf("%s: incomplete frame\n", stream.file); + + close(xfd); + close(yfd); + close(zfd); + if (afd >= 0) + close(afd); + return 0; +}