blind-repeat: add -f and fix reading from file bug - blind - suckless command-line video editing utility
 (HTM) git clone git://git.suckless.org/blind
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 3e0822a8a5127a5ba395bc506622af73d75af0ab
 (DIR) parent bbd8ee77641288bb9051c99bc90d294ec1baa7cb
 (HTM) Author: Mattias Andrée <maandree@kth.se>
       Date:   Sat,  3 Jun 2017 18:38:37 +0200
       
       blind-repeat: add -f and fix reading from file bug
       
       Signed-off-by: Mattias Andrée <maandree@kth.se>
       
       Diffstat:
         M TODO                                |       2 --
         M man/blind-repeat.1                  |      16 +++++++++++++++-
         M src/blind-repeat.c                  |      59 +++++++++++++++++++++++++++----
       
       3 files changed, 68 insertions(+), 9 deletions(-)
       ---
 (DIR) diff --git a/TODO b/TODO
       @@ -56,8 +56,6 @@ bug: blind-stack: cannot use file outside /dev/fd/
        
        Add [-j jobs] to blind-from-video and blind-to-video.
        
       -Add -f (framewise) to blind-repeat
       -
        Generate a header file with the appropriate values for USING_BINARY32, USING_BINARY64.
        long double is slightly faster than long.
        long double (xyza q) could be added as another format.
 (DIR) diff --git a/man/blind-repeat.1 b/man/blind-repeat.1
       @@ -3,7 +3,8 @@
        blind-repeat - Repeat a video
        .SH SYNOPSIS
        .B blind-repeat
       -.RI ( count
       +([-f]
       +.I count
        |
        .RB ' inf ')
        .I file
       @@ -33,12 +34,25 @@ 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 OPTIONS
       +.TP
       +.B -f
       +Repeat each frames
       +.B count
       +times before copying the next frame, rather than
       +copying the entire video
       +.B count
       +times.
        .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.
       +However, if
       +.B -f
       +is used, only a full video frame will be loaded into
       +memory rather than an entire video, if reading from stdin.
        .SH SEE ALSO
        .BR blind (7),
        .BR blind-from-image (1)
 (DIR) diff --git a/src/blind-repeat.c b/src/blind-repeat.c
       @@ -1,7 +1,7 @@
        /* See LICENSE file for copyright and license details. */
        #include "common.h"
        
       -USAGE("(count | 'inf') file")
       +USAGE("([-f] count | 'inf') file")
        
        static size_t count = 0;
        static int inf;
       @@ -10,6 +10,7 @@ static struct stream stream;
        static int
        repeat_regular_file(void)
        {
       +        stream.ptr = 0;
                while (inf || count--) {
                        fadvise_sequential(stream.fd, (off_t)(stream.headlen), 0);
                        elseek(stream.fd, (off_t)(stream.headlen), SEEK_SET, stream.file);
       @@ -20,6 +21,22 @@ repeat_regular_file(void)
        }
        
        static int
       +repeat_regular_file_framewise(void)
       +{
       +        size_t i;
       +        off_t off = (off_t)(stream.headlen);
       +        stream.ptr = 0;
       +        echeck_dimensions(&stream, WIDTH | HEIGHT | LENGTH, "input");
       +        for (;; off += (off_t)(stream.frame_size)) {
       +                for (i = 0; i < count; i++) {
       +                        elseek(stream.fd, off, SEEK_SET, stream.file);
       +                        if (!esend_frames(&stream, STDOUT_FILENO, 1, "<stdout>"))
       +                                return 0;
       +                }
       +        }
       +}
       +
       +static int
        repeat_stdin(void)
        {
                size_t ptr = stream.ptr;
       @@ -32,24 +49,54 @@ repeat_stdin(void)
                return free(buf), 0;
        }
        
       +static int
       +repeat_stdin_framewise(void)
       +{
       +        char *buf;
       +        size_t i;
       +        echeck_dimensions(&stream, WIDTH | HEIGHT, "input");
       +        buf = emalloc(stream.frame_size);
       +        while (eread_frame(&stream, buf))
       +                for (i = 0; i < count; i++)
       +                        if (writeall(STDOUT_FILENO, buf, stream.frame_size))
       +                                return free(buf), -1;
       +        return free(buf), 0;
       +}
       +
        int
        main(int argc, char *argv[])
        {
       -        UNOFLAGS(argc != 2);
       +        int framewise = 0;
        
       -        if ((inf = !strcmp(argv[0], "inf")))
       +        ARGBEGIN {
       +        case 'f':
       +                framewise = 1;
       +                break;
       +        default:
       +                usage();
       +        } ARGEND;
       +
       +        if (argc != 2)
       +                usage();
       +
       +        if ((inf = !strcmp(argv[0], "inf"))) {
       +                if (framewise)
       +                        usage();
                        einf_check_fd(STDOUT_FILENO, "<stdout>");
       -        else
       +        } else {
                        count = etozu_arg("the count", argv[0], 0, SIZE_MAX);
       +        }
        
                eopen_stream(&stream, !strcmp(argv[1], "-") ? NULL : argv[1]);
       -        if (count > SIZE_MAX / stream.frames)
       +        if (stream.frames && count > SIZE_MAX / stream.frames)
                        eprintf("%s: video is too long\n", stream.file);
                stream.frames *= count;
                fprint_stream_head(stdout, &stream);
                efflush(stdout, "<stdout>");
        
       -        if (!strcmp(argv[1], "-") ? repeat_stdin() : repeat_regular_file())
       +        if (!strcmp(argv[1], "-")
       +            ? (framewise ? repeat_stdin_framewise()       : repeat_stdin())
       +            : (framewise ? repeat_regular_file_framewise(): repeat_regular_file()))
                        if (!inf || errno != EPIPE)
                                eprintf("write <stdout>:");