blind

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

commit 478b53f935264bdfe4efe394f8d804a1361a6770
parent ab3493cd565f6dd620016469b5dcbc84f89b881d
Author: Mattias Andrée <maandree@kth.se>
Date:   Sat,  8 Apr 2017 13:57:36 +0200

Document memory requirements, minor style fixes, more use of BUFSIZ, fix warnings, and fix potential buffer overflow

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

Diffstat:
Mman/blind-compress.1 | 4++++
Mman/blind-crop.1 | 15+++++++++++++++
Mman/blind-decompress.1 | 4++++
Mman/blind-extend.1 | 9+++++++++
Mman/blind-flip.1 | 4++++
Mman/blind-flop.1 | 5+++++
Mman/blind-gauss-blur.1 | 4++++
Mman/blind-repeat.1 | 6++++++
Mman/blind-rotate-180.1 | 11+++++++++++
Mman/blind-rotate-270.1 | 10++++++++++
Mman/blind-rotate-90.1 | 10++++++++++
Mman/blind-transpose.1 | 7+++++++
Msrc/arg.h | 4++--
Msrc/blind-colour-srgb.c | 2+-
Msrc/blind-compress.c | 1-
Msrc/blind-concat.c | 4++--
Msrc/blind-crop.c | 1-
Msrc/blind-extend.c | 11+++++------
Msrc/blind-flip.c | 1-
Msrc/blind-flop.c | 1-
Msrc/blind-from-video.c | 8++++----
Msrc/blind-gauss-blur.c | 4++--
Msrc/blind-single-colour.c | 8++++----
Msrc/blind-to-image.c | 2+-
Msrc/blind-to-video.c | 2+-
Msrc/blind-transpose.c | 1-
Msrc/stream.c | 31++++++++++++++++++++-----------
Msrc/stream.h | 12++++++------
28 files changed, 137 insertions(+), 45 deletions(-)

diff --git a/man/blind-compress.1 b/man/blind-compress.1 @@ -18,6 +18,10 @@ It is recommended to combine .B blind-compress with .BR "lz4 -1" . +.SH REQUIREMENTS +.B blind-compress +requires enough free memory to load two full frames into +memory. A frame requires 32 bytes per pixel it contains. .SH SEE ALSO .BR blind (7), .BR blind-decompress (1), diff --git a/man/blind-crop.1 b/man/blind-crop.1 @@ -49,6 +49,21 @@ pixels rightward of the output video's left-most pixel, and the subvideo's top-most pixel will be positioned .I top pixels downward of the output video's left-most pixel. +.SH REQUIREMENTS +.B blind-crop +requires enough free memory to load two full frames into +memory, one of the size of the source video's frames, +and one of the size of the target video's frames. However, +if +.B -s +or +.B -S +is used, only memory for one full frame, of the size of +the source video's frames, are required. A frame requires +32 bytes per pixel it contains. +.B blind-crop +has not been optimised for memory usage, but instead +for code simplicity. .SH SEE ALSO .BR blind (7), .BR blind-extend (1) diff --git a/man/blind-decompress.1 b/man/blind-decompress.1 @@ -7,6 +7,10 @@ blind-decompress - Decompress a video compressed by blind-compress(1) .B blind-decompress removes compressed added by .BR blind-compress (1). +.SH REQUIREMENTS +.B blind-decompress +requires enough free memory to load one full frame into +memory. A frame requires 32 bytes per pixel it contains. .SH SEE ALSO .BR blind (7), .BR blind-compress (1), diff --git a/man/blind-extend.1 b/man/blind-extend.1 @@ -52,6 +52,15 @@ of the input videos in the new room, such that the right-most part of the video has is put side-by-side with the left-most part of the video, and analogously for the other sides. +.SH REQUIREMENTS +.B blind-extend +requires enough free memory to load two full frames into +memory, one of the size of the source video's frames, +and one of the size of the target video's frames. A frame +requires 32 bytes per pixel it contains. +.B blind-extend +has not been optimised for memory usage, but instead +for code simplicity. .SH SEE ALSO .BR blind (7), .BR blind-crop (1) diff --git a/man/blind-flip.1 b/man/blind-flip.1 @@ -7,6 +7,10 @@ blind-flip - Mirror a video vertically .B blind-flip reads a video from stdin and prints it, mirrored vertically, to stdout. +.SH REQUIREMENTS +.B blind-flip +requires enough free memory to load one full frame into +memory. A frame requires 32 bytes per pixel it contains. .SH SEE ALSO .BR blind (7), .BR blind-flop (1), diff --git a/man/blind-flop.1 b/man/blind-flop.1 @@ -7,6 +7,11 @@ blind-flop - Mirror a video horizontally .B blind-flop reads a video from stdin and prints it, mirrored horizontally, to stdout. +.SH REQUIREMENTS +.B blind-flop +requires enough free memory to load two frame rows into memory. +A frame row requires 32 bytes per pixel it contains, that is, +32 bytes times the width of the video in pixel. .SH SEE ALSO .BR blind (7), .BR blind-flip (1), diff --git a/man/blind-gauss-blur.1 b/man/blind-gauss-blur.1 @@ -72,6 +72,10 @@ specified. Use the Y value (multiplied by the alpha value) from .I sd-stream as the standard deviation all channels. +.SH REQUIREMENTS +.B blind-compress +requires enough free memory to load three full frames into +memory. A frame requires 32 bytes per pixel it contains. .SH SEE ALSO .BR blind (7), .BR blind-single-colour (1), diff --git a/man/blind-repeat.1 b/man/blind-repeat.1 @@ -33,6 +33,12 @@ will read stdin into memory; you are highly discouraged from using this unless stdin is a single frame, or known to only be a very small number of frames, is it can potentially use all of the computer's memory. +.SH REQUIREMENTS +.B blind-repeat +requires enough free memory to load the entire video +into memory if it is read from stdin. A frame requires +32 bytes per pixel it contains. So for a 720p video at +25 Hz, 1 GB is reached in just below 1.5 seconds. .SH SEE ALSO .BR blind (7), .BR blind-from-image (1) diff --git a/man/blind-rotate-180.1 b/man/blind-rotate-180.1 @@ -7,6 +7,17 @@ blind-rotate-180 - Rotate a video 180 degrees .B blind-rotate-180 reads a video from stdin and prints it, rotated 180 degrees, to stdout. +.SH REQUIREMENTS +.B blind-rotate-180 +is implemented as a shell script pipeline of +.BR blind-flip (1) +and +.BR blind-flop (1), +see those for details on requirements. +.B blind-rotate-180 +is not been optimised for memory usage, but instead +for code simplicity, however, it does not exceed the +optimum greatly. .SH SEE ALSO .BR blind (7), .BR blind-rotate-90 (1), diff --git a/man/blind-rotate-270.1 b/man/blind-rotate-270.1 @@ -8,6 +8,16 @@ blind-rotate-270 - Rotate a video 270 degrees clockwise reads a video from stdin and prints it, rotated 270 degrees clockwise (90 degrees anti-clockwise), to stdout. +.SH REQUIREMENTS +.B blind-rotate-270 +is implemented as a shell script pipeline of +.BR blind-flop (1) +and +.BR blind-transpose (1), +see those for details on requirements. +.B blind-rotate-270 +is not been optimised for memory usage, but instead +for code simplicity. .SH SEE ALSO .BR blind (7), .BR blind-rotate-90 (1), diff --git a/man/blind-rotate-90.1 b/man/blind-rotate-90.1 @@ -7,6 +7,16 @@ blind-rotate-90 - Rotate a video 90 degrees clockwise .B blind-rotate-90 reads a video from stdin and prints it, rotated 90 degrees clockwise, to stdout. +.SH REQUIREMENTS +.B blind-rotate-90 +is implemented as a shell script pipeline of +.BR blind-transpose (1) +and +.BR blind-flop (1), +see those for details on requirements. +.B blind-rotate-90 +is not been optimised for memory usage, but instead +for code simplicity. .SH SEE ALSO .BR blind (7), .BR blind-rotate-180 (1), diff --git a/man/blind-transpose.1 b/man/blind-transpose.1 @@ -10,6 +10,13 @@ transposed, to stdout. .P To transpose a videos means to swap the X and Y coordinates. +.SH REQUIREMENTS +.B blind-transpose +requires enough free memory to load two full frames into +memory. A frame requires 32 bytes per pixel it contains. +.B blind-transpose +has not been optimised for memory usage, but instead +for code simplicity. .SH SEE ALSO .BR blind (7), .BR blind-flip (1), diff --git a/src/arg.h b/src/arg.h @@ -73,9 +73,9 @@ extern char *argv0; (&argv[0][1]) :\ (argc--, argv++, argv[0]))) -#define LNGARG() &argv[0][0] +#define UARGF() EARGF(usage()) -#define EARG() EARGF(usage()) +#define LNGARG() &argv[0][0] #define ENOFLAGS(...) ARGBEGIN {\ default:\ diff --git a/src/blind-colour-srgb.c b/src/blind-colour-srgb.c @@ -12,7 +12,7 @@ main(int argc, char *argv[]) ARGBEGIN { case 'd': - depth = etoi_flag('d', EARG(), 1, 64); + depth = etoi_flag('d', UARGF(), 1, 64); break; case 'l': linear = 1; diff --git a/src/blind-compress.c b/src/blind-compress.c @@ -51,7 +51,6 @@ main(int argc, char *argv[]) buf[0] = emalloc(n); buf[1] = ecalloc(1, n); - memcpy(buf[0], stream.buf, stream.ptr); for (i = 0; eread_frame(&stream, buf[i], n); i ^= 1) { parts = compare(buf[i], buf[i ^ 1], n, &cmp, &cmpsize); for (off = part = 0; part < parts; part += 2) { diff --git a/src/blind-concat.c b/src/blind-concat.c @@ -209,10 +209,10 @@ main(int argc, char *argv[]) ARGBEGIN { case 'o': - output_file = EARG(); + output_file = UARGF(); break; case 'j': - jobs = etozu_flag('j', EARG(), 1, SHRT_MAX); + jobs = etozu_flag('j', UARGF(), 1, SHRT_MAX); break; default: usage(); diff --git a/src/blind-crop.c b/src/blind-crop.c @@ -77,7 +77,6 @@ main(int argc, char *argv[]) right_start = left + orown; right = irown - right_start; - memcpy(buf, stream.buf, ptr = stream.ptr); while (eread_frame(&stream, buf, n)) { if (tile) { for (ptr = y = 0; y < stream.height; y++) { diff --git a/src/blind-extend.c b/src/blind-extend.c @@ -14,23 +14,23 @@ main(int argc, char *argv[]) { struct stream stream; char *buf, *image; - size_t ptr, n, m, imgw, imgh, rown; + size_t n, m, imgw, imgh, rown; size_t xoff, yoff, h, x, y; size_t left = 0, right = 0, top = 0, bottom = 0; int tile = 0; ARGBEGIN { case 'l': - left = etozu_flag('l', EARG(), 0, SIZE_MAX); + left = etozu_flag('l', UARGF(), 0, SIZE_MAX); break; case 'r': - right = etozu_flag('r', EARG(), 0, SIZE_MAX); + right = etozu_flag('r', UARGF(), 0, SIZE_MAX); break; case 'a': - top = etozu_flag('a', EARG(), 0, SIZE_MAX); + top = etozu_flag('a', UARGF(), 0, SIZE_MAX); break; case 'b': - bottom = etozu_flag('b', EARG(), 0, SIZE_MAX); + bottom = etozu_flag('b', UARGF(), 0, SIZE_MAX); break; case 't': tile = 1; @@ -80,7 +80,6 @@ main(int argc, char *argv[]) xoff = (rown - left % rown) % rown; yoff = (stream.height - top % stream.height) % stream.height; - memcpy(buf, stream.buf, ptr = stream.ptr); while (eread_frame(&stream, buf, n)) { if (!tile) { for (y = 0; y < stream.height; y++) diff --git a/src/blind-flip.c b/src/blind-flip.c @@ -26,7 +26,6 @@ main(int argc, char *argv[]) n = stream.height * (row_size = stream.width * stream.pixel_size); buf = emalloc(n); - memcpy(buf, stream.buf, stream.ptr); while (eread_frame(&stream, buf, n)) for (ptr = n; ptr;) ewriteall(STDOUT_FILENO, buf + (ptr -= row_size), row_size, "<stdout>"); diff --git a/src/blind-flop.c b/src/blind-flop.c @@ -30,7 +30,6 @@ main(int argc, char *argv[]) image = emalloc(n); m = n - stream.pixel_size; - memcpy(buf, stream.buf, stream.ptr); while (eread_row(&stream, buf, n)) { for (i = 0; i < stream.pixel_size; i++) for (j = 0; j < n; j += stream.pixel_size) diff --git a/src/blind-from-video.c b/src/blind-from-video.c @@ -172,7 +172,7 @@ convert(const char *infile, int outfd, const char *outfile, size_t width, size_t if (dup2(pipe_rw[1], STDOUT_FILENO) == -1) eprintf("dup2:"); close(pipe_rw[1]); - execvp("ffmpeg", cmd); + execvp("ffmpeg", (char **)(void *)cmd); eprintf("exec ffmpeg:"); } @@ -221,13 +221,13 @@ main(int argc, char *argv[]) skip_length = 1; break; case 'r': - frame_rate = EARG(); + frame_rate = UARGF(); break; case 'w': - width = etozu_flag('w', EARG(), 1, SIZE_MAX); + width = etozu_flag('w', UARGF(), 1, SIZE_MAX); break; case 'h': - height = etozu_flag('h', EARG(), 1, SIZE_MAX); + height = etozu_flag('h', UARGF(), 1, SIZE_MAX); break; default: usage(); diff --git a/src/blind-gauss-blur.c b/src/blind-gauss-blur.c @@ -317,10 +317,10 @@ main(int argc, char *argv[]) measure_y_only = 1; break; case 'j': - jobs = etozu_flag('j', EARG(), 1, SHRT_MAX); + jobs = etozu_flag('j', UARGF(), 1, SHRT_MAX); break; case 's': - arg = EARG(); + arg = UARGF(); if (!strcmp(arg, "auto")) auto_spread = 1; else diff --git a/src/blind-single-colour.c b/src/blind-single-colour.c @@ -16,7 +16,7 @@ main(int argc, char *argv[]) struct stream stream; double X, Y, Z, alpha = 1; size_t x, y, n; - pixel_t buf[1024]; + pixel_t buf[BUFSIZ / 4]; ssize_t r; int inf = 0; char *arg; @@ -27,17 +27,17 @@ main(int argc, char *argv[]) ARGBEGIN { case 'f': - arg = EARG(); + arg = UARGF(); if (!strcmp(arg, "inf")) inf = 1, stream.frames = 0; else stream.frames = etozu_flag('f', arg, 1, SIZE_MAX); break; case 'w': - stream.width = etozu_flag('w', EARG(), 1, SIZE_MAX); + stream.width = etozu_flag('w', UARGF(), 1, SIZE_MAX); break; case 'h': - stream.height = etozu_flag('h', EARG(), 1, SIZE_MAX); + stream.height = etozu_flag('h', UARGF(), 1, SIZE_MAX); break; default: usage(); diff --git a/src/blind-to-image.c b/src/blind-to-image.c @@ -91,7 +91,7 @@ main(int argc, char *argv[]) ARGBEGIN { case 'd': - depth = etoi_flag('d', EARG(), 1, 64); + depth = etoi_flag('d', UARGF(), 1, 64); break; case 'f': farbfeld = 1; diff --git a/src/blind-to-video.c b/src/blind-to-video.c @@ -123,7 +123,7 @@ main(int argc, char *argv[]) if (dup2(pipe_rw[0], STDIN_FILENO) == -1) eprintf("dup2:"); close(pipe_rw[0]); - execvp("ffmpeg", cmd); + execvp("ffmpeg", (char **)(void *)cmd); eprintf("exec ffmpeg:"); } diff --git a/src/blind-transpose.c b/src/blind-transpose.c @@ -35,7 +35,6 @@ main(int argc, char *argv[]) srch *= ps; srcw *= dx = imgw * ps; imgw *= ps; - memcpy(buf, stream.buf, stream.ptr); while (eread_frame(&stream, buf, n)) { for (b = y = 0; y < srch; y += ps) for (x = 0; x < srcw; x += dx) diff --git a/src/stream.c b/src/stream.c @@ -32,14 +32,11 @@ eninit_stream(int status, struct stream *stream) } *p = '\0'; - w = strchr(stream->buf, ' '); - if (!w) + if (!(w = strchr(stream->buf, ' '))) goto bad_format; - h = strchr(w + 1, ' '); - if (!h) + if (!(h = strchr(w + 1, ' '))) goto bad_format; - f = strchr(h + 1, ' '); - if (!f) + if (!(f = strchr(h + 1, ' '))) goto bad_format; *w++ = *h++ = *f++ = '\0'; @@ -89,6 +86,8 @@ eninit_stream(int status, struct stream *stream) enset_pixel_size(status, stream); + stream->xptr = 0; + return; bad_format: enprintf(status, "%s: file format not supported\n", stream->file); @@ -181,19 +180,29 @@ enread_frame(int status, struct stream *stream, void *buf, size_t n) { char *buffer = buf; ssize_t r; - for (; stream->ptr < n; stream->ptr += (size_t)r) { - r = read(stream->fd, buffer + stream->ptr, n - stream->ptr); + size_t m; + + if (stream->ptr) { + m = stream->ptr < n ? stream->ptr : n; + memcpy(buffer + stream->xptr, stream->buf, m); + memmove(stream->buf, stream->buf + m, stream->ptr -= m); + stream->xptr += m; + } + + for (; stream->xptr < n; stream->xptr += (size_t)r) { + r = read(stream->fd, buffer + stream->xptr, n - stream->xptr); if (r < 0) { enprintf(status, "read %s:", stream->file); } else if (r == 0) { - if (!stream->ptr) + if (!stream->xptr) break; enprintf(status, "%s: incomplete frame", stream->file); } } - if (!stream->ptr) + + if (!stream->xptr) return 0; - stream->ptr -= n; + stream->xptr -= n; return 1; } diff --git a/src/stream.h b/src/stream.h @@ -36,8 +36,7 @@ #define process_multiple_streams(...) nprocess_multiple_streams(1, __VA_ARGS__) #define process_each_frame_two_streams(...) nprocess_each_frame_two_streams(1, __VA_ARGS__) -struct stream -{ +struct stream { size_t frames; size_t width; size_t height; @@ -45,7 +44,8 @@ struct stream char pixfmt[32]; int fd; size_t ptr; - char buf[4096]; + size_t xptr; + char buf[BUFSIZ]; const char *file; size_t headlen; }; @@ -62,13 +62,13 @@ void encheck_compat(int status, const struct stream *a, const struct stream *b); int enread_frame(int status, struct stream *stream, void *buf, size_t n); void nprocess_each_frame_segmented(int status, struct stream *stream, int output_fd, const char* output_fname, - void (*process)(struct stream *stream, size_t n, size_t frame)); + void (*process)(struct stream *stream, size_t n, size_t frame)); void nprocess_two_streams(int status, struct stream *left, struct stream *right, int output_fd, const char* output_fname, - void (*process)(struct stream *left, struct stream *right, size_t n)); + void (*process)(struct stream *left, struct stream *right, size_t n)); void nprocess_multiple_streams(int status, struct stream *streams, size_t n_streams, int output_fd, const char* output_fname, - void (*process)(struct stream *streams, size_t n_streams, size_t n)); + void (*process)(struct stream *streams, size_t n_streams, size_t n)); void nprocess_each_frame_two_streams(int status, struct stream *left, struct stream *right, int output_fd, const char* output_fname, void (*process)(char *restrict output, char *restrict lbuf, char *restrict rbuf,