diff --git a/docker-compose.gpu.yml b/docker-compose.gpu.yml index e26eeb9..59e48e7 100644 --- a/docker-compose.gpu.yml +++ b/docker-compose.gpu.yml @@ -16,6 +16,11 @@ # - Sets NVENC_ENABLED=true so the worker prioritises h264_nvenc/hevc_nvenc services: + capture: + runtime: nvidia + environment: + NVIDIA_VISIBLE_DEVICES: all + NVIDIA_DRIVER_CAPABILITIES: video,compute,utility worker: build: context: ./services/worker diff --git a/docker-compose.worker.yml b/docker-compose.worker.yml index 4592f94..dbb0386 100644 --- a/docker-compose.worker.yml +++ b/docker-compose.worker.yml @@ -104,6 +104,7 @@ services: build: ./services/capture profiles: [capture] restart: unless-stopped + runtime: nvidia environment: REDIS_URL: ${REDIS_URL} DATABASE_URL: ${DATABASE_URL} @@ -112,6 +113,8 @@ services: S3_ACCESS_KEY: ${S3_ACCESS_KEY} S3_SECRET_KEY: ${S3_SECRET_KEY} CAPTURE_PORT: 3001 + NVIDIA_VISIBLE_DEVICES: all + NVIDIA_DRIVER_CAPABILITIES: video,compute,utility devices: - ${BMD_DEVICE_0:-/dev/blackmagic/dv0}:/dev/blackmagic/dv0 - ${BMD_DEVICE_1:-/dev/blackmagic/dv1}:/dev/blackmagic/dv1 diff --git a/services/capture/deltacast-bridge/main.c b/services/capture/deltacast-bridge/main.c index 5675eb7..00a5472 100644 --- a/services/capture/deltacast-bridge/main.c +++ b/services/capture/deltacast-bridge/main.c @@ -110,14 +110,33 @@ static VideoInfo video_info(VHD_VIDEOSTANDARD std, VHD_CLOCKDIVISOR div) { } /* ── Write-all helper ─────────────────────────────────────────────────── */ +/* Writes all bytes to fd. Uses non-blocking I/O so the bridge never stalls + * waiting for a slow reader. Returns 0 on success, -1 on fatal error (EPIPE + * = reader closed the FIFO). EAGAIN / EWOULDBLOCK on a full pipe is NOT fatal + * — the caller (video_thread) will retry on the next slot lock. */ static int write_all(int fd, const unsigned char *p, size_t len) { + /* Make the fd non-blocking for the duration of this write */ + int flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) return -1; + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) return -1; + size_t off = 0; while (off < len) { ssize_t n = write(fd, p + off, len - off); if (n > 0) { off += (size_t)n; continue; } if (n < 0 && errno == EINTR) continue; + if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + /* Pipe full — brief yield then retry */ + struct timespec ts = {0, 1000000L}; /* 1ms */ + nanosleep(&ts, NULL); + continue; + } + /* EPIPE or other fatal error — restore flags and return */ + fcntl(fd, F_SETFL, flags); return -1; } + /* Restore blocking mode */ + fcntl(fd, F_SETFL, flags); return 0; } @@ -318,10 +337,13 @@ static void *video_thread(void *arg) { #ifndef F_SETPIPE_SZ #define F_SETPIPE_SZ 1031 #endif - if (fcntl(fd, F_SETPIPE_SZ, 8 * 1024 * 1024) < 0) { - fprintf(stderr, "[video:%u] fcntl F_SETPIPE_SZ failed: %s\n", ps->port, strerror(errno)); - } else { - fprintf(stderr, "[video:%u] FIFO pipe size increased to 8MB\n", ps->port); + { + int pipe_sz = 64 * 1024 * 1024; /* 64 MB — ~16 frames of 1080p UYVY */ + if (fcntl(fd, F_SETPIPE_SZ, pipe_sz) < 0) { + fprintf(stderr, "[video:%u] fcntl F_SETPIPE_SZ failed: %s\n", ps->port, strerror(errno)); + } else { + fprintf(stderr, "[video:%u] FIFO pipe size increased to %dMB\n", ps->port, pipe_sz / (1024*1024)); + } } HANDLE slot = NULL;