Add blind-apply-kernel - blind - suckless command-line video editing utility | |
git clone git://git.suckless.org/blind | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit ebe2e88b44f46e59bdefef1eb585078d5fa6d4d4 | |
parent 28635cabc72a60674c18c0e160fefdbd4af41734 | |
Author: Mattias Andrée <[email protected]> | |
Date: Sat, 22 Jul 2017 19:33:54 +0200 | |
Add blind-apply-kernel | |
Signed-off-by: Mattias Andrée <[email protected]> | |
Diffstat: | |
M Makefile | 1 + | |
M README | 6 ++++++ | |
M TODO | 1 - | |
A man/blind-apply-kernel.1 | 69 ++++++++++++++++++++++++++++++ | |
M man/blind-gauss-blur.1 | 4 +++- | |
M man/blind.7 | 6 ++++++ | |
M src/blind-affine-colour.c | 2 ++ | |
A src/blind-apply-kernel.c | 159 +++++++++++++++++++++++++++++… | |
8 files changed, 246 insertions(+), 2 deletions(-) | |
--- | |
diff --git a/Makefile b/Makefile | |
@@ -4,6 +4,7 @@ include $(CONFIGFILE) | |
BIN =\ | |
blind-affine-colour\ | |
+ blind-apply-kernel\ | |
blind-apply-palette\ | |
blind-arithm\ | |
blind-cat-cols\ | |
diff --git a/README b/README | |
@@ -15,6 +15,12 @@ UTILITIES | |
blind-affine-colour(1) | |
Apply an affine transformation to the colours in a video | |
+ blind-apply-kernel(1) | |
+ Apply a convolution matrix to a video | |
+ | |
+ blind-apply-palette(1) | |
+ Apply a colour palette to a video | |
+ | |
blind-arithm(1) | |
Perform simple arithmetic on a video | |
diff --git a/TODO b/TODO | |
@@ -4,7 +4,6 @@ blind-primary-key replace a primary with transparency, -… | |
blind-colour-matrix create colour space conversion matrix | |
blind-apply-map remap pixels (distortion) using the X and Y val… | |
improve quality on downscaling (pixels' neighb… | |
-blind-apply-kernel apply a convolution matrix. | |
blind-find-frame a graphical tool for locating frames, should highlight… | |
play audio. Should support both regular videos… | |
finding key frames: ffprobe -show_frames (list… | |
diff --git a/man/blind-apply-kernel.1 b/man/blind-apply-kernel.1 | |
@@ -0,0 +1,69 @@ | |
+.TH BLIND-APPLY-KERNEL 1 blind | |
+.SH NAME | |
+blind-apply-kernel - Apply a convolution matrix to a video | |
+.SH SYNOPSIS | |
+.B blind-apply-kernel | |
+[-apPxy] | |
+.I kernel-stream | |
+.SH DESCRIPTION | |
+.B blind-apply-kernel | |
+reads a video from stdin and a convolution matrix video | |
+from | |
+.I kernel-stream | |
+and apply the convolution matrix in each frame the | |
+same frame in stdin, and prints the resulting video | |
+to stdout. | |
+.SH OPTIONS | |
+.TP | |
+.B -a | |
+Used to optimise performance if it is known that | |
+the video is opaque, and to ensure that the output | |
+video is opaque. | |
+.TP | |
+.B -p | |
+Each frame in | |
+.I kernel-stream | |
+shall contain one matrix per pixel in a frame in | |
+stdin. The width of | |
+.I kernel-stream | |
+shall be a multiple of the width of stdin, the width | |
+shall be the width of stdin multiplied by the width | |
+of the convolution matrix. The height of | |
+.I kernel-stream | |
+shall be a multiple of the height of stdin, the | |
+height shall be the height of stdin multiplied by the | |
+height of the convolution matrix. | |
+.TP | |
+.B -P | |
+Apply the convolution with first premultiplying | |
+the alpha channel. | |
+.TP | |
+.B -x | |
+When encountering the left or right edge of the video, | |
+wrap around to the opposite edge. | |
+.TP | |
+.B -y | |
+When encountering the upper or lower edge of the video, | |
+wrap around to the opposite edge. | |
+.SH REQUIREMENTS | |
+.B blind-apply-kernel | |
+requires enough free memory to load two full frames | |
+from stdin and one full frame from | |
+.I kernel-stream | |
+into memory. However, if | |
+.I -p | |
+is used, the height of | |
+.I kernel-stream | |
+divide by the height of stdin number of rows from | |
+.I kernel-stream | |
+rather than a full frame from | |
+.I kernel-stream | |
+is loaded into memory. | |
+A frame or row requires 32 bytes per pixel it contains. | |
+.SH SEE ALSO | |
+.BR blind (7), | |
+.BR blind-make-kernel (1), | |
+.BR blind-gauss-blur (1) | |
+.SH AUTHORS | |
+Mattias Andrée | |
+.RI < [email protected] > | |
diff --git a/man/blind-gauss-blur.1 b/man/blind-gauss-blur.1 | |
@@ -79,7 +79,9 @@ memory. A frame requires 32 bytes per pixel it contains. | |
.SH SEE ALSO | |
.BR blind (7), | |
.BR blind-single-colour (1), | |
-.BR blind-time-blur (1) | |
+.BR blind-time-blur (1), | |
+.BR blind-make-kernel (1), | |
+.BR blind-apply-kernel (1) | |
.SH AUTHORS | |
Mattias Andrée | |
.RI < [email protected] > | |
diff --git a/man/blind.7 b/man/blind.7 | |
@@ -22,6 +22,12 @@ first convert it with | |
.BR blind-affine-colour (1) | |
Apply an affine transformation to the colours in a video | |
.TP | |
+.BR blind-apply-kernel (1) | |
+Apply a convolution matrix to a video | |
+.TP | |
+.BR blind-apply-palette (1) | |
+Apply a colour palette to a video | |
+.TP | |
.BR blind-arithm (1) | |
Perform simple arithmetic on a video | |
.TP | |
diff --git a/src/blind-affine-colour.c b/src/blind-affine-colour.c | |
@@ -113,6 +113,8 @@ PROCESS(struct stream *colour, struct stream *matrix) | |
} while (eread_stream(colour, SIZE_MAX)); | |
if (colour->ptr) | |
eprintf("%s: incomplete frame\n", colour->file); | |
+ | |
+ free(mbuf); | |
} | |
#endif | |
diff --git a/src/blind-apply-kernel.c b/src/blind-apply-kernel.c | |
@@ -0,0 +1,159 @@ | |
+/* See LICENSE file for copyright and license details. */ | |
+#ifndef TYPE | |
+#include "common.h" | |
+ | |
+USAGE("[-apPxy] kernel-stream") | |
+ | |
+static int no_alpha = 0; | |
+static int dont_premultiply = 0; | |
+static int per_pixel = 0; | |
+static int wrap_x = 0; | |
+static int wrap_y = 0; | |
+static size_t kern_w; | |
+static size_t kern_h; | |
+ | |
+#define FILE "blind-apply-kernel.c" | |
+#include "define-functions.h" | |
+ | |
+int | |
+main(int argc, char *argv[]) | |
+{ | |
+ struct stream colour, kernel; | |
+ void (*process)(struct stream *colour, struct stream *kernel); | |
+ size_t tmp; | |
+ | |
+ ARGBEGIN { | |
+ case 'a': | |
+ no_alpha = 1; | |
+ break; | |
+ case 'p': | |
+ per_pixel = 1; | |
+ break; | |
+ case 'P': | |
+ dont_premultiply = 1; | |
+ break; | |
+ case 'x': | |
+ wrap_x = 1; | |
+ break; | |
+ case 'y': | |
+ wrap_y = 1; | |
+ break; | |
+ default: | |
+ usage(); | |
+ } ARGEND; | |
+ | |
+ if (argc != 1) | |
+ usage(); | |
+ | |
+ eopen_stream(&colour, NULL); | |
+ eopen_stream(&kernel, argv[0]); | |
+ | |
+ SELECT_PROCESS_FUNCTION(&colour); | |
+ if (colour.encoding != kernel.encoding || colour.n_chan != kernel.n_ch… | |
+ eprintf("videos use incompatible pixel formats"); | |
+ if (per_pixel && !(kernel.width % colour.width || kernel.height % colo… | |
+ eprintf("-p is specified but the dimensions of kernel-stream " | |
+ "are not multiples of the dimensions of stdin."); | |
+ | |
+ kern_w = per_pixel ? kernel.width / colour.width : kernel.width; | |
+ kern_h = per_pixel ? kernel.height / colour.height : kernel.height; | |
+ | |
+ tmp = kernel.height, kernel.height = kern_h; | |
+ echeck_dimensions(&colour, WIDTH | HEIGHT, NULL); | |
+ echeck_dimensions(&kernel, WIDTH | HEIGHT, NULL); | |
+ kernel.height = tmp; | |
+ | |
+ fprint_stream_head(stdout, &colour); | |
+ efflush(stdout, "<stdout>"); | |
+ process(&colour, &kernel); | |
+ return 0; | |
+} | |
+ | |
+#else | |
+ | |
+static void | |
+PROCESS(struct stream *colour, struct stream *kernel) | |
+{ | |
+ TYPE *out, *clr, *krn, *kern, *pix; | |
+ size_t i, x, y, n, x2, y2; | |
+ ssize_t cx, cy, xoff, yoff; | |
+ | |
+ out = emalloc(colour->frame_size); | |
+ clr = emalloc(colour->frame_size); | |
+ krn = emalloc2(kern_h, kernel->row_size); | |
+ | |
+ xoff = (ssize_t)(kern_w / 2); | |
+ yoff = (ssize_t)(kern_h / 2); | |
+ | |
+ n = colour->width * colour->height * colour->n_chan; | |
+ while (eread_frame(colour, clr)) { | |
+ /* premultiply */ | |
+ if (!no_alpha && !dont_premultiply) { | |
+ for (i = 0; i < n; i += 4) { | |
+ clr[i + 0] *= clr[i + 3]; | |
+ clr[i + 1] *= clr[i + 3]; | |
+ clr[i + 2] *= clr[i + 3]; | |
+ } | |
+ } | |
+ | |
+ /* apply kernel */ | |
+ memset(out, 0, colour->frame_size); | |
+ pix = out; | |
+ for (y = 0; y < colour->height; y++) { | |
+ if ((!y || per_pixel) && !eread_segment(kernel, krn, k… | |
+ goto done; | |
+ for (x = 0; x < colour->width; x++, pix += colour->n_c… | |
+ kern = per_pixel ? (krn + x * kern_w * kernel-… | |
+ for (y2 = 0; y2 < kern_h; y2++, kern += kernel… | |
+ cy = (ssize_t)(y + y2) - yoff; | |
+ if (cy < 0 || (size_t)cy >= colour->he… | |
+ if (!wrap_y) | |
+ continue; | |
+ cy %= (ssize_t)(colour->height… | |
+ if (cy < 0) | |
+ cy += (ssize_t)(colour… | |
+ } | |
+ for (x2 = 0; x2 < kern_w; x2++) { | |
+ cx = (ssize_t)(x + x2) - xoff; | |
+ if (cx < 0 || (size_t)cx >= co… | |
+ if (!wrap_x) | |
+ continue; | |
+ cx %= (ssize_t)(colour… | |
+ if (cx < 0) | |
+ cx += (ssize_t… | |
+ } | |
+ for (i = 0; i < colour->n_chan… | |
+ pix[i] += kern[x2 * ke… | |
+ clr[((size_t… | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+ /* unpremultiply */ | |
+ if (!dont_premultiply) { | |
+ for (i = 0; i < n; i += 4) { | |
+ if (out[i + 3]) { | |
+ out[i + 0] /= out[i + 3]; | |
+ out[i + 1] /= out[i + 3]; | |
+ out[i + 2] /= out[i + 3]; | |
+ } | |
+ } | |
+ } | |
+ | |
+ /* ensure video is opaque if -a was used */ | |
+ if (no_alpha) | |
+ for (i = 0; i < n; i += 4) | |
+ out[i + 3] = 1; | |
+ | |
+ /* output video */ | |
+ ewriteall(STDOUT_FILENO, out, colour->frame_size, "<stdout>"); | |
+ } | |
+done: | |
+ | |
+ free(out); | |
+ free(clr); | |
+ free(krn); | |
+} | |
+ | |
+#endif |