diff --git a/C/Makefile b/C/Makefile index 4c85aa3..b1eb68f 100644 --- a/C/Makefile +++ b/C/Makefile @@ -1,7 +1,7 @@ CC = gcc CFLAGS = -Wall -Wextra -O2 -Iinclude LDFLAGS = -lm -# LDFLAGS += -lpthread +LDFLAGS += -lpthread SRCDIR = src INCDIR = include diff --git a/C/include/thread_sharing.h b/C/include/thread_sharing.h new file mode 100644 index 0000000..7a800af --- /dev/null +++ b/C/include/thread_sharing.h @@ -0,0 +1,17 @@ +#include +#include +#include "ascii.h" + +typedef struct { + uint8_t *buf[2]; // Duble buffer + int width, height; + int ascii_w, ascii_h; + int ready_idx; + int has_frame; + pthread_mutex_t lock; + pthread_cond_t cond; + volatile int stop; + + ascii_opts_t opts; +} shared_frame_t; + diff --git a/C/src/main.c b/C/src/main.c index 2883091..9cc24d1 100644 --- a/C/src/main.c +++ b/C/src/main.c @@ -1,6 +1,7 @@ #include "ascii.h" #include "capture.h" #include "timing.h" +#include "thread_sharing.h" #include #include @@ -10,6 +11,8 @@ #include #include #include +#include +#include // Defaults #define DEFAULT_ASCII_WIDTH 80 diff --git a/C/src/thread_sharing.c b/C/src/thread_sharing.c new file mode 100644 index 0000000..fb62afd --- /dev/null +++ b/C/src/thread_sharing.c @@ -0,0 +1,98 @@ +#include "ascii.h" +#include "capture.h" +#include "thread_sharing.h" + +#include +#include +#include +#include + +// Producer thread for capturing frames +void *capture_thread(void *arg) { + shared_frame_t *sf = arg; + webcam_t cam = {.fd = -1, .buffer = MAP_FAILED}; + + // Intialialize webcam into the thread context + if (webcam_init(&cam, "/dev/video0", sf->width, sf->height) < 0) { + perror("webcam_init in capture thread"); + sf->stop = 1; + return NULL; + } + + int write_idx = 0; + + while (!sf->stop) { + if (webcam_wait_frame(&cam, 100) < 0) { + continue; + } + + // Capture into inactive frame buffer slot + if (webcam_capture_frame(&cam, sf->buf[write_idx]) < 0) { + break; + } + webcam_requeue_buffer(&cam); + + pthread_mutex_lock(&sf->lock); + sf->ready_idx = write_idx; + sf->has_frame = 1; + pthread_cond_signal(&sf->cond); // wake render thread + pthread_mutex_unlock(&sf->lock); + + write_idx ^= 1; // XOR, swap buffers + } + + webcam_cleanup(&cam); + return NULL; +} + +// Producer thread for rendering +void *render_thread(void *arg) { + shared_frame_t *sf = arg; + + // Allocate dynamic buffers + size_t out_size = ascii_out_size(sf->ascii_w, sf->ascii_h, sf->opts.color); + char *out_buf = malloc(out_size); + uint8_t *local_rgb = + sf->opts.color ? malloc(sf->width * sf->height * 3) : NULL; + + if (!out_buf) { + perror("render_thread malloc"); + return NULL; + } + + pthread_mutex_lock(&sf->lock); + while (!sf->stop) { + while (!sf->has_frame && !sf->stop) { + pthread_cond_wait(&sf->cond, &sf->lock); // sleep + } + if (sf->stop) + break; + + int read_idx = sf->ready_idx; + sf->has_frame = 0; + + pthread_mutex_unlock(&sf->lock); + + // Process frame outside locked state + int len = grayscale_to_ascii(sf->buf[read_idx], local_rgb, sf->width, + sf->height, sf->ascii_w, sf->ascii_h, out_buf, + out_size, &sf->opts); + + if (len > 0) { + write(STDOUT_FILENO, "\033[H", 3); // cursor to top-left + write(STDOUT_FILENO, out_buf, (size_t)len); + } + + pthread_mutex_lock(&sf->lock); + } + + pthread_mutex_unlock(&sf->lock); + + // Cleanup memory + free(out_buf); + if (local_rgb) { + free(local_rgb); + } + + return NULL; +} diff --git a/README.md b/README.md index 86d0be5..44d94ea 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # AsciiCam -Ascii video output from your webcam in your terminal. +Ascii video output from webcam in terminal. @@ -12,5 +12,6 @@ Ascii video output from your webcam in your terminal. - [x] Color output - Extract U/V channels, map to ANSI/RGB codes - [ ] Add feature to record and save it in popular video formats like `.mp4`, `.mov` and `.gif`. - [x] Dithering effect. -- [ ] A producer/consumer split with pthread_mutex + pthread_cond and a double-buffer swap would decouple them: one thread talks exclusively to V4L2, the other does ASCII conversion and writes. +- [x] A producer/consumer thread splitting. + - [ ] Migrate from C to Cpp.