diff options
| author | Mattias Andrée <maandree@kth.se> | 2017-12-07 23:48:45 +0100 |
|---|---|---|
| committer | Mattias Andrée <maandree@kth.se> | 2017-12-07 23:48:45 +0100 |
| commit | 4d7c506a29a5153a2b6ab903d2f4731bbab6abcb (patch) | |
| tree | 67bdf5fa8d517cd9fc137f45567f4e312a0f4fc9 | |
| parent | blind-peek-head: fix minor compile-time bug (diff) | |
| download | blind-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-- | Makefile | 12 | ||||
| -rw-r--r-- | blind.mk | 30 | ||||
| -rw-r--r-- | src/blind-colour-matrix.c | 2 | ||||
| -rw-r--r-- | src/blind-concat.c | 4 | ||||
| -rw-r--r-- | src/blind-convert.c | 4 | ||||
| -rw-r--r-- | src/blind-coordinate-field.c | 2 | ||||
| -rw-r--r-- | src/blind-from-video.c | 4 | ||||
| -rw-r--r-- | src/blind-hexagon-tessellation.c | 2 | ||||
| -rw-r--r-- | src/blind-next-frame.c | 2 | ||||
| -rw-r--r-- | src/blind-peek-head.c | 2 | ||||
| -rw-r--r-- | src/blind-read-head.c | 2 | ||||
| -rw-r--r-- | src/blind-rectangle-tessellation.c | 2 | ||||
| -rw-r--r-- | src/blind-rewrite-head.c | 4 | ||||
| -rw-r--r-- | src/blind-single-colour.c | 2 | ||||
| -rw-r--r-- | src/blind-triangle-tessellation.c | 2 | ||||
| -rw-r--r-- | src/common.h | 2 | ||||
| -rw-r--r-- | src/libblind.c | 504 | ||||
| -rw-r--r-- | src/libblind.h | 190 | ||||
| -rw-r--r-- | src/stream.c | 446 | ||||
| -rw-r--r-- | src/stream.h | 69 |
20 files changed, 792 insertions, 495 deletions
@@ -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 @@ -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); |
