mirror of
https://github.com/Harshit-Dhanwalkar/AsciiCam.git
synced 2026-06-12 10:35:13 +02:00
Add thread sharing for producer(webcam) and consumer(rendering) threads
This commit is contained in:
parent
319746afe6
commit
c1f0298dae
5 changed files with 122 additions and 3 deletions
|
|
@ -1,7 +1,7 @@
|
|||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -O2 -Iinclude
|
||||
LDFLAGS = -lm
|
||||
# LDFLAGS += -lpthread
|
||||
LDFLAGS += -lpthread
|
||||
|
||||
SRCDIR = src
|
||||
INCDIR = include
|
||||
|
|
|
|||
17
C/include/thread_sharing.h
Normal file
17
C/include/thread_sharing.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#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;
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include "ascii.h"
|
||||
#include "capture.h"
|
||||
#include "timing.h"
|
||||
#include "thread_sharing.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
|
|
@ -10,6 +11,8 @@
|
|||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Defaults
|
||||
#define DEFAULT_ASCII_WIDTH 80
|
||||
|
|
|
|||
98
C/src/thread_sharing.c
Normal file
98
C/src/thread_sharing.c
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#include "ascii.h"
|
||||
#include "capture.h"
|
||||
#include "thread_sharing.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
# AsciiCam
|
||||
Ascii video output from your webcam in your terminal.
|
||||
Ascii video output from webcam in terminal.
|
||||
|
||||
<img src="assets/demo.gif" width="325">
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue