commit 3e0822a8a5127a5ba395bc506622af73d75af0ab
parent bbd8ee77641288bb9051c99bc90d294ec1baa7cb
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:
3 files changed, 68 insertions(+), 9 deletions(-)
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.
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)
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>:");