aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2017-12-07 23:48:45 +0100
committerMattias Andrée <maandree@kth.se>2017-12-07 23:48:45 +0100
commit4d7c506a29a5153a2b6ab903d2f4731bbab6abcb (patch)
tree67bdf5fa8d517cd9fc137f45567f4e312a0f4fc9
parentblind-peek-head: fix minor compile-time bug (diff)
downloadblind-4d7c506a29a5153a2b6ab903d2f4731bbab6abcb.tar.gz
blind-4d7c506a29a5153a2b6ab903d2f4731bbab6abcb.tar.bz2
blind-4d7c506a29a5153a2b6ab903d2f4731bbab6abcb.tar.xz
Start on libblind
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r--Makefile12
-rw-r--r--blind.mk30
-rw-r--r--src/blind-colour-matrix.c2
-rw-r--r--src/blind-concat.c4
-rw-r--r--src/blind-convert.c4
-rw-r--r--src/blind-coordinate-field.c2
-rw-r--r--src/blind-from-video.c4
-rw-r--r--src/blind-hexagon-tessellation.c2
-rw-r--r--src/blind-next-frame.c2
-rw-r--r--src/blind-peek-head.c2
-rw-r--r--src/blind-read-head.c2
-rw-r--r--src/blind-rectangle-tessellation.c2
-rw-r--r--src/blind-rewrite-head.c4
-rw-r--r--src/blind-single-colour.c2
-rw-r--r--src/blind-triangle-tessellation.c2
-rw-r--r--src/common.h2
-rw-r--r--src/libblind.c504
-rw-r--r--src/libblind.h190
-rw-r--r--src/stream.c446
-rw-r--r--src/stream.h69
20 files changed, 792 insertions, 495 deletions
diff --git a/Makefile b/Makefile
index 8d611c5..e2f12c4 100644
--- a/Makefile
+++ b/Makefile
@@ -13,13 +13,15 @@ KSH_SCRIPTS =\
blind-primary-key
COMMON_OBJ =\
- util.o\
- stream.o
+ libblind.o\
+ stream.o\
+ util.o
HDR =\
arg.h\
common.h\
define-functions.h\
+ libblind.h\
stream.h\
util.h\
util/to.h\
@@ -39,7 +41,6 @@ MISCFILES =\
Makefile\
config.mk\
blind.mk\
- rules.mk\
LICENSE\
README\
TODO\
@@ -75,6 +76,10 @@ build/files.mk: files.mk
printf '\n\nMAN =' && \
printf '\\\n\tman1/%s.1' $(BIN) $(SH_SCRIPTS) $(KSH_SCRIPTS) && \
printf '\\\n\tman7/%s.7' $(MAN7) && \
+ printf '\n\nMAN1 =' && \
+ printf '\\\n\t%s.1' $(BIN) $(SH_SCRIPTS) $(KSH_SCRIPTS) && \
+ printf '\n\nMAN7 =' && \
+ printf '\\\n\t%s.7' $(MAN7) && \
printf '\n' \
) > $@.$$$$ && mv $@.$$$$ $@
@@ -96,3 +101,4 @@ clean:
@make -f blind.mk $@
.PHONY: all clean
+.PRECIOUS: build/files.mk build/common-files.mk
diff --git a/blind.mk b/blind.mk
index ac30c20..1e5de6a 100644
--- a/blind.mk
+++ b/blind.mk
@@ -3,41 +3,37 @@
CONFIGFILE = config.mk
SCRIPTS = $(SH_SCRIPTS) $(KSH_SCRIPTS)
-MAN1 = $(BIN:=.1) $(SCRIPTS:=.1)
-MAN7 = blind.7
BOBJ = $(BIN:=.bo)
OBJ = $(BIN:=.o) $(COMMON_OBJ)
+C_DEPS = $(HDR) build/platform.h
DIST_MAN = $(MAN1) $(MAN7)
DIST_MISC = $(HDR) $(SRC) $(SCRIPTS) $(MISCFILES) $(EXAMPLEFILES)
-DEPS = build/common-files.mk blind.mk $(CONFIGFILE)
-MCB_DEPS = build/files.mk $(DEPS)
-
-include $(CONFIGFILE)
include build/files.mk
include build/common-files.mk
+include $(CONFIGFILE)
all: $(BIN)
mcb: blind-mcb
-$(BIN): $(@:=.o) $(COMMON_OBJ) $(DEPS)
+$(BIN): $(@:=.o) $(COMMON_OBJ)
.o:
$(CC) -o $@ $< $(COMMON_OBJ) $(LDFLAGS)
+ -@rm $@.o
-$(OBJ): src/$(@:.o=:c) $(HDR) build/platform.h $(DEPS)
+$(OBJ): src/$(@:.o=:c) $(C_DEPS)
$(OBJ):
$(CC) $(CFLAGS) -c -o $$$$.$@ src/$*.c && mv $$$$.$@ $@
-build/blind-mcb.o: $(MCB_DEPS)
.c.o:
$(CC) $(CFLAGS) -c -o $@ $<
-$(BOBJ): src/$(@:.bo=:c) $(HDR) build/platform.h $(DEPS)
+$(BOBJ): src/$(@:.bo=:c) $(C_DEPS)
$(BOBJ):
$(CC) $(CFLAGS) -Dmain="$$(printf 'main_%s\n' $* | tr -- - _)" -c -o $@ src/$*.c
-build/blind-mcb.c: $(MCB_DEPS)
+build/blind-mcb.c: build/files.mk
mkdir -p $(@D)
printf '#include <%s.h>\n' stdio string > $@
printf 'int main_%s(int argc, char *argv[]);\n' $(BIN) | tr -- - _ >> $@
@@ -52,15 +48,15 @@ build/blind-mcb.c: $(MCB_DEPS)
printf 'return 1;\n' >> $@
printf '}\n' >> $@
-blind-mcb: build/blind-mcb.o $(BOBJ) $(COMMON_OBJ) $(MCB_DEPS)
+blind-mcb: build/blind-mcb.o $(BOBJ) $(COMMON_OBJ)
$(CC) -o $@ build/blind-mcb.o $(BOBJ) $(COMMON_OBJ) $(LDFLAGS)
-build/generate-macros: src/generate-macros.c $(DEPS)
+build/generate-macros: src/generate-macros.c
@mkdir -p -- $(@D)
$(CC) $(CFLAGS) -o $@.$$$$ src/generate-macros.c $(LDFLAGS) && mv $@.$$$$ $@
src/../build/platform.h: build/platform.h
-build/platform.h: build/generate-macros $(DEPS)
+build/platform.h: build/generate-macros
@mkdir -p -- $(@D)
build/generate-macros > $@.$$$$ && mv $@.$$$$ $@
@@ -89,8 +85,8 @@ install-common:
cd -- "$(DESTDIR)$(MANPREFIX)" && chmod 644 $(MAN)
uninstall:
- cd -- "$(DESTDIR)$(PREFIX)/bin" && rm -f $(BIN) $(SCRIPTS)
- cd -- "$(DESTDIR)$(MANPREFIX)" && rm -f $(MAN)
+ cd -- "$(DESTDIR)$(PREFIX)/bin" && rm -f -- $(BIN) $(SCRIPTS)
+ cd -- "$(DESTDIR)$(MANPREFIX)" && rm -f -- $(MAN)
dist:
-rm -rf "blind-$(VERSION)"
@@ -106,4 +102,4 @@ dist:
.SUFFIXES: .o .bo .c
.PHONY: all mcb install install-mcb install-common uninstall dist
-.PRECIOUS: $(COMMON_OBJ) build/platform.h
+.PRECIOUS: $(COMMON_OBJ) $(BOBJ) build/platform.h
diff --git a/src/blind-colour-matrix.c b/src/blind-colour-matrix.c
index 01d3f27..8cf3ac1 100644
--- a/src/blind-colour-matrix.c
+++ b/src/blind-colour-matrix.c
@@ -111,7 +111,7 @@ main(int argc, char *argv[])
invert(M);
- eset_pixel_format(&stream, pixfmt);
+ eset_pixfmt(&stream, pixfmt);
fprint_stream_head(stdout, &stream);
efflush(stdout, "<stdout>");
diff --git a/src/blind-concat.c b/src/blind-concat.c
index a5d40ca..5242d0d 100644
--- a/src/blind-concat.c
+++ b/src/blind-concat.c
@@ -39,7 +39,7 @@ concat_to_file(int argc, char *argv[], char *output_file)
struct stream stream, refstream;
int first = 1;
int fd = eopen(output_file, O_RDWR | O_CREAT | O_TRUNC, 0666);
- char head[STREAM_HEAD_MAX];
+ char head[LIBBLIND_HEAD_MAX];
ssize_t headlen;
size_t size;
off_t pos;
@@ -91,7 +91,7 @@ concat_to_file_parallel(int argc, char *argv[], char *output_file, size_t jobs)
struct epoll_event *events;
struct stream *streams;
off_t *ptrs, ptr;
- char head[STREAM_HEAD_MAX];
+ char head[LIBBLIND_HEAD_MAX];
size_t frames = 0, next = 0, j;
ssize_t headlen;
int fd, i, n, pollfd;
diff --git a/src/blind-convert.c b/src/blind-convert.c
index a61baba..93977c0 100644
--- a/src/blind-convert.c
+++ b/src/blind-convert.c
@@ -337,9 +337,9 @@ main(int argc, char *argv[])
memcpy(&out, &stream, sizeof(out));
pixfmt = stream.pixfmt;
while (*argv)
- pixfmt = get_pixel_format(*argv++, pixfmt);
+ pixfmt = get_pixfmt(*argv++, pixfmt);
strcpy(out.pixfmt, pixfmt);
- if (set_pixel_format(&out, NULL))
+ if (set_pixfmt(&out, NULL))
eprintf("output pixel format %s is not supported\n", pixfmt);
fprint_stream_head(stdout, &out);
diff --git a/src/blind-coordinate-field.c b/src/blind-coordinate-field.c
index 1c87876..a09030b 100644
--- a/src/blind-coordinate-field.c
+++ b/src/blind-coordinate-field.c
@@ -44,7 +44,7 @@ main(int argc, char *argv[])
if (inf)
einf_check_fd(STDOUT_FILENO, "<stdout>");
- eset_pixel_format(&stream, pixfmt);
+ eset_pixfmt(&stream, pixfmt);
SELECT_PROCESS_FUNCTION(&stream);
CHECK_N_CHAN(&stream, 4, 4);
diff --git a/src/blind-from-video.c b/src/blind-from-video.c
index 3041ea1..cacb2fb 100644
--- a/src/blind-from-video.c
+++ b/src/blind-from-video.c
@@ -180,7 +180,7 @@ int
main(int argc, char *argv[])
{
size_t width = 0, height = 0, frames;
- char head[STREAM_HEAD_MAX];
+ char head[LIBBLIND_HEAD_MAX];
char *frame_rate = NULL;
char *infile;
const char *outfile;
@@ -220,7 +220,7 @@ main(int argc, char *argv[])
infile = argv[0];
outfile = argv[1] ? argv[1] : "-";
- pixfmt = get_pixel_format(pixfmt, "xyza");
+ pixfmt = get_pixfmt(pixfmt, "xyza");
if (!strcmp(pixfmt, "xyza")) {
convert_segment = convert_segment_xyza;
pixel_size = 4 * sizeof(double);
diff --git a/src/blind-hexagon-tessellation.c b/src/blind-hexagon-tessellation.c
index 377c110..4d245c2 100644
--- a/src/blind-hexagon-tessellation.c
+++ b/src/blind-hexagon-tessellation.c
@@ -46,7 +46,7 @@ main(int argc, char *argv[])
diameter = etozu_arg("block-diameter", argv[0], 1, SIZE_MAX);
- eset_pixel_format(&stream, pixfmt);
+ eset_pixfmt(&stream, pixfmt);
CHECK_N_CHAN(&stream, 4, 4);
if (stream.encoding == DOUBLE)
SET_XYZA(double);
diff --git a/src/blind-next-frame.c b/src/blind-next-frame.c
index 1d33c46..d3f43a1 100644
--- a/src/blind-next-frame.c
+++ b/src/blind-next-frame.c
@@ -37,7 +37,7 @@ main(int argc, char *argv[])
p = stpcpy(p, argv[i]);
}
}
- enset_pixel_format(2, &stream, NULL);
+ enset_pixfmt(2, &stream, NULL);
fprint_stream_head(stdout, &stream);
enfflush(2, stdout, "<stdout>");
diff --git a/src/blind-peek-head.c b/src/blind-peek-head.c
index d33776b..0fe3394 100644
--- a/src/blind-peek-head.c
+++ b/src/blind-peek-head.c
@@ -80,7 +80,7 @@ peek(char *buf, size_t n)
int
main(int argc, char *argv[])
{
- char buf[STREAM_HEAD_MAX], *p;
+ char buf[LIBBLIND_HEAD_MAX], *p;
char magic[] = {'\0', 'u', 'i', 'v', 'f'};
size_t i, len = 0, last_len;
#if defined(HAVE_EPOLL)
diff --git a/src/blind-read-head.c b/src/blind-read-head.c
index 7258e19..21b4af7 100644
--- a/src/blind-read-head.c
+++ b/src/blind-read-head.c
@@ -6,7 +6,7 @@ USAGE("")
int
main(int argc, char *argv[])
{
- char buf[STREAM_HEAD_MAX];
+ char buf[LIBBLIND_HEAD_MAX];
char magic[] = {'\0', 'u', 'i', 'v', 'f'};
char b, *p;
size_t i, ptr;
diff --git a/src/blind-rectangle-tessellation.c b/src/blind-rectangle-tessellation.c
index 7ffcb49..371e6b7 100644
--- a/src/blind-rectangle-tessellation.c
+++ b/src/blind-rectangle-tessellation.c
@@ -46,7 +46,7 @@ main(int argc, char *argv[])
width = etozu_arg("block-width", argv[0], 1, SIZE_MAX);
height = etozu_arg("block-height", argv[1], 1, SIZE_MAX);
- eset_pixel_format(&stream, pixfmt);
+ eset_pixfmt(&stream, pixfmt);
CHECK_N_CHAN(&stream, 4, 4);
if (stream.encoding == DOUBLE)
SET_XYZA(double);
diff --git a/src/blind-rewrite-head.c b/src/blind-rewrite-head.c
index aad19e4..0b87df9 100644
--- a/src/blind-rewrite-head.c
+++ b/src/blind-rewrite-head.c
@@ -6,7 +6,7 @@ USAGE("[-h] file [(frames | 'auto') [(width | 'same') (height | 'same') [format
static void
rewrite(struct stream *stream, int frames_auto)
{
- char head[STREAM_HEAD_MAX];
+ char head[LIBBLIND_HEAD_MAX];
ssize_t headlen;
size_t frame_count, length;
struct stat st;
@@ -99,7 +99,7 @@ main(int argc, char *argv[])
else if (strcmp(argv[4], "same")) {
if (strlen(argv[4]) >= sizeof(stream.pixfmt))
eprintf("choosen pixel format is unsupported\n");
- if (set_pixel_format(&stream, argv[5]))
+ if (set_pixfmt(&stream, argv[5]))
eprintf("choosen pixel format is unsupported\n");
} else if (headless) {
eprintf("cannot use both 'same' and -h\n");
diff --git a/src/blind-single-colour.c b/src/blind-single-colour.c
index 92a8289..c1f529b 100644
--- a/src/blind-single-colour.c
+++ b/src/blind-single-colour.c
@@ -57,7 +57,7 @@ main(int argc, char *argv[])
if (inf)
einf_check_fd(STDOUT_FILENO, "<stdout>");
- eset_pixel_format(&stream, pixfmt);
+ eset_pixfmt(&stream, pixfmt);
SELECT_PROCESS_FUNCTION(&stream);
CHECK_N_CHAN(&stream, 4, 4);
if (argc < 3)
diff --git a/src/blind-triangle-tessellation.c b/src/blind-triangle-tessellation.c
index f806527..2564519 100644
--- a/src/blind-triangle-tessellation.c
+++ b/src/blind-triangle-tessellation.c
@@ -62,7 +62,7 @@ main(int argc, char *argv[])
width = etozu_arg("block-width", argv[0], 1, SIZE_MAX);
height = etozu_arg("block-height", argv[1], 1, SIZE_MAX);
- eset_pixel_format(&stream, pixfmt);
+ eset_pixfmt(&stream, pixfmt);
CHECK_N_CHAN(&stream, 4, 4);
if (stream.encoding == DOUBLE)
SET_XYZA(double);
diff --git a/src/common.h b/src/common.h
index a06bc16..7a2c82f 100644
--- a/src/common.h
+++ b/src/common.h
@@ -65,7 +65,7 @@
# define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
#endif
-#if !defined(PIPE_BUF)
+#ifndef PIPE_BUF
# define PIPE_BUF 512
#endif
diff --git a/src/libblind.c b/src/libblind.c
new file mode 100644
index 0000000..436c433
--- /dev/null
+++ b/src/libblind.c
@@ -0,0 +1,504 @@
+#define LIBBLIND_NO_NAMESPACE
+#include "libblind.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+
+extern int writeall(int fd, const void *buf, size_t n);
+
+
+
+#if defined(POSIX_FADV_SEQUENTIAL)
+# define fadvise_sequential(...) posix_fadvise(__VA_ARGS__, POSIX_FADV_SEQUENTIAL)
+#else
+# define fadvise_sequential(...)
+#endif
+
+
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+#define ELEMSOF(A) (sizeof(A) / sizeof(*(A)))
+
+
+#define X(NUM, NAM, STR) ,STR
+static const char *error_names[] = {
+ "Success", NULL
+ LIBBLIND_LIST_ERRORS(X)
+};
+#undef X
+
+
+const char *
+libblind_strerror(int errnum)
+{
+ const char *ret;
+ errnum = -errnum;
+ if (errnum < 0 || errnum >= ELEMSOF(error_names))
+ return "Unknown libblind error";
+ ret = error_names[errnum];
+ return ret ? ret : strerror(errno);
+}
+
+
+void
+libblind_perror(const char *prefix, int errnum)
+{
+ fprintf(stderr, "%s%s%s\n",
+ prefix ? prefix : "",
+ prefix ? ": " : "",
+ libblind_strerror(errnum));
+}
+
+
+const char *
+libblind_get_pixfmt(const char *specified, const char *current)
+{
+ enum colour_space space = CIEXYZ;
+ enum alpha alpha = UNPREMULTIPLIED;
+ enum encoding encoding = UINT16;
+ int level = -1;
+ size_t n = strlen(specified);
+
+ if ((n >= 2 && !strcmp(specified - 2, " f")) ||
+ !strcmp(specified, "raw0") || !strcmp(specified, "raw1") ||
+ !strcmp(specified, "raw2") || !strcmp(specified, "raw2a"))
+ return specified;
+
+ if (!strcmp(current, "xyza")) space = CIEXYZ, encoding = DOUBLE;
+ else if (!strcmp(current, "xyza f")) space = CIEXYZ, encoding = FLOAT;
+ else if (!strcmp(current, "raw0")) level = 0;
+ else if (!strcmp(current, "raw1")) level = 1;
+ else if (!strcmp(current, "raw2")) level = 2, alpha = NO_ALPHA;
+ else if (!strcmp(current, "raw2a")) level = 2;
+ else if (!strcmp(current, "raw3")) level = 3, encoding = DOUBLE, alpha = NO_ALPHA;
+ else if (!strcmp(current, "raw3a")) level = 3, encoding = DOUBLE;
+ else if (!strcmp(current, "raw3 f")) level = 3, encoding = FLOAT, alpha = NO_ALPHA;
+ else if (!strcmp(current, "raw3a f")) level = 3, encoding = FLOAT;
+ else if (!strcmp(current, "raw4")) level = 4, encoding = DOUBLE, alpha = NO_ALPHA;
+ else if (!strcmp(current, "raw4a")) level = 4, encoding = DOUBLE;
+ else if (!strcmp(current, "raw4 f")) level = 4, encoding = FLOAT, alpha = NO_ALPHA;
+ else if (!strcmp(current, "raw4a f")) level = 4, encoding = FLOAT;
+ else if (!strcmp(current, "raw5")) level = 5, encoding = DOUBLE, alpha = NO_ALPHA;
+ else if (!strcmp(current, "raw5a")) level = 5, encoding = DOUBLE;
+ else if (!strcmp(current, "raw5 f")) level = 5, encoding = FLOAT, alpha = NO_ALPHA;
+ else if (!strcmp(current, "raw5a f")) level = 5, encoding = FLOAT;
+ else
+ return specified;
+
+ if (!strcmp(specified, "f")) encoding = FLOAT;
+ else if (!strcmp(specified, "!f")) encoding = DOUBLE;
+ else if (!strcmp(specified, "xyza")) level = -1, alpha = UNPREMULTIPLIED, space = CIEXYZ;
+ else if (!strcmp(specified, "raw3")) level = 3, alpha = NO_ALPHA;
+ else if (!strcmp(specified, "raw3a")) level = 3, alpha = UNPREMULTIPLIED;
+ else if (!strcmp(specified, "raw4")) level = 4, alpha = NO_ALPHA;
+ else if (!strcmp(specified, "raw4a")) level = 4, alpha = UNPREMULTIPLIED;
+ else if (!strcmp(specified, "raw5")) level = 5, alpha = NO_ALPHA;
+ else if (!strcmp(specified, "raw5a")) level = 5, alpha = UNPREMULTIPLIED;
+ else if (!strcmp(specified, "xyza !f")) return "xyza";
+ else if (!strcmp(specified, "raw3 !f")) return "raw3";
+ else if (!strcmp(specified, "raw3a !f")) return "raw3a";
+ else if (!strcmp(specified, "raw4 !f")) return "raw4";
+ else if (!strcmp(specified, "raw4a !f")) return "raw4a";
+ else if (!strcmp(specified, "raw5 !f")) return "raw5";
+ else if (!strcmp(specified, "raw5a !f")) return "raw5a";
+ else
+ return specified;
+
+ if (level == 0 && encoding == UINT16) return "raw0";
+ else if (level == 1 && encoding == UINT16) return "raw1";
+ else if (level == 2 && encoding == UINT16) return alpha ? "raw2a" : "raw2";
+ else if (level == 3 && encoding == DOUBLE) return alpha ? "raw3a" : "raw3";
+ else if (level == 3 && encoding == FLOAT) return alpha ? "raw3a f" : "raw3 f";
+ else if (level == 4 && encoding == DOUBLE) return alpha ? "raw4a" : "raw4";
+ else if (level == 4 && encoding == FLOAT) return alpha ? "raw4a f" : "raw4 f";
+ else if (level == 5 && encoding == DOUBLE) return alpha ? "raw5a" : "raw5";
+ else if (level == 5 && encoding == FLOAT) return alpha ? "raw5a f" : "raw5 f";
+ else if (level < 0 && space == CIEXYZ && alpha == UNPREMULTIPLIED)
+ return encoding == FLOAT ? "xyza f" : encoding == DOUBLE ? "xyza" : specified;
+ else
+ return specified;
+}
+
+
+int
+libblind_set_pixfmt(struct libblind_stream *stream, const char *pixfmt)
+{
+#define TEST_ENCODING_AGNOSTIC(FMT) (!strcmp(stream->pixfmt, FMT) || !strcmp(stream->pixfmt, FMT" f"))
+
+ if (pixfmt) {
+ pixfmt = get_pixfmt(pixfmt, stream->pixfmt[0] ? stream->pixfmt : "xyza");
+ if (strlen(pixfmt) >= sizeof(stream->pixfmt))
+ return LIBBLIND_EPIXFMTNOSUPPORT;
+ strcpy(stream->pixfmt, pixfmt);
+ }
+
+ stream->n_chan = 4;
+ stream->alpha = UNPREMULTIPLIED;
+ stream->encoding = DOUBLE;
+ stream->endian = HOST;
+ stream->alpha_chan = 3;
+ stream->luma_chan = -1;
+
+ if (!strcmp(stream->pixfmt, "xyza")) {
+ stream->space = CIEXYZ;
+ } else if (!strcmp(stream->pixfmt, "xyza f")) {
+ stream->space = CIEXYZ;
+ stream->encoding = FLOAT;
+ } else if (!strcmp(stream->pixfmt, "raw0")) {
+ stream->space = YUV_NONLINEAR;
+ stream->encoding = UINT16;
+ stream->endian = LITTLE;
+ stream->alpha_chan = 0;
+ stream->luma_chan = 1;
+ } else if (!strcmp(stream->pixfmt, "raw1")) {
+ stream->space = YUV_NONLINEAR;
+ stream->encoding = UINT16;
+ stream->endian = LITTLE;
+ } else if (!strcmp(stream->pixfmt, "raw2a") || !strcmp(stream->pixfmt, "raw2")) {
+ stream->space = YUV_NONLINEAR;
+ stream->alpha = stream->pixfmt[4] == 'a' ? UNPREMULTIPLIED : NO_ALPHA;
+ stream->encoding = UINT16;
+ } else if (TEST_ENCODING_AGNOSTIC("raw3") || TEST_ENCODING_AGNOSTIC("raw3a")) {
+ stream->space = YUV_NONLINEAR;
+ stream->alpha = stream->pixfmt[4] == 'a' ? UNPREMULTIPLIED : NO_ALPHA;
+ stream->encoding = strlen(stream->pixfmt) > 5 ? FLOAT : DOUBLE;
+ } else if (TEST_ENCODING_AGNOSTIC("raw4") || TEST_ENCODING_AGNOSTIC("raw4a")) {
+ stream->space = SRGB_NONLINEAR;
+ stream->alpha = stream->pixfmt[4] == 'a' ? UNPREMULTIPLIED : NO_ALPHA;
+ stream->encoding = strlen(stream->pixfmt) > 5 ? FLOAT : DOUBLE;
+ } else if (TEST_ENCODING_AGNOSTIC("raw5") || TEST_ENCODING_AGNOSTIC("raw5a")) {
+ stream->space = SRGB;
+ stream->alpha = stream->pixfmt[4] == 'a' ? UNPREMULTIPLIED : NO_ALPHA;
+ stream->encoding = strlen(stream->pixfmt) > 5 ? FLOAT : DOUBLE;
+ } else {
+ return LIBBLIND_EPIXFMTNOSUPPORT;
+ }
+
+ if (stream->alpha == NO_ALPHA) {
+ stream->n_chan -= 1;
+ stream->alpha_chan = -1;
+ }
+
+ if (stream->luma_chan == -1) {
+ if (stream->space == CIEXYZ)
+ stream->luma_chan = 1;
+ else if (stream->space == YUV_NONLINEAR)
+ stream->luma_chan = 0;
+ }
+
+ switch (stream->encoding) {
+ case FLOAT:
+ stream->chan_size = sizeof(float);
+ break;
+ case DOUBLE:
+ stream->chan_size = sizeof(double);
+ break;
+ case LONG_DOUBLE:
+ stream->chan_size = sizeof(long double);
+ break;
+ case UINT8:
+ stream->chan_size = sizeof(uint8_t);
+ break;
+ case UINT16:
+ stream->chan_size = sizeof(uint16_t);
+ break;
+ case UINT32:
+ stream->chan_size = sizeof(uint32_t);
+ break;
+ case UINT64:
+ stream->chan_size = sizeof(uint64_t);
+ break;
+ default:
+ return LIBBLIND_ECORRUPTSTATE;
+ }
+
+ stream->pixel_size = stream->n_chan * stream->chan_size;
+ stream->row_size = stream->pixel_size * stream->width;
+ stream->col_size = stream->pixel_size * stream->height;
+ stream->frame_size = stream->pixel_size * stream->height * stream->width;
+ return 0;
+
+#undef TEST_ENCODING_AGNOSTIC
+}
+
+
+ssize_t
+libblind_read_stream(struct libblind_stream *stream, size_t n)
+{
+ ssize_t r;
+ n = MIN(n, sizeof(stream->buf) - stream->ptr);
+ r = read(stream->fd, &stream->buf[stream->ptr], n);
+ if (r > 0)
+ stream->ptr += (size_t)r;
+ return r;
+ /* LIBBLIND_ESYSTEM == -1 and read(3p) explicitly specifies -1 on error */
+}
+
+
+static inline int
+get_dimension(size_t *out, const char *s, int dimerr)
+{
+ char *end;
+ int saved_errno = errno;
+ errno = 0;
+ *out = strtoul(s, &end, 10);
+ if (errno == ERANGE && *s != '-')
+ return dimerr;
+ errno = saved_errno;
+ return LIBBLIND_EBADFORMAT;
+}
+
+
+int
+libblind_init_stream(struct libblind_stream *stream)
+{
+ char *p = NULL, *w, *h, *f;
+ size_t n;
+ ssize_t r;
+ int err;
+
+ if (stream->fd >= 0) {
+ fadvise_sequential(stream->fd, 0, 0);
+ for (stream->ptr = 0; !p; p = memchr(stream->buf, '\n', stream->ptr))
+ if ((r = libblind_read_stream(stream, SIZE_MAX)) <= 0)
+ return r ? r : LIBBLIND_EBADFORMAT;
+ } else {
+ p = memchr(stream->buf, '\n', stream->ptr);
+ }
+
+ *p = '\0';
+ if (!(w = strchr(stream->buf, ' ')) ||
+ !(h = strchr(&w[1], ' ')) ||
+ !(f = strchr(&h[1], ' ')))
+ return LIBBLIND_EBADFORMAT;
+ *w++ = *h++ = *f++ = '\0';
+
+ if (strlen(f) >= sizeof(stream->pixfmt))
+ return LIBBLIND_EBADFORMAT;
+ strcpy(stream->pixfmt, f);
+ if ((err = get_dimension(&stream->frames, stream->buf, LIBBLIND_EVIDTOOLONG)) ||
+ (err = get_dimension(&stream->width, w, LIBBLIND_EVIDTOOWIDE)) ||
+ (err = get_dimension(&stream->height, h, LIBBLIND_EVIDTOOTALL)))
+ return err;
+
+ if (!stream->width)
+ return LIBBLIND_EZEROWIDTH;
+ if (!stream->height)
+ return LIBBLIND_EZEROHEIGHT;
+
+ n = (size_t)(p - stream->buf) + 1;
+ memmove(stream->buf, &stream->buf[n], stream->ptr -= n);
+ while (stream->ptr < 5)
+ if ((r = libblind_read_stream(stream, SIZE_MAX)) <= 0)
+ return r ? r : LIBBLIND_EBADFORMAT;
+ if (stream->buf[0] != '\0' ||
+ stream->buf[1] != 'u' || stream->buf[2] != 'i' ||
+ stream->buf[3] != 'v' || stream->buf[4] != 'f')
+ return LIBBLIND_EBADFORMAT;
+ memmove(stream->buf, &stream->buf[5], stream->ptr -= 5);
+ stream->headlen = n + 5;
+
+ if ((err = libblind_set_pixfmt(stream, NULL)))
+ return err;
+
+ stream->xptr = 0;
+
+ return 0;
+}
+
+
+int
+libblind_check_dimensions(const struct stream *stream, enum dimension dimensions)
+{
+ size_t n;
+
+ if (!stream->pixel_size)
+ return LIBBLIND_ECORRUPTSTATE;
+ n = SIZE_MAX / stream->pixel_size;
+
+ if ((dimensions & WIDTH) && stream->width > n)
+ return LIBBLIND_EFRMTOOWIDE;
+ if ((dimensions & HEIGHT) && stream->height > n)
+ return LIBBLIND_EFRMTOOTALL;
+ if (!stream->width || !stream->height)
+ return 0;
+
+ if ((dimensions & (WIDTH | HEIGHT)) == (WIDTH | HEIGHT))
+ if (stream->width > n / stream->height)
+ return LIBBLIND_EFRMTOOLARGE;
+
+ if (!(dimensions & LENGTH))
+ return 0;
+ if (dimensions & WIDTH)
+ n /= stream->width;
+ if (dimensions & HEIGHT)
+ n /= stream->height;
+
+ if (stream->frames > n)
+ return LIBBLIND_EVIDTOOLARGE;
+
+ return 0;
+}
+
+
+int
+libblind_read_segment(struct stream *stream, void *buf, size_t n)
+{
+ char *buffer = buf;
+ ssize_t r;
+ size_t m;
+
+ if (stream->ptr) {
+ m = MIN(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)
+ return LIBBLIND_ESYSTEM;
+ if (!r) {
+ if (!stream->xptr)
+ break;
+ return LIBBLIND_EINCOMPLETE;
+ }
+ }
+
+ if (!stream->xptr)
+ return 0;
+ stream->xptr -= n;
+ return 1;
+}
+
+
+ssize_t
+libblind_send_frames(struct libblind_stream *stream, int outfd, size_t frames, int *outfailed)
+{
+ size_t h, w, p, n, ret;
+ ssize_t r;
+
+ for (ret = 0; ret < frames; ret++) {
+ for (p = stream->pixel_size; p; p--) {
+ for (h = stream->height; h; h--) {
+ for (w = stream->width; w; w -= n) {
+ if (!stream->ptr && (r = libblind_read_stream(stream, w)) <= 0) {
+ if (outfailed)
+ *outfailed = 0;
+ if (!r)
+ goto done;
+ return r;
+ }
+ n = MIN(stream->ptr, p);
+ if (outfd >= 0 && writeall(outfd, stream->buf, n)) {
+ if (outfailed)
+ *outfailed = 1;
+ return LIBBLIND_ESYSTEM;
+ }
+ memmove(stream->buf, &stream->buf[n], stream->ptr -= n);
+ }
+ }
+ }
+ }
+
+ return ret;
+done:
+ if (p != stream->pixel_size)
+ return (ssize_t)LIBBLIND_EINCOMPLETEFRAME;
+ /* Note that due to order of the nested for-loops, we don't
+ * know which unit is incomplete: pixel, row, or frame. */
+ return ret;
+}
+
+
+ssize_t
+libblind_send_rows(struct libblind_stream *stream, int outfd, size_t rows, int *outfailed)
+{
+ size_t w, p, n, ret;
+ ssize_t r;
+
+ for (ret = 0; ret < rows; ret++) {
+ for (p = stream->pixel_size; p; p--) {
+ for (w = stream->width; w; w -= n) {
+ if (!stream->ptr && (r = libblind_read_stream(stream, w)) <= 0) {
+ if (outfailed)
+ *outfailed = 0;
+ if (!r)
+ goto done;
+ return r;
+ }
+ n = MIN(stream->ptr, p);
+ if (outfd >= 0 && writeall(outfd, stream->buf, n)) {
+ if (outfailed)
+ *outfailed = 1;
+ return LIBBLIND_ESYSTEM;
+ }
+ memmove(stream->buf, &stream->buf[n], stream->ptr -= n);
+ }
+ }
+ }
+
+ return ret;
+done:
+ if (p != stream->pixel_size)
+ return (ssize_t)LIBBLIND_EINCOMPLETEROW;
+ /* Note that due to order of the nested for-loops, we don't
+ * know whether a pixel is incomplete or just a row. */
+ return ret;
+}
+
+
+ssize_t
+libblind_send_pixels(struct libblind_stream *stream, int outfd, size_t pixels, int *outfailed)
+{
+ size_t p, n, ret;
+ ssize_t r;
+
+ for (ret = 0; ret < pixels; ret++) {
+ for (p = stream->pixel_size; p; p -= n) {
+ if (!stream->ptr && (r = libblind_read_stream(stream, p)) <= 0) {
+ if (outfailed)
+ *outfailed = 0;
+ if (!r)
+ goto done;
+ return r;
+ }
+ n = MIN(stream->ptr, p);
+ if (outfd >= 0 && writeall(outfd, stream->buf, n)) {
+ if (outfailed)
+ *outfailed = 1;
+ return LIBBLIND_ESYSTEM;
+ }
+ memmove(stream->buf, &stream->buf[n], stream->ptr -= n);
+ }
+ }
+
+ return ret;
+done:
+ if (p != stream->pixel_size)
+ return (ssize_t)LIBBLIND_EINCOMPLETEPIX;
+ return ret;
+}
+
+
+int
+libblind_send_stream(struct libblind_stream *stream, int outfd, int *outfailed)
+{
+ ssize_t r;
+ do {
+ if (writeall(outfd, stream->buf, stream->ptr)) {
+ if (outfailed)
+ *outfailed = 1;
+ return LIBBLIND_ESYSTEM;
+ }
+ stream->ptr = 0;
+ } while ((r = libblind_read_stream(stream, SIZE_MAX)) > 0);
+ if (outfailed)
+ *outfailed = 0;
+ return -(r < 0);
+}
diff --git a/src/libblind.h b/src/libblind.h
new file mode 100644
index 0000000..e358dd9
--- /dev/null
+++ b/src/libblind.h
@@ -0,0 +1,190 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef LIBBLIND_H
+#define LIBBLIND_H
+
+
+#include <stdlib.h>
+
+
+#ifdef LIBBLIND_NO_NAMESPACE
+/* errors and error related functions are still namespaced */
+# define libblind_dimension dimension
+# define LIBBLIND_WIDTH WIDTH
+# define LIBBLIND_HEIGHT HEIGHT
+# define LIBBLIND_LENGTH LENGTH
+# define libblind_colour_space colour_space
+# define LIBBLIND_CIEXYZ CIEXYZ
+# define LIBBLIND_YUV_NONLINEAR YUV_NONLINEAR
+# define LIBBLIND_SRGB_NONLINEAR SRGB_NONLINEAR
+# define LIBBLIND_SRGB SRGB
+# define libblind_alpha alpha
+# define LIBBLIND_NO_ALPHA NO_ALPHA
+# define LIBBLIND_UNPREMULTIPLIED UNPREMULTIPLIED
+# define LIBBLIND_PREMULTIPLIED PREMULTIPLIED
+# define libblind_encoding encoding
+# define LIBBLIND_FLOAT FLOAT
+# define LIBBLIND_DOUBLE DOUBLE
+# define LIBBLIND_LONG_DOUBLE LONG_DOUBLE
+# define LIBBLIND_UINT8 UINT8
+# define LIBBLIND_UINT16 UINT16
+# define LIBBLIND_UINT32 UINT32
+# define LIBBLIND_UINT64 UINT64
+# define libblind_endian endian
+# define LIBBLIND_HOST HOST
+# define LIBBLIND_LITTLE LITTLE
+# define LIBBLIND_BIG BIG
+# define libblind_stream stream
+# define get_pixfmt libblind_get_pixfmt
+# define set_pixfmt libblind_set_pixfmt
+# define read_stream libblind_read_stream
+# define init_stream libblind_init_stream
+# define check_dimensions libblind_check_dimensions
+# define read_segment libblind_read_segment
+# define read_frame libblind_read_frame
+# define read_row libblind_read_row
+# define read_pixel libblind_read_pixel
+# define send_frames libblind_send_frames
+# define send_rows libblind_send_rows
+# define send_pixels libblind_send_pixels
+# define send_stream libblind_send_stream
+#endif
+
+
+#ifndef LIBBLIND_BUFSIZ
+# define LIBBLIND_BUFSIZ 8192
+#endif
+
+
+#define LIBBLIND_HEAD_MAX\
+ (((sizeof(size_t) == 1 ? 3 : (5 * sizeof(size_t) / 2)) + ((size_t)-1 < 1))\
+ * 3 + sizeof(((struct libblind_stream *)0)->pixfmt) + 10)
+
+
+enum libblind_dimension {
+ LIBBLIND_WIDTH = 1,
+ LIBBLIND_HEIGHT = 2,
+ LIBBLIND_LENGTH = 4
+};
+
+enum libblind_colour_space {
+ LIBBLIND_CIEXYZ,
+ LIBBLIND_YUV_NONLINEAR,
+ LIBBLIND_SRGB_NONLINEAR,
+ LIBBLIND_SRGB
+};
+
+enum libblind_alpha {
+ LIBBLIND_NO_ALPHA,
+ LIBBLIND_UNPREMULTIPLIED,
+ LIBBLIND_PREMULTIPLIED /* currently unused */
+};
+
+enum libblind_encoding {
+ LIBBLIND_FLOAT,
+ LIBBLIND_DOUBLE,
+ LIBBLIND_LONG_DOUBLE, /* currently unused */
+ LIBBLIND_UINT8, /* currently unused */
+ LIBBLIND_UINT16,
+ LIBBLIND_UINT32, /* currently unused */
+ LIBBLIND_UINT64 /* currently unused */
+};
+
+enum libblind_endian {
+ LIBBLIND_HOST,
+ LIBBLIND_LITTLE,
+ LIBBLIND_BIG /* currently unused */
+};
+
+struct libblind_stream {
+ size_t frames;
+ size_t width;
+ size_t height;
+ size_t n_chan;
+ size_t chan_size;
+ size_t pixel_size;
+ char pixfmt[32];
+ enum libblind_colour_space space;
+ enum libblind_alpha alpha;
+ enum libblind_encoding encoding;
+ enum libblind_endian endian;
+ short int alpha_chan;
+ short int luma_chan;
+ int fd;
+ size_t ptr;
+ size_t xptr;
+ char buf[LIBBLIND_BUFSIZ];
+ const char *file;
+ size_t headlen;
+ size_t row_size;
+ size_t col_size;
+ size_t frame_size;
+};
+
+
+#define LIBBLIND_LIST_ERRORS(_)\
+ _( -2, LIBBLIND_EVIDTOOLONG, "Video is too long")\
+ _( -3, LIBBLIND_EVIDTOOWIDE, "Video is too wide")\
+ _( -4, LIBBLIND_EVIDTOOTALL, "Video is too tall")\
+ _( -5, LIBBLIND_EVIDTOOLARGE, "Video is too large")\
+ _( -6, LIBBLIND_EFRMTOOWIDE, "Video frame is too wide")\
+ _( -7, LIBBLIND_EFRMTOOTALL, "Video frame is too tall")\
+ _( -8, LIBBLIND_EFRMTOOLARGE, "Video frame is too large")\
+ _( -9, LIBBLIND_EZEROWIDTH, "Video has zero width")\
+ _(-10, LIBBLIND_EZEROHEIGHT, "Video has zero height")\
+ _(-11, LIBBLIND_EBADFORMAT, "File format not supported")\
+ _(-12, LIBBLIND_EPIXFMTNOSUPPORT, "Pixel format not supported")\
+ _(-13, LIBBLIND_EGEOMDIFF, "Videos do not have the same geometries")\
+ _(-14, LIBBLIND_EGEOMNOCOMPAT, "Videos have incompatible geometries")\
+ _(-15, LIBBLIND_EPIXFMTDIFF, "Videos do not have the same pixel formats")\
+ _(-16, LIBBLIND_EPIXFMTNOCOMPAT, "Videos have incompatible pixel formats")\
+ _(-17, LIBBLIND_ECORRUPTSTATE, "State corrupted")\
+ _(-18, LIBBLIND_EINCOMPLETE, "Incomplete segment")\
+ _(-19, LIBBLIND_EINCOMPLETEFRAME, "Incomplete frame")\
+ _(-20, LIBBLIND_EINCOMPLETEROW, "Incomplete row")\
+ _(-21, LIBBLIND_EINCOMPLETEPIX, "Incomplete pixel")
+
+enum {
+ LIBBLIND_ESYSTEM = -1 /* errno set */
+#define LIBBLIND_X(NUM, NAM, STR) , NAM = NUM
+ LIBBLIND_LIST_ERRORS(LIBBLIND_X)
+#undef LIBBLIND_X
+};
+
+
+const char *libblind_strerror(int);
+void libblind_perror(const char *, int);
+
+const char *libblind_get_pixfmt(const char *, const char *);
+int libblind_set_pixfmt(struct libblind_stream *, const char *);
+ssize_t libblind_read_stream(struct libblind_stream *, size_t);
+int libblind_init_stream(struct libblind_stream *);
+int libblind_check_dimensions(const struct libblind_stream *, enum dimension);
+int libblind_read_segment(struct libblind_stream *, void *, size_t);
+ssize_t libblind_send_frames(struct libblind_stream *, int, size_t, int *);
+ssize_t libblind_send_rows(struct libblind_stream *, int, size_t, int *);
+ssize_t libblind_send_pixels(struct libblind_stream *, int, size_t, int *);
+int libblind_send_stream(struct libblind_stream *, int, int *);
+
+static inline int
+libblind_read_frame(struct libblind_stream *stream, void *buf)
+{
+ int r = libblind_read_segment(stream, buf, stream->frame_size);
+ return r == LIBBLIND_EINCOMPLETE ? LIBBLIND_EINCOMPLETEFRAME : r;
+}
+
+static inline int
+libblind_read_row(struct libblind_stream *stream, void *buf)
+{
+ int r = libblind_read_segment(stream, buf, stream->row_size);
+ return r == LIBBLIND_EINCOMPLETE ? LIBBLIND_EINCOMPLETEROW : r;
+}
+
+static inline int
+libblind_read_pixel(struct libblind_stream *stream, void *buf)
+{
+ int r = libblind_read_segment(stream, buf, stream->pixel_size);
+ return r == LIBBLIND_EINCOMPLETE ? LIBBLIND_EINCOMPLETEROW : r;
+}
+
+
+#endif
diff --git a/src/stream.c b/src/stream.c
index 52a32dd..3b1340a 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -1,88 +1,14 @@
/* See LICENSE file for copyright and license details. */
#include "common.h"
-static inline int
-get_dimension(int status, size_t *out, const char *s, const char *fname, const char *dim)
-{
- char *end;
- errno = 0;
- *out = strtoul(s, &end, 10);
- if (errno == ERANGE && *s != '-')
- enprintf(status, "%s: video is too %s\n", fname, dim);
- return -(errno || *end);
-}
-
-static inline int
-sread(int status, struct stream *stream)
-{
- ssize_t r;
- r = read(stream->fd, stream->buf + stream->ptr, sizeof(stream->buf) - stream->ptr);
- if (r < 0)
- enprintf(status, "read %s:", stream->file);
- if (r == 0)
- return 0;
- stream->ptr += (size_t)r;
- return 1;
-}
-
void
eninit_stream(int status, struct stream *stream)
{
- size_t n;
- char *p = NULL, *w, *h, *f;
-
- fadvise_sequential(stream->fd, 0, 0);
-
- if (stream->fd >= 0) {
- for (stream->ptr = 0; !p; p = memchr(stream->buf, '\n', stream->ptr))
- if (!sread(status, stream))
- goto bad_format;
- } else {
- p = memchr(stream->buf, '\n', stream->ptr);
- }
-
- *p = '\0';
- if (!(w = strchr(stream->buf, ' ')) ||
- !(h = strchr(w + 1, ' ')) ||
- !(f = strchr(h + 1, ' ')))
- goto bad_format;
- *w++ = *h++ = *f++ = '\0';
-
- if (strlen(f) >= sizeof(stream->pixfmt))
- goto bad_format;
- strcpy(stream->pixfmt, f);
- if (get_dimension(status, &stream->frames, stream->buf, stream->file, "long") ||
- get_dimension(status, &stream->width, w, stream->file, "wide") ||
- get_dimension(status, &stream->height, h, stream->file, "tall"))
- goto bad_format;
-
- if (!stream->width)
- eprintf("%s: width is zero\n", stream->file);
- if (!stream->height)
- eprintf("%s: height is zero\n", stream->file);
-
- n = (size_t)(p - stream->buf) + 1;
- memmove(stream->buf, stream->buf + n, stream->ptr -= n);
- while (stream->ptr < 5)
- if (!sread(status, stream))
- goto bad_format;
- if (stream->buf[0] != '\0' ||
- stream->buf[1] != 'u' || stream->buf[2] != 'i' ||
- stream->buf[3] != 'v' || stream->buf[4] != 'f')
- goto bad_format;
- memmove(stream->buf, stream->buf + 5, stream->ptr -= 5);
- stream->headlen = n + 5;
-
- enset_pixel_format(status, stream, NULL);
-
- stream->xptr = 0;
-
- return;
-bad_format:
- enprintf(status, "%s: file format not supported\n", stream->file);
+ int r = libblind_init_stream(stream);
+ if (r)
+ enprintf(status, "%s: %s\n", stream->file, libblind_strerror(r));
}
-
void
enopen_stream(int status, struct stream *stream, const char *file)
{
@@ -91,113 +17,14 @@ enopen_stream(int status, struct stream *stream, const char *file)
eninit_stream(status, stream);
}
-
-int
-set_pixel_format(struct stream *stream, const char *pixfmt)
-{
-#define TEST_ENCODING_AGNOSTIC(FMT) (!strcmp(stream->pixfmt, FMT) || !strcmp(stream->pixfmt, FMT" f"))
-
- if (pixfmt) {
- pixfmt = get_pixel_format(pixfmt, stream->pixfmt[0] ? stream->pixfmt : "xyza");
- if (strlen(pixfmt) >= sizeof(stream->pixfmt))
- return -1;
- strcpy(stream->pixfmt, pixfmt);
- }
-
- stream->n_chan = 4;
- stream->alpha = UNPREMULTIPLIED;
- stream->encoding = DOUBLE;
- stream->endian = HOST;
- stream->alpha_chan = 3;
- stream->luma_chan = -1;
-
- if (!strcmp(stream->pixfmt, "xyza")) {
- stream->space = CIEXYZ;
- } else if (!strcmp(stream->pixfmt, "xyza f")) {
- stream->space = CIEXYZ;
- stream->encoding = FLOAT;
- } else if (!strcmp(stream->pixfmt, "raw0")) {
- stream->space = YUV_NONLINEAR;
- stream->encoding = UINT16;
- stream->endian = LITTLE;
- stream->alpha_chan = 0;
- stream->luma_chan = 1;
- } else if (!strcmp(stream->pixfmt, "raw1")) {
- stream->space = YUV_NONLINEAR;
- stream->encoding = UINT16;
- stream->endian = LITTLE;
- } else if (!strcmp(stream->pixfmt, "raw2a") || !strcmp(stream->pixfmt, "raw2")) {
- stream->space = YUV_NONLINEAR;
- stream->alpha = stream->pixfmt[4] == 'a' ? UNPREMULTIPLIED : NO_ALPHA;
- stream->encoding = UINT16;
- } else if (TEST_ENCODING_AGNOSTIC("raw3") || TEST_ENCODING_AGNOSTIC("raw3a")) {
- stream->space = YUV_NONLINEAR;
- stream->alpha = stream->pixfmt[4] == 'a' ? UNPREMULTIPLIED : NO_ALPHA;
- stream->encoding = strlen(stream->pixfmt) > 5 ? FLOAT : DOUBLE;
- } else if (TEST_ENCODING_AGNOSTIC("raw4") || TEST_ENCODING_AGNOSTIC("raw4a")) {
- stream->space = SRGB_NONLINEAR;
- stream->alpha = stream->pixfmt[4] == 'a' ? UNPREMULTIPLIED : NO_ALPHA;
- stream->encoding = strlen(stream->pixfmt) > 5 ? FLOAT : DOUBLE;
- } else if (TEST_ENCODING_AGNOSTIC("raw5") || TEST_ENCODING_AGNOSTIC("raw5a")) {
- stream->space = SRGB;
- stream->alpha = stream->pixfmt[4] == 'a' ? UNPREMULTIPLIED : NO_ALPHA;
- stream->encoding = strlen(stream->pixfmt) > 5 ? FLOAT : DOUBLE;
- } else {
- return -1;
- }
-
- if (stream->alpha == NO_ALPHA) {
- stream->n_chan -= 1;
- stream->alpha_chan = -1;
- }
-
- if (stream->luma_chan == -1) {
- if (stream->space == CIEXYZ)
- stream->luma_chan = 1;
- else if (stream->space == YUV_NONLINEAR)
- stream->luma_chan = 0;
- }
-
- switch (stream->encoding) {
- case FLOAT:
- stream->chan_size = sizeof(float);
- break;
- case DOUBLE:
- stream->chan_size = sizeof(double);
- break;
- case LONG_DOUBLE:
- stream->chan_size = sizeof(long double);
- break;
- case UINT8:
- stream->chan_size = sizeof(uint8_t);
- break;
- case UINT16:
- stream->chan_size = sizeof(uint16_t);
- break;
- case UINT32:
- stream->chan_size = sizeof(uint32_t);
- break;
- case UINT64:
- stream->chan_size = sizeof(uint64_t);
- break;
- default:
- abort();
- }
-
- stream->pixel_size = stream->n_chan * stream->chan_size;
- stream->row_size = stream->pixel_size * stream->width;
- stream->col_size = stream->pixel_size * stream->height;
- stream->frame_size = stream->pixel_size * stream->height * stream->width;
- return 0;
-
-#undef TEST_ENCODING_AGNOSTIC
-}
-
void
-enset_pixel_format(int status, struct stream *stream, const char *pixfmt)
+enset_pixfmt(int status, struct stream *stream, const char *pixfmt)
{
- if (set_pixel_format(stream, pixfmt)) {
- if (pixfmt)
+ int err;
+ if ((err = set_pixfmt(stream, pixfmt))) {
+ if (err != LIBBLIND_EPIXFMTNOSUPPORT)
+ enprintf(status, "%s: %s\n", stream->file, libblind_strerror(err));
+ else if (pixfmt)
enprintf(status, "pixel format %s is not supported, try xyza\n", pixfmt);
else
enprintf(status, "%s: unsupported pixel format: %s\n",
@@ -223,11 +50,9 @@ dprint_stream_head(int fd, struct stream *stream)
size_t
enread_stream(int status, struct stream *stream, size_t n)
{
- ssize_t r = read(stream->fd, stream->buf + stream->ptr,
- MIN(sizeof(stream->buf) - stream->ptr, n));
+ ssize_t r = libblind_read_stream(stream, n);
if (r < 0)
- enprintf(status, "read %s:", stream->file);
- stream->ptr += (size_t)r;
+ enprintf(status, "read %s: %s\n", stream->file, libblind_strerror((int)r));
return (size_t)r;
}
@@ -246,46 +71,12 @@ eninf_check_fd(int status, int fd, const char *file)
void
encheck_dimensions(int status, const struct stream *stream, enum dimension dimensions, const char *prefix)
{
- size_t n;
-
- if (!stream->pixel_size)
- enprintf(status, "%s: %s%svideo frame doesn't have a pixel size\n",
- stream->file, prefix ? prefix : "",
- (prefix && *prefix) ? " " : "");
-
- n = SIZE_MAX / stream->pixel_size;
-
- if ((dimensions & WIDTH) && stream->width > n)
- enprintf(status, "%s: %s%svideo frame is too wide\n",
- stream->file, prefix ? prefix : "",
- (prefix && *prefix) ? " " : "");
-
- if ((dimensions & HEIGHT) && stream->height > n)
- enprintf(status, "%s: %s%svideo frame is too wide\n",
- stream->file, prefix ? prefix : "",
- (prefix && *prefix) ? " " : "");
-
- if (!stream->width || !stream->height)
- return;
-
- if ((dimensions & (WIDTH | HEIGHT)) == (WIDTH | HEIGHT)) {
- if (stream->width > n / stream->height)
- enprintf(status, "%s: %s%svideo frame is too large\n",
- stream->file, prefix ? prefix : "",
- (prefix && *prefix) ? " " : "");
- }
-
- if (!(dimensions & LENGTH))
- return;
- if (dimensions & WIDTH)
- n /= stream->width;
- if (dimensions & HEIGHT)
- n /= stream->height;
-
- if (stream->frames > n)
- enprintf(status, "%s: %s%svideo is too large\n",
- stream->file, prefix ? prefix : "",
- (prefix && *prefix) ? " " : "");
+ int r = libblind_check_dimensions(stream, dimensions);
+ if (r < 0)
+ enprintf(status, "%s: %s%s%s\n",
+ stream->file, prefix ? prefix : "",
+ (prefix && *prefix) ? ": " : "",
+ libblind_strerror(r));
}
@@ -300,76 +91,6 @@ encheck_compat(int status, const struct stream *a, const struct stream *b)
const char *
-get_pixel_format(const char *specified, const char *current)
-{
- enum colour_space space = CIEXYZ;
- enum alpha alpha = UNPREMULTIPLIED;
- enum encoding encoding = UINT16;
- int level = -1;
- size_t n = strlen(specified);
-
- if ((n >= 2 && !strcmp(specified - 2, " f")) ||
- !strcmp(specified, "raw0") || !strcmp(specified, "raw1") ||
- !strcmp(specified, "raw2") || !strcmp(specified, "raw2a"))
- return specified;
-
- if (!strcmp(current, "xyza")) space = CIEXYZ, encoding = DOUBLE;
- else if (!strcmp(current, "xyza f")) space = CIEXYZ, encoding = FLOAT;
- else if (!strcmp(current, "raw0")) level = 0;
- else if (!strcmp(current, "raw1")) level = 1;
- else if (!strcmp(current, "raw2")) level = 2, alpha = NO_ALPHA;
- else if (!strcmp(current, "raw2a")) level = 2;
- else if (!strcmp(current, "raw3")) level = 3, encoding = DOUBLE, alpha = NO_ALPHA;
- else if (!strcmp(current, "raw3a")) level = 3, encoding = DOUBLE;
- else if (!strcmp(current, "raw3 f")) level = 3, encoding = FLOAT, alpha = NO_ALPHA;
- else if (!strcmp(current, "raw3a f")) level = 3, encoding = FLOAT;
- else if (!strcmp(current, "raw4")) level = 4, encoding = DOUBLE, alpha = NO_ALPHA;
- else if (!strcmp(current, "raw4a")) level = 4, encoding = DOUBLE;
- else if (!strcmp(current, "raw4 f")) level = 4, encoding = FLOAT, alpha = NO_ALPHA;
- else if (!strcmp(current, "raw4a f")) level = 4, encoding = FLOAT;
- else if (!strcmp(current, "raw5")) level = 5, encoding = DOUBLE, alpha = NO_ALPHA;
- else if (!strcmp(current, "raw5a")) level = 5, encoding = DOUBLE;
- else if (!strcmp(current, "raw5 f")) level = 5, encoding = FLOAT, alpha = NO_ALPHA;
- else if (!strcmp(current, "raw5a f")) level = 5, encoding = FLOAT;
- else
- return specified;
-
- if (!strcmp(specified, "f")) encoding = FLOAT;
- else if (!strcmp(specified, "!f")) encoding = DOUBLE;
- else if (!strcmp(specified, "xyza")) level = -1, alpha = UNPREMULTIPLIED, space = CIEXYZ;
- else if (!strcmp(specified, "raw3")) level = 3, alpha = NO_ALPHA;
- else if (!strcmp(specified, "raw3a")) level = 3, alpha = UNPREMULTIPLIED;
- else if (!strcmp(specified, "raw4")) level = 4, alpha = NO_ALPHA;
- else if (!strcmp(specified, "raw4a")) level = 4, alpha = UNPREMULTIPLIED;
- else if (!strcmp(specified, "raw5")) level = 5, alpha = NO_ALPHA;
- else if (!strcmp(specified, "raw5a")) level = 5, alpha = UNPREMULTIPLIED;
- else if (!strcmp(specified, "xyza !f")) return "xyza";
- else if (!strcmp(specified, "raw3 !f")) return "raw3";
- else if (!strcmp(specified, "raw3a !f")) return "raw3a";
- else if (!strcmp(specified, "raw4 !f")) return "raw4";
- else if (!strcmp(specified, "raw4a !f")) return "raw4a";
- else if (!strcmp(specified, "raw5 !f")) return "raw5";
- else if (!strcmp(specified, "raw5a !f")) return "raw5a";
- else
- return specified;
-
- if (level == 0 && encoding == UINT16) return "raw0";
- else if (level == 1 && encoding == UINT16) return "raw1";
- else if (level == 2 && encoding == UINT16) return alpha ? "raw2a" : "raw2";
- else if (level == 3 && encoding == DOUBLE) return alpha ? "raw3a" : "raw3";
- else if (level == 3 && encoding == FLOAT) return alpha ? "raw3a f" : "raw3 f";
- else if (level == 4 && encoding == DOUBLE) return alpha ? "raw4a" : "raw4";
- else if (level == 4 && encoding == FLOAT) return alpha ? "raw4a f" : "raw4 f";
- else if (level == 5 && encoding == DOUBLE) return alpha ? "raw5a" : "raw5";
- else if (level == 5 && encoding == FLOAT) return alpha ? "raw5a f" : "raw5 f";
- else if (level < 0 && space == CIEXYZ && alpha == UNPREMULTIPLIED)
- return encoding == FLOAT ? "xyza f" : encoding == DOUBLE ? "xyza" : specified;
- else
- return specified;
-}
-
-
-const char *
nselect_print_format(int status, const char *format, enum encoding encoding, const char *fmt)
{
static char retbuf[512];
@@ -526,125 +247,66 @@ check_done:
int
enread_segment(int status, struct stream *stream, void *buf, size_t n)
{
- char *buffer = buf;
- ssize_t r;
- size_t m;
-
- if (stream->ptr) {
- m = MIN(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->xptr)
- break;
- enprintf(status, "%s: incomplete frame", stream->file);
- }
- }
-
- if (!stream->xptr)
- return 0;
- stream->xptr -= n;
- return 1;
+ int r = libblind_read_segment(stream, buf, n);
+ if (r < 0)
+ enprintf(status, "%s: %s\n", stream->file, libblind_strerror(r));
+ return r;
}
-
size_t
ensend_frames(int status, struct stream *stream, int outfd, size_t frames, const char *outfname)
{
- size_t h, w, p, n, ret;
-
- for (ret = 0; ret < frames; ret++) {
- for (p = stream->pixel_size; p; p--) {
- for (h = stream->height; h; h--) {
- for (w = stream->width; w; w -= n) {
- if (!stream->ptr && !enread_stream(status, stream, w))
- goto done;
- n = MIN(stream->ptr, w);
- if (outfd >= 0)
- enwriteall(status, outfd, stream->buf, n, outfname);
- memmove(stream->buf, stream->buf + n, stream->ptr -= n);
- }
- }
- }
+ int outfailed;
+ int r = libblind_send_frames(stream, outfd, frames, &outfailed);
+ if (r < 0) {
+ if (!outfailed)
+ enprintf(status, "%s:", stream->file);
+ else if (outfname)
+ enprintf(status, "%s:", outfname);
}
-
- return ret;
-done:
- if (p != stream->pixel_size || h != stream->height || w != stream->width)
- enprintf(status, "%s: incomplete frame", stream->file);
- return ret;
+ return r;
}
-
size_t
ensend_rows(int status, struct stream *stream, int outfd, size_t rows, const char *outfname)
{
- size_t w, p, n, ret;
-
- for (ret = 0; ret < rows; ret++) {
- for (p = stream->pixel_size; p; p--) {
- for (w = stream->width; w; w -= n) {
- if (!stream->ptr && !enread_stream(status, stream, w))
- goto done;
- n = MIN(stream->ptr, w);
- if (outfd >= 0)
- enwriteall(status, outfd, stream->buf, n, outfname);
- memmove(stream->buf, stream->buf + n, stream->ptr -= n);
- }
- }
+ int outfailed;
+ int r = libblind_send_rows(stream, outfd, rows, &outfailed);
+ if (r < 0) {
+ if (!outfailed)
+ enprintf(status, "%s:", stream->file);
+ else if (outfname)
+ enprintf(status, "%s:", outfname);
}
-
- return ret;
-done:
- if (p != stream->pixel_size || w != stream->width)
- enprintf(status, "%s: incomplete row", stream->file);
- return ret;
+ return r;
}
-
size_t
ensend_pixels(int status, struct stream *stream, int outfd, size_t pixels, const char *outfname)
{
- size_t p, n, ret;
-
- for (ret = 0; ret < pixels; ret++) {
- for (p = stream->pixel_size; p; p -= n) {
- if (!stream->ptr && !enread_stream(status, stream, p))
- goto done;
- n = MIN(stream->ptr, p);
- if (outfd >= 0)
- enwriteall(status, outfd, stream->buf, n, outfname);
- memmove(stream->buf, stream->buf + n, stream->ptr -= n);
- }
+ int outfailed;
+ int r = libblind_send_pixels(stream, outfd, pixels, &outfailed);
+ if (r < 0) {
+ if (!outfailed)
+ enprintf(status, "%s:", stream->file);
+ else if (outfname)
+ enprintf(status, "%s:", outfname);
}
-
- return ret;
-done:
- if (p != stream->pixel_size)
- enprintf(status, "%s: incomplete pixel", stream->file);
- return ret;
+ return r;
}
-
int
ensend_stream(int status, struct stream *stream, int outfd, const char *outfname)
{
- do {
- if (writeall(outfd, stream->buf, stream->ptr)) {
- if (outfname)
- eprintf("write %s:", outfname);
- return -1;
- }
- stream->ptr = 0;
- } while (enread_stream(status, stream, SIZE_MAX));
- return 0;
+ int outfailed;
+ int r = libblind_send_stream(stream, outfd, &outfailed);
+ if (r < 0) {
+ if (!outfailed)
+ enprintf(status, "%s:", stream->file);
+ else if (outfname)
+ enprintf(status, "%s:", outfname);
+ }
+ return r;
}
diff --git a/src/stream.h b/src/stream.h
index 9499bcf..9ff1bdb 100644
--- a/src/stream.h
+++ b/src/stream.h
@@ -3,7 +3,8 @@
#include <stddef.h>
#include <stdio.h>
-#define STREAM_HEAD_MAX (3 * INTSTRLEN(size_t) + sizeof(((struct stream *)0)->pixfmt) + 10)
+#define LIBBLIND_NO_NAMESPACE
+#include "libblind.h"
#define XPRINTF_HEAD_FMT "%zu %zu %zu %s\n%cuivf"
#define XPRINTF_HEAD_ARGS(FRAMES, WIDTH, HEIGHT, PIXFMT)\
@@ -37,7 +38,7 @@
#define einit_stream(...) eninit_stream(1, __VA_ARGS__)
#define eopen_stream(...) enopen_stream(1, __VA_ARGS__)
-#define eset_pixel_format(...) enset_pixel_format(1, __VA_ARGS__)
+#define eset_pixfmt(...) enset_pixfmt(1, __VA_ARGS__)
#define eread_stream(...) enread_stream(1, __VA_ARGS__)
#define einf_check_fd(...) eninf_check_fd(1, __VA_ARGS__)
#define echeck_dimensions(...) encheck_dimensions(1, __VA_ARGS__)
@@ -58,77 +59,15 @@
#define process_multiple_streams(...) nprocess_multiple_streams(1, __VA_ARGS__)
#define process_each_frame_two_streams(...) nprocess_each_frame_two_streams(1, __VA_ARGS__)
-enum dimension {
- WIDTH = 1,
- HEIGHT = 2,
- LENGTH = 4
-};
-
-enum colour_space {
- CIEXYZ,
- YUV_NONLINEAR,
- SRGB_NONLINEAR,
- SRGB
-};
-
-enum alpha {
- NO_ALPHA,
- UNPREMULTIPLIED,
- PREMULTIPLIED /* not used */
-};
-
-enum encoding {
- FLOAT,
- DOUBLE,
- LONG_DOUBLE, /* not used */
- UINT8, /* not used */
- UINT16,
- UINT32, /* not used */
- UINT64 /* not used */
-};
-
-enum endian {
- HOST,
- LITTLE,
- BIG /* not used */
-};
-
-struct stream {
- size_t frames;
- size_t width;
- size_t height;
- size_t n_chan;
- size_t chan_size;
- size_t pixel_size;
- char pixfmt[32];
- enum colour_space space;
- enum alpha alpha;
- enum encoding encoding;
- enum endian endian;
- short int alpha_chan;
- short int luma_chan;
- int fd;
- size_t ptr;
- size_t xptr;
- char buf[BUFSIZ];
- const char *file;
- size_t headlen;
- size_t row_size;
- size_t col_size;
- size_t frame_size;
-};
-
void eninit_stream(int status, struct stream *stream);
void enopen_stream(int status, struct stream *stream, const char *file);
-int set_pixel_format(struct stream *stream, const char *pixfmt);
-void enset_pixel_format(int status, struct stream *stream, const char *pixfmt);
+void enset_pixfmt(int status, struct stream *stream, const char *pixfmt);
void fprint_stream_head(FILE *fp, struct stream *stream);
int dprint_stream_head(int fd, struct stream *stream);
size_t enread_stream(int status, struct stream *stream, size_t n);
void eninf_check_fd(int status, int fd, const char *file);
void encheck_dimensions(int status, const struct stream *stream, enum dimension dimensions, const char *prefix);
void encheck_compat(int status, const struct stream *a, const struct stream *b);
-const char *get_pixel_format(const char *specified, const char *current);
const char *nselect_print_format(int status, const char *format, enum encoding encoding, const char *fmt);
int enread_segment(int status, struct stream *stream, void *buf, size_t n);
size_t ensend_frames(int status, struct stream *stream, int outfd, size_t frames, const char *outfname);