blind

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

commit 1519bc79a4bc7749b0e4808d78f3ee0c171db9e8
parent 836ed8b478c660a2fcb18cb4036da5706afd155c
Author: Mattias Andrée <maandree@kth.se>
Date:   Fri, 13 Jan 2017 08:59:01 +0100

vu-from-video: fix Y'UV encoding + add vu-to-video

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

Diffstat:
MMakefile | 1+
MTODO | 1-
Msrc/vu-from-video.c | 12++++++------
Asrc/vu-to-video.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 153 insertions(+), 7 deletions(-)

diff --git a/Makefile b/Makefile @@ -29,6 +29,7 @@ BIN =\ vu-stack\ vu-to-image\ vu-to-text\ + vu-to-video\ vu-transpose\ vu-write-head diff --git a/TODO b/TODO @@ -2,7 +2,6 @@ vu-transform transformation by matrix multiplication, -t for tiling, -s for imp on downscaling (pixels' neighbours must not change) vu-chroma-key replace a chroma with transparency vu-primary-key replace a primary with transparency, -g for greyscaled images -vu-to-video use ffmpeg to convert to another format vu-primaries given three selectable primaries split the video into three side-by-side which only one primary active vu-apply-map remap pixels (distortion) using the X and Y values, -t for tiling, -s for diff --git a/src/vu-from-video.c b/src/vu-from-video.c @@ -112,9 +112,9 @@ convert_segment(char *buf, size_t n, int fd, char *file) if (draft) { for (ptr = i = 0; ptr < n; ptr += 8) { pixels[i][3] = ntohs(((uint16_t *)(buf + ptr))[0]) / max; - y = ntohs(((uint16_t *)(buf + ptr))[1]); - u = ntohs(((uint16_t *)(buf + ptr))[2]); - v = ntohs(((uint16_t *)(buf + ptr))[3]); + y = (ntohs(((uint16_t *)(buf + ptr))[1]) - 16 * 256); + u = (ntohs(((uint16_t *)(buf + ptr))[2]) - 128 * 256); + v = (ntohs(((uint16_t *)(buf + ptr))[3]) - 128 * 256); scaled_yuv_to_ciexyz(y, u, v, pixels[i] + 0, pixels[i] + 1, pixels[i] + 2); if (++i == 1024) { i = 0; @@ -124,9 +124,9 @@ convert_segment(char *buf, size_t n, int fd, char *file) } else { for (ptr = i = 0; ptr < n; ptr += 8) { pixels[i][3] = ntohs(((uint16_t *)(buf + ptr))[0]) / max; - y = ntohs(((uint16_t *)(buf + ptr))[1]) / max; - u = ntohs(((uint16_t *)(buf + ptr))[2]) / max; - v = ntohs(((uint16_t *)(buf + ptr))[3]) / max; + y = (ntohs(((uint16_t *)(buf + ptr))[1]) - 16 * 256) / max; + u = (ntohs(((uint16_t *)(buf + ptr))[2]) - 128 * 256) / max; + v = (ntohs(((uint16_t *)(buf + ptr))[3]) - 128 * 256) / max; yuv_to_srgb(y, u, v, &r, &g, &b); r = srgb_decode(r); g = srgb_decode(g); diff --git a/src/vu-to-video.c b/src/vu-to-video.c @@ -0,0 +1,146 @@ +/* See LICENSE file for copyright and license details. */ +#include "stream.h" +#include "util.h" + +#include <arpa/inet.h> +#if defined(HAVE_PRCTL) +# include <sys/prctl.h> +#endif +#include <sys/wait.h> +#include <signal.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +USAGE("[-d] frame-rate ffmpeg-arguments ...") + +static int draft = 0; + +static void +process_xyza(char *buf, size_t n, int fd, const char *fname) +{ + double *pixel, r, g, b; + uint16_t *pixels, *end; + uint16_t pixbuf[1024]; + long int a, y, u, v; + size_t ptr; + pixels = pixbuf; + end = pixbuf + ELEMENTSOF(pixbuf); + if (draft) { + for (ptr = 0; ptr < n; ptr += sizeof(pixel)) { + pixel = (double *)(buf + ptr); + a = (long int)(pixel[3] * 0xFFFFL); + ciexyz_to_scaled_yuv(pixel[0], pixel[1], pixel[2], &r, &g, &b); + y = (long int)r + 16 * 256; + u = (long int)g + 128 * 256; + v = (long int)b + 128 * 256; + *pixels++ = htons((uint16_t)(a < 0 ? 0 : a > 0xFFFFL ? 0xFFFFL : a)); + *pixels++ = htons((uint16_t)(y < 0 ? 0 : y > 0xFFFFL ? 0xFFFFL : y)); + *pixels++ = htons((uint16_t)(u < 0 ? 0 : u > 0xFFFFL ? 0xFFFFL : u)); + *pixels++ = htons((uint16_t)(v < 0 ? 0 : v > 0xFFFFL ? 0xFFFFL : v)); + if (pixels == end) + ewriteall(fd, pixels = pixbuf, sizeof(pixbuf), fname); + } + } else { + for (ptr = 0; ptr < n; ptr += sizeof(pixel)) { + pixel = (double *)(buf + ptr); + a = (long int)(pixel[3] * 0xFFFFL); + ciexyz_to_srgb(pixel[0], pixel[1], pixel[2], &r, &g, &b); + r = srgb_encode(r); + g = srgb_encode(g); + b = srgb_encode(b); + srgb_to_yuv(r, g, b, pixel + 0, pixel + 1, pixel + 2); + y = (long int)(pixel[0] * 0xFFFFL); + u = (long int)(pixel[1] * 0xFFFFL); + v = (long int)(pixel[2] * 0xFFFFL); + y += 16 * 256; + u += 128 * 256; + v += 128 * 256; + *pixels++ = htons((uint16_t)(a < 0 ? 0 : a > 0xFFFFL ? 0xFFFFL : a)); + *pixels++ = htons((uint16_t)(y < 0 ? 0 : y > 0xFFFFL ? 0xFFFFL : y)); + *pixels++ = htons((uint16_t)(u < 0 ? 0 : u > 0xFFFFL ? 0xFFFFL : u)); + *pixels++ = htons((uint16_t)(v < 0 ? 0 : v > 0xFFFFL ? 0xFFFFL : v)); + if (pixels == end) + ewriteall(fd, pixels = pixbuf, sizeof(pixbuf), fname); + } + } + if (pixels != pixbuf) + ewriteall(fd, pixels = pixbuf, sizeof(pixbuf), fname); +} + +int +main(int argc, char *argv[]) +{ + struct stream stream; + char geometry[2 * 3 * sizeof(size_t) + 2]; + char *frame_rate; + const char **cmd; + size_t n = 0; + int status, pipe_rw[2]; + pid_t pid; + void (*process)(char *buf, size_t n, int fd, const char *fname) = NULL; + + ARGBEGIN { + case 'd': + draft = 1; + break; + default: + usage(); + } ARGEND; + + if (argc < 2) + usage(); + + frame_rate = *argv++, argc--; + cmd = ecalloc((size_t)argc + 12, sizeof(*cmd)); + cmd[n++] = "ffmpeg"; + cmd[n++] = "-f", cmd[n++] = "rawvideo"; + cmd[n++] = "-pix_fmt", cmd[n++] = "ayuv64le"; + cmd[n++] = "-r", cmd[n++] = frame_rate; + cmd[n++] = "-s:v", cmd[n++] = geometry; + cmd[n++] = "-i", cmd[n++] = "-"; + memcpy(cmd + n, argv, (size_t)argc * sizeof(*cmd)); + + stream.file = "<stdin>"; + stream.fd = STDIN_FILENO; + einit_stream(&stream); + + sprintf(geometry, "%zux%zu", stream.width, stream.height); + + if (!strcmp(stream.pixfmt, "xyza")) + process = process_xyza; + else + eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); + + if (pipe(pipe_rw)) + eprintf("pipe:"); + + pid = fork(); + if (pid < 0) + eprintf("fork:"); + + if (!pid) { +#if defined(HAVE_PRCTL) && defined(PR_SET_PDEATHSIG) + prctl(PR_SET_PDEATHSIG, SIGKILL); +#endif + close(pipe_rw[1]); + if (dup2(pipe_rw[0], STDIN_FILENO) == -1) + eprintf("dup2:"); + close(pipe_rw[0]); + eprintf("exec ffmpeg:"); + } + + close(pipe_rw[0]); + while (!eread_stream(&stream, SIZE_MAX)) { + n = stream.ptr - (stream.ptr % stream.pixel_size); + process(stream.buf, n, pipe_rw[1], "<subprocess>"); + memmove(stream.buf, stream.buf + n, stream.ptr -= n); + } + close(pipe_rw[1]); + + if (waitpid(pid, &status, 0) == -1) + eprintf("waitpid:"); + + return !!status; +}