From 616b2af44b8e9f24896451f369612c77f7359790 Mon Sep 17 00:00:00 2001 From: klemek Date: Sun, 21 Sep 2025 23:31:09 +0200 Subject: [PATCH] wip video device --- Makefile.dev | 2 +- shaders/frag0.glsl | 15 +++++++- shaders/frag1.glsl | 10 +----- shaders/frag2.glsl | 10 +----- src/forge.c | 2 +- src/video.c | 86 ++++++++++++++++++++++++++++++++-------------- 6 files changed, 78 insertions(+), 47 deletions(-) diff --git a/Makefile.dev b/Makefile.dev index 7ae6b2b..99f8b09 100644 --- a/Makefile.dev +++ b/Makefile.dev @@ -1,6 +1,6 @@ TARGET ?= forge INSTALL_DIR ?= $(HOME)/.local/bin -TEST_ARGS ?= --frag=./shaders --frag-config=./config/shaders.cfg --video-in=/dev/video2 --video-in=/dev/video9 --tempo=30 +TEST_ARGS ?= --frag=./shaders --frag-config=./config/shaders.cfg --video-in=/dev/video0 --video-in=/dev/video1 --video-in=/dev/video2 --video-in=/dev/video3 --video-in=/dev/video4 --video-in=/dev/video5 --video-in=/dev/video6 --video-in=/dev/video7 --video-in=/dev/video8 --video-in=/dev/video9 --tempo=30 SHELL := /bin/bash .PHONY: build diff --git a/shaders/frag0.glsl b/shaders/frag0.glsl index 538b8c1..2f51cb1 100644 --- a/shaders/frag0.glsl +++ b/shaders/frag0.glsl @@ -1923,4 +1923,17 @@ subroutine(mix_stage_sub) vec4 mix_16(vec2 vUV, sampler2D ta, sampler2D tb, int // TODO temp -const mat4x4 yuv_to_rgb = {{1,0,1.13983,0},{1,-0.39465,-0.5806,0},{1,2.03211,0,0},{0,0,0,1}}; \ No newline at end of file +const mat3x3 yuv_to_rgb = {{1,1,1},{0,-0.39465,2.03211},{1.13983,-0.5806,0}}; + +vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) { + float w = base_width - 1; + int x = int(vUV.x * w); + int xU = x - x % 2; + int xV = x - x % 2 + 1; + vec3 yuv = vec3( + texture(tex, vec2(vUV.x, 1 - vUV.y)).x, + texture(tex, vec2(xU / w, 1 - vUV.y)).y - 0.5, + texture(tex, vec2(xV / w, 1 - vUV.y)).y - 0.5 + ); + return vec4(yuv_to_rgb * yuv, 1.0); +} \ No newline at end of file diff --git a/shaders/frag1.glsl b/shaders/frag1.glsl index d7863bc..d2ce06c 100644 --- a/shaders/frag1.glsl +++ b/shaders/frag1.glsl @@ -7,13 +7,5 @@ in vec2 vUV; out vec4 fragColor; void main() { - float r, g, b, y, u, v; - vec4 src = texture(tex1, vec2(vUV.x, 1 - vUV.y)); - y = src.r; - u = src.g - 0.5; - v = src.a - 0.5; - r = y + 1.13983 * v; - g = y - 0.39465 * u - 0.58060 * v; - b = y + 2.03211 * u; - fragColor = vec4(r, g, b, 1.0); + fragColor = yuyvTex(tex1, vUV, 320); } \ No newline at end of file diff --git a/shaders/frag2.glsl b/shaders/frag2.glsl index 628df6a..98aecd1 100644 --- a/shaders/frag2.glsl +++ b/shaders/frag2.glsl @@ -7,13 +7,5 @@ in vec2 vUV; out vec4 fragColor; void main() { - float r, g, b, y, u, v; - vec4 src = texture(tex2, vec2(vUV.x, 1 - vUV.y)); - y = src.r; - u = src.g - 0.5; - v = src.a - 0.5; - r = y + 1.13983 * v; - g = y - 0.39465 * u - 0.58060 * v; - b = y + 2.03211 * u; - fragColor = vec4(r, g, b, 1.0); + fragColor = yuyvTex(tex2, vUV, 320); } \ No newline at end of file diff --git a/src/forge.c b/src/forge.c index 2aba87d..ad83cbb 100644 --- a/src/forge.c +++ b/src/forge.c @@ -150,7 +150,7 @@ static void init_devices(char *video_in[MAX_VIDEO], unsigned int video_count) { devices = malloc(video_count * sizeof(VideoDevice)); for (i = 0; i < video_count; i++) { - devices[i] = video_init(video_in[i], 640, 480); // TODO define in args + devices[i] = video_init(video_in[i], 320, 240); // TODO define in args } } diff --git a/src/video.c b/src/video.c index 88f6c8c..18438c4 100644 --- a/src/video.c +++ b/src/video.c @@ -8,6 +8,47 @@ #include "types.h" #include "video.h" +static void ioctl_error(VideoDevice *device, const char *operation, + const char *default_msg) { + if (errno == EINVAL) { + log_warn("(%s) %s -> EINVAL: %s", device->name, operation, default_msg); + } else if (errno == EAGAIN) { + log_warn("(%s) %s -> EAGAIN: device state invalid", operation, + device->name); + } else if (errno == EBADF) { + log_warn("(%s) %s -> EBADF: file descriptor invalid", operation, + device->name); + } else if (errno == EBUSY) { + log_warn("(%s) %s -> EBUSY: device is busy", device->name, operation); + } else if (errno == EFAULT) { + log_warn("(%s) %s -> EFAULT: invalid pointer", device->name, operation); + } else if (errno == ENODEV) { + log_warn("(%s) %s -> ENODEV: device not found", device->name, operation); + } else if (errno == ENOMEM) { + log_warn("(%s) %s -> ENOMEM: not enough memory", device->name, operation); + } else if (errno == ENOTTY) { + log_warn("(%s) %s -> ENOTTY: ioctl not supported by file descriptor", + device->name, operation); + } else if (errno == ENOSPC) { + log_warn("(%s) %s -> ENOSPC: USB bandwidth error", device->name, operation); + } else if (errno == EPERM) { + log_warn("(%s) %s -> EPERM: permission denied", device->name, operation); + } else if (errno == EIO) { + log_warn("(%s) %s -> EIO: I/O error", device->name, operation); + } else if (errno == ENXIO) { + log_warn("(%s) %s -> ENXIO: no device exists", device->name, operation); + } else if (errno == EPIPE) { + log_warn("(%s) %s -> EPIPE: pipeline error", device->name, operation); + } else if (errno == ENOLINK) { + log_warn("(%s) %s -> ENOLINK: pipeline configuration invalid for Media " + "Controller interface", + device->name, operation); + } else { + log_error("(%s) %s unknown error %d", device->name, operation, errno); + } + device->error = true; +} + static VideoDevice open_device(char *name) { VideoDevice device; @@ -30,12 +71,7 @@ static bool check_device_caps(VideoDevice *device) { memset(&cap, 0, sizeof(cap)); if (ioctl(device->fd, VIDIOC_QUERYCAP, &cap) == -1) { - if (EINVAL == errno) { - log_warn("(%s) Not a V4L2 device", device->name); - } else { - log_error("(%s) VIDIOC_QUERYCAP unkown error", device->name); - } - device->error = true; + ioctl_error(device, "VIDIOC_QUERYCAP", "Not a V4L2 device"); return false; } @@ -67,8 +103,7 @@ static bool set_device_format(VideoDevice *device, unsigned int preferred_width, fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (ioctl(device->fd, VIDIOC_S_FMT, &fmt) == -1) { - log_warn("(%s) Format set failed", device->name); - device->error = true; + ioctl_error(device, "VIDIOC_S_FMT", "Requested buffer type not supported"); return false; } @@ -96,13 +131,8 @@ static bool request_buffers(VideoDevice *device) { reqbuf.count = 1; if (ioctl(device->fd, VIDIOC_REQBUFS, &reqbuf) == -1) { - if (errno == EINVAL) { - log_info("(%s) Video capturing or DMABUF streaming is not supported", - device->name); - } else { - log_error("(%s) VIDIOC_REQBUFS unkown error", device->name); - } - device->error = true; + ioctl_error(device, "VIDIOC_REQBUFS", + "Buffer type or I/O method not supported"); return false; } @@ -123,8 +153,9 @@ static bool export_buffer(VideoDevice *device) { expbuf.flags = O_RDONLY; if (ioctl(device->fd, VIDIOC_EXPBUF, &expbuf) == -1) { - log_error("(%s) VIDIOC_EXPBUF error", device->name); - device->error = true; + ioctl_error( + device, "VIDIOC_EXPBUF", + "A queue is not in MMAP mode or DMABUF exporting is not supported"); return false; } @@ -137,8 +168,9 @@ static const enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; static bool open_stream(VideoDevice *device) { if (ioctl(device->fd, VIDIOC_STREAMON, &buf_type) == -1) { - log_error("(%s) VIDIOC_STREAMON error", device->name); - device->error = true; + ioctl_error( + device, "VIDIOC_STREAMON", + "Buffer type not supported or no buffer allocated or enqueued yet"); return false; } @@ -177,9 +209,9 @@ VideoDevice video_init(char *name, unsigned int preferred_width, return device; } - if (!request_buffers(&device)) { - return device; - } + // if (!request_buffers(&device)) { + // return device; + // } if (!export_buffer(&device)) { return device; @@ -196,14 +228,16 @@ VideoDevice video_init(char *name, unsigned int preferred_width, bool video_read(VideoDevice *device) { if (ioctl(device->fd, VIDIOC_DQBUF, &device->buf) == -1) { - log_warn("(%s) Video error", device->name); - device->error = true; + ioctl_error(device, "VIDIOC_DQBUF", + "buffer type not supported or no buffer allocated or the index " + "is out of bounds"); return false; } if (ioctl(device->fd, VIDIOC_QBUF, &device->buf) == -1) { - log_warn("(%s) Video error", device->name); - device->error = true; + ioctl_error(device, "VIDIOC_QBUF", + "buffer type not supported or no buffer allocated or the index " + "is out of bounds"); return false; }