ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
Webcam Module

📷 Cross-platform webcam capture API More...

Files

file  webcam_v4l2.c
 ðŸ“· Linux V4L2 webcam capture implementation with MJPEG/YUY2 format support
 
file  webcam_avfoundation.m
 ðŸ“· macOS AVFoundation webcam capture implementation with hardware acceleration
 
file  webcam_mediafoundation.c
 ðŸ“· Windows Media Foundation webcam capture with hardware acceleration support
 

Data Structures

struct  webcam_device_info_t
 Webcam device information structure. More...
 

Macros

#define WEBCAM_DEVICE_NAME_MAX   256
 Maximum length of webcam device name.
 

Typedefs

typedef struct webcam_context_t webcam_context_t
 Opaque webcam context structure.
 

Functions

asciichat_error_t webcam_list_devices (webcam_device_info_t **devices, unsigned int *count)
 Enumerate available webcam devices.
 
void webcam_free_device_list (webcam_device_info_t *devices)
 Free device list returned by webcam_list_devices()
 
asciichat_error_t webcam_init (unsigned short int webcam_index)
 Initialize global webcam interface.
 
image_twebcam_read (void)
 Capture a frame from global webcam.
 
void webcam_cleanup (void)
 Clean up global webcam interface.
 
void webcam_flush (void)
 Flush/interrupt any pending webcam read operations.
 
void webcam_print_init_error_help (asciichat_error_t error_code)
 Print helpful error diagnostics for webcam initialization failures.
 
asciichat_error_t webcam_init_context (webcam_context_t **ctx, unsigned short int device_index)
 Initialize webcam context for advanced operations.
 
void webcam_cleanup_context (webcam_context_t *ctx)
 Clean up webcam context and release resources.
 
void webcam_flush_context (webcam_context_t *ctx)
 Flush/interrupt pending read operations on webcam context.
 
image_twebcam_read_context (webcam_context_t *ctx)
 Capture a frame from webcam context.
 
asciichat_error_t webcam_get_dimensions (webcam_context_t *ctx, int *width, int *height)
 Get webcam frame dimensions.
 

Detailed Description

📷 Cross-platform webcam capture API

This header provides a cross-platform webcam capture interface for ascii-chat. The system abstracts platform-specific webcam APIs (Windows Media Foundation, Linux V4L2, macOS AVFoundation) behind a unified interface for video frame capture.

CORE FEATURES:

PLATFORM SUPPORT:

ARCHITECTURE:

The webcam system uses a context-based architecture:

VIDEO FORMATS:

The system supports:

Note
The global webcam interface (webcam_init, webcam_read) provides simple single-webcam access. Use context-based functions for advanced multi-webcam scenarios.
Webcam frames are returned as image_t structures compatible with the video conversion pipeline.
Error codes include specific diagnostics for webcam issues (permission denied, device in use, etc.).
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
August 2025

Webcam Capture

Cross-platform webcam capture functionality for Windows, Linux, and macOS.

Overview

The webcam module (lib/video/webcam/) provides cross-platform webcam capture with platform-specific implementations:

  • Webcam capture: Different APIs per platform (AVFoundation, V4L2, Media Foundation)

Platform Implementations

Each platform has its own webcam API with different capabilities and performance:

macOS - AVFoundation

Implementation: lib/video/webcam/macos/webcam_avfoundation.m (Objective-C)

API: AVFoundation framework (modern, recommended by Apple)

  • AVCaptureDevice: Represents physical camera
  • AVCaptureSession: Manages capture pipeline
  • AVCaptureVideoDataOutput: Provides frame callbacks

Capabilities:

  • Supports all built-in and USB webcams
  • Hardware-accelerated video processing
  • Multiple simultaneous capture sessions
  • Automatic format negotiation
  • Native RGB/YUV pixel formats

Supported Resolutions:

  • 640x480 @ 30 FPS (VGA, default)
  • 1280x720 @ 30 FPS (HD)
  • 1920x1080 @ 30 FPS (Full HD, if supported)
  • 3840x2160 @ 30 FPS (4K, if supported)

Pixel Formats:

  • kCVPixelFormatType_24RGB: 24-bit RGB (preferred)
  • kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: NV12 (efficient)
  • Automatic conversion handled by Core Video

Performance:

  • ~5% CPU for 1920x1080 @ 30 FPS capture
  • Zero-copy frame access via CVPixelBuffer
  • Hardware-accelerated color space conversion

Implementation Example:

// Create capture session
AVCaptureSession *session = [[AVCaptureSession alloc] init];
session.sessionPreset = AVCaptureSessionPreset1280x720;
// Get default camera
AVCaptureDevice *camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:camera error:nil];
[session addInput:input];
// Configure output
AVCaptureVideoDataOutput *output = [[AVCaptureVideoDataOutput alloc] init];
output.videoSettings = @{
(id)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_24RGB)
};
// Set frame callback
dispatch_queue_t queue = dispatch_queue_create("webcam", NULL);
[output setSampleBufferDelegate:self queue:queue];
[session addOutput:output];
// Start capture
[session startRunning];

Linux - Video4Linux2 (V4L2)

Implementation: lib/video/webcam/linux/webcam_v4l2.c (C)

API: Video4Linux2 kernel interface (standard Linux video API)

  • Device nodes: /dev/video0, /dev/video1, etc.
  • ioctl-based control interface
  • Memory-mapped I/O for zero-copy capture
  • Support for USB webcams and built-in cameras

Capabilities:

  • Universal Linux webcam support
  • Low-level control over camera settings
  • Efficient memory-mapped buffers (4-8 buffers typical)
  • Select/poll support for async I/O
  • Multiple pixel format support

Supported Pixel Formats:

  • V4L2_PIX_FMT_RGB24: 24-bit RGB (preferred)
  • V4L2_PIX_FMT_YUYV: YUV 4:2:2 (common, requires conversion)
  • V4L2_PIX_FMT_MJPEG: Motion JPEG (requires decoding)
  • V4L2_PIX_FMT_H264: H.264 compressed (requires decoding)

Device Enumeration:

// Find all video devices
for (int i = 0; i < 64; i++) {
char devname[32];
snprintf(devname, sizeof(devname), "/dev/video%d", i);
int fd = open(devname, O_RDWR);
if (fd >= 0) {
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0) {
if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
log_info("Found camera: %s (%s)", cap.card, devname);
}
}
close(fd);
}
}
#define log_info(...)
Log an INFO message.

Memory-Mapped Capture:

// Request buffers
struct v4l2_requestbuffers req = {0};
req.count = 4; // Number of buffers
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl(fd, VIDIOC_REQBUFS, &req);
// Map buffers
struct buffer {
void *start;
size_t length;
} buffers[4];
for (int i = 0; i < req.count; i++) {
struct v4l2_buffer buf = {0};
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ioctl(fd, VIDIOC_QUERYBUF, &buf);
buffers[i].length = buf.length;
buffers[i].start = mmap(NULL, buf.length,
PROT_READ | PROT_WRITE,
MAP_SHARED, fd, buf.m.offset);
}
// Start capture
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd, VIDIOC_STREAMON, &type);
// Dequeue frame
struct v4l2_buffer buf = {0};
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ioctl(fd, VIDIOC_DQBUF, &buf);
// Process frame at buffers[buf.index].start
// ...
// Requeue buffer
ioctl(fd, VIDIOC_QBUF, &buf);
platform_mmap_t mmap
Definition mmap.c:32

Performance:

  • ~3% CPU for 1920x1080 @ 30 FPS capture (RGB)
  • Zero-copy via memory mapping
  • ~10% CPU if YUYV→RGB conversion needed

Windows - Media Foundation

Implementation: lib/video/webcam/windows/webcam_mediafoundation.c (C++)

API: Media Foundation (modern Windows multimedia API, Vista+)

  • IMFMediaSource: Represents camera device
  • IMFSourceReader: Simplified capture interface
  • COM-based object model

Capabilities:

  • Supports all UVC (USB Video Class) webcams
  • Built-in Windows camera app compatibility
  • Hardware-accelerated video processing
  • Automatic format negotiation
  • Native RGB/YUV pixel formats

Supported Pixel Formats:

  • MFVideoFormat_RGB24: 24-bit RGB (preferred)
  • MFVideoFormat_NV12: NV12 YUV (efficient, requires conversion)
  • MFVideoFormat_YUY2: YUY2 422 (common)
  • MFVideoFormat_MJPG: Motion JPEG (requires decoding)

Device Enumeration:

// Initialize COM
CoInitializeEx(NULL, COINIT_MULTITHREADED);
MFStartup(MF_VERSION);
// Enumerate video capture devices
IMFAttributes *attributes = NULL;
MFCreateAttributes(&attributes, 1);
attributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
IMFActivate **devices = NULL;
UINT32 count = 0;
MFEnumDeviceSources(attributes, &devices, &count);
for (UINT32 i = 0; i < count; i++) {
WCHAR *friendly_name = NULL;
UINT32 name_len = 0;
devices[i]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
&friendly_name, &name_len);
log_info("Found camera: %ls", friendly_name);
CoTaskMemFree(friendly_name);
}

Capture with Source Reader:

// Activate device
IMFMediaSource *source = NULL;
devices[0]->ActivateObject(IID_PPV_ARGS(&source));
// Create source reader
IMFSourceReader *reader = NULL;
MFCreateSourceReaderFromMediaSource(source, NULL, &reader);
// Configure output format
IMFMediaType *media_type = NULL;
MFCreateMediaType(&media_type);
media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB24);
MFSetAttributeSize(media_type, MF_MT_FRAME_SIZE, 1920, 1080);
reader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, media_type);
// Read frame
IMFSample *sample = NULL;
DWORD stream_flags = 0;
reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0,
NULL, &stream_flags, NULL, &sample);
if (sample) {
IMFMediaBuffer *buffer = NULL;
sample->ConvertToContiguousBuffer(&buffer);
BYTE *data = NULL;
DWORD length = 0;
buffer->Lock(&data, NULL, &length);
// Process frame data...
buffer->Unlock();
buffer->Release();
sample->Release();
}

Performance:

  • ~4% CPU for 1920x1080 @ 30 FPS capture (RGB)
  • Hardware-accelerated decoding for MJPEG/H.264

Unified Webcam API

ascii-chat provides a unified C API across all platforms:

typedef struct webcam_context webcam_context_t;
// Initialize webcam
webcam_context_t *webcam_init(int device_index, int width, int height, int fps);
// Start capture
// Capture frame (blocking)
asciichat_error_t webcam_capture_frame(webcam_context_t *ctx,
uint8_t **rgb_data,
size_t *data_len);
// Stop capture
// Cleanup
void webcam_destroy(webcam_context_t *ctx);
// List available devices
char** webcam_list_devices(int *count);
unsigned char uint8_t
Definition common.h:56
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
asciichat_error_t webcam_list_devices(webcam_device_info_t **out_devices, unsigned int *out_count)
Enumerate available webcam devices.
Definition webcam.c:336
asciichat_error_t webcam_init(unsigned short int webcam_index)
Initialize global webcam interface.
Definition webcam.c:18
struct webcam_context_t webcam_context_t
Opaque webcam context structure.
Definition webcam.h:153

Usage example:

// Initialize webcam (first device, 1920x1080 @ 30fps)
webcam_context_t *webcam = webcam_init(0, 1920, 1080, 30);
if (!webcam) {
log_error("Failed to initialize webcam");
return ERROR_WEBCAM_INIT;
}
// Start capture
webcam_start(webcam);
// Capture loop
while (running) {
uint8_t *rgb_frame;
size_t frame_len;
asciichat_error_t err = webcam_capture_frame(webcam, &rgb_frame, &frame_len);
if (err == ASCIICHAT_OK) {
// Process frame...
process_frame(rgb_frame, 1920, 1080);
}
}
// Cleanup
webcam_stop(webcam);
webcam_destroy(webcam);
@ ASCIICHAT_OK
Definition error_codes.h:48
#define log_error(...)
Log an ERROR message.

Hardware Detection

CPU capability detection for SIMD optimization:

x86/x86_64:

bool cpu_has_sse2(void); // SSE2 (baseline for x86_64)
bool cpu_has_ssse3(void); // SSSE3
bool cpu_has_avx2(void); // AVX2
bool cpu_has_aes(void); // AES-NI instructions
bool cpu_has_crc32(void); // CRC32 instruction

Implementation uses CPUID instruction:

static void cpuid(uint32_t leaf, uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx) {
__asm__ __volatile__(
"cpuid"
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
: "a"(leaf)
);
}
bool cpu_has_avx2(void) {
uint32_t eax, ebx, ecx, edx;
cpuid(7, &eax, &ebx, &ecx, &edx);
return (ebx & (1 << 5)) != 0; // AVX2 bit
}
unsigned int uint32_t
Definition common.h:58

ARM/ARM64:

bool cpu_has_neon(void); // NEON SIMD
bool cpu_has_sve(void); // Scalable Vector Extension
bool cpu_has_crypto(void); // ARM Crypto Extensions

Implementation reads /proc/cpuinfo on Linux, sysctlbyname on macOS:

#ifdef __APPLE__
bool cpu_has_neon(void) {
// All Apple Silicon has NEON
return true;
}
#elif defined(__linux__)
bool cpu_has_neon(void) {
FILE *f = fopen("/proc/cpuinfo", "r");
char line[256];
while (fgets(line, sizeof(line), f)) {
if (strstr(line, "Features") && strstr(line, "neon")) {
fclose(f);
return true;
}
}
fclose(f);
return false;
}
#endif

Platform-Specific Optimizations

Windows:

  • SetThreadPriority for realtime video/audio threads
  • SetProcessPriorityBoost to disable dynamic priority boost
  • QueryPerformanceCounter for high-resolution timestamps
  • Multimedia Class Scheduler Service (MMCSS) for low-latency audio

macOS:

  • pthread_setschedparam for realtime threads
  • mach_timebase_info for nanosecond timing
  • Metal acceleration for video processing (future)
  • Core Audio low-latency mode

Linux:

  • SCHED_FIFO for realtime scheduling (requires CAP_SYS_NICE)
  • clock_gettime(CLOCK_MONOTONIC) for precise timing
  • memfd_create for anonymous shared memory
  • ALSA period size tuning for low-latency audio
See also
video/webcam/webcam.h
video/webcam/macos/webcam_avfoundation.m
video/webcam/linux/webcam_v4l2.c
video/webcam/windows/webcam_mediafoundation.c

Macro Definition Documentation

◆ WEBCAM_DEVICE_NAME_MAX

#define WEBCAM_DEVICE_NAME_MAX   256

#include <webcam.h>

Maximum length of webcam device name.

Definition at line 77 of file webcam.h.

Typedef Documentation

◆ webcam_context_t

#include <webcam.h>

Opaque webcam context structure.

Forward declaration of webcam context for context-based operations. Context provides per-webcam state management for advanced scenarios.

Note
Use webcam_init_context() to create a new context.
Context must be cleaned up with webcam_cleanup_context().

Definition at line 153 of file webcam.h.

Function Documentation

◆ webcam_cleanup()

void webcam_cleanup ( void  )

#include <webcam.h>

Clean up global webcam interface.

Cleans up the global webcam interface and releases resources. Closes the webcam device and frees all associated memory.

Note
Safe to call multiple times (no-op after first call).
After cleanup, webcam_read() will fail until webcam_init() is called again.

Definition at line 204 of file webcam.c.

204 {
205 if (GET_OPTION(test_pattern)) {
206 log_info("Test pattern mode - no webcam resources to release");
207 return;
208 }
209
210 if (global_webcam_ctx) {
211 webcam_cleanup_context(global_webcam_ctx);
212 global_webcam_ctx = NULL;
213 // log_info("Webcam resources released");
214 } else {
215 log_info("Webcam was not opened, nothing to release");
216 }
217}
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
Definition options.h:644
void webcam_cleanup_context(webcam_context_t *ctx)
Clean up webcam context and release resources.
Definition webcam.c:313

References GET_OPTION, log_info, and webcam_cleanup_context().

Referenced by ascii_read_destroy(), capture_cleanup(), and mirror_main().

◆ webcam_cleanup_context()

void webcam_cleanup_context ( webcam_context_t ctx)

#include <webcam.h>

Clean up webcam context and release resources.

Parameters
ctxWebcam context to clean up (can be NULL)

Cleans up a webcam context and releases all associated resources. Closes the webcam device, frees memory, and invalidates the context.

Note
Safe to call multiple times or with NULL pointer (no-op).
After cleanup, context pointer is invalid and must not be used.

Definition at line 313 of file webcam.c.

313 {
314 (void)ctx;
315 log_warn("Webcam cleanup called on unsupported platform");
316}
#define log_warn(...)
Log a WARN message.

References log_warn.

Referenced by webcam_cleanup().

◆ webcam_flush()

void webcam_flush ( void  )

#include <webcam.h>

Flush/interrupt any pending webcam read operations.

Cancels any blocking ReadSample operations. Call this before stopping the capture thread to allow it to exit cleanly.

Definition at line 219 of file webcam.c.

219 {
220 if (GET_OPTION(test_pattern)) {
221 return; // Test pattern doesn't need flushing
222 }
223
224 if (global_webcam_ctx) {
225 webcam_flush_context(global_webcam_ctx);
226 }
227}
void webcam_flush_context(webcam_context_t *ctx)
Flush/interrupt pending read operations on webcam context.
Definition webcam.c:318

References GET_OPTION, and webcam_flush_context().

Referenced by capture_stop_thread().

◆ webcam_flush_context()

void webcam_flush_context ( webcam_context_t ctx)

#include <webcam.h>

Flush/interrupt pending read operations on webcam context.

Parameters
ctxWebcam context (may be NULL - no-op)

Cancels any blocking read operations. Call before stopping capture thread.

Definition at line 318 of file webcam.c.

318 {
319 (void)ctx;
320 // No-op on unsupported platforms
321}

Referenced by webcam_flush().

◆ webcam_free_device_list()

void webcam_free_device_list ( webcam_device_info_t devices)

#include <webcam.h>

Free device list returned by webcam_list_devices()

Parameters
devicesDevice list to free (can be NULL)

Frees a device list allocated by webcam_list_devices(). Safe to call with NULL pointer (no-op).

Definition at line 344 of file webcam.c.

344 {
345 (void)devices;
346 // No-op on unsupported platforms
347}

Referenced by action_list_webcams().

◆ webcam_get_dimensions()

asciichat_error_t webcam_get_dimensions ( webcam_context_t ctx,
int *  width,
int *  height 
)

#include <webcam.h>

Get webcam frame dimensions.

Parameters
ctxWebcam context (must not be NULL)
widthOutput pointer for frame width (must not be NULL)
heightOutput pointer for frame height (must not be NULL)
Returns
ASCIICHAT_OK on success, error code on failure

Queries the webcam context for current frame dimensions. Returns the width and height in pixels as determined during format negotiation with the webcam hardware.

Note
Dimensions may change if webcam format is renegotiated.
Frame dimensions are set during webcam_init_context().

Definition at line 329 of file webcam.c.

329 {
330 (void)ctx;
331 (void)width;
332 (void)height;
333 return SET_ERRNO(ERROR_WEBCAM, "Webcam get dimensions not supported on this platform");
334}
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ERROR_WEBCAM
Definition error_codes.h:61

References ERROR_WEBCAM, and SET_ERRNO.

Referenced by webcam_init().

◆ webcam_init()

asciichat_error_t webcam_init ( unsigned short int  webcam_index)

#include <webcam.h>

Initialize global webcam interface.

Parameters
webcam_indexWebcam device index (0 for default device)
Returns
ASCIICHAT_OK on success, error code on failure

Initializes the global webcam interface for simple single-webcam access. Opens the specified webcam device and prepares it for frame capture. This is a convenience wrapper around webcam_init_context() for simple single-webcam scenarios.

Note
This function initializes global webcam state.
Use webcam_read() to capture frames after initialization.
Must call webcam_cleanup() when done.
Use webcam_init_context() for advanced multi-webcam scenarios.
Warning
On failure, use webcam_print_init_error_help() for diagnostics.

Definition at line 18 of file webcam.c.

18 {
19 // Check if test pattern mode is enabled
20 if (GET_OPTION(test_pattern)) {
21 log_info("Test pattern mode enabled - not opening real webcam");
22 log_info("Test pattern resolution: 1280x720");
23 return ASCIICHAT_OK;
24 }
25
26#ifdef __linux__
27 log_info("Initializing webcam with V4L2 (Linux)");
28 log_info("Attempting to open webcam with index %d using V4L2 (Linux)...", webcam_index);
29#elif defined(__APPLE__)
30 log_info("Initializing webcam with AVFoundation (macOS)");
31 log_info("Attempting to open webcam with index %d using AVFoundation (macOS)...", webcam_index);
32#elif defined(_WIN32)
33 log_info("Initializing webcam with Media Foundation (Windows)");
34 log_info("Attempting to open webcam with index %d using Media Foundation (Windows)...", webcam_index);
35#else
36 log_info("Initializing webcam with Unknown platform");
37 log_info("Attempting to open webcam with index %d using Unknown platform...", webcam_index);
38#endif
39
40 asciichat_error_t result = webcam_init_context(&global_webcam_ctx, webcam_index);
41 if (result != ASCIICHAT_OK) {
42 SET_ERRNO(result, "Failed to connect to webcam (error code: %d)", result);
43 return result;
44 }
45
46 // Get image dimensions
47 int width, height;
48 if (webcam_get_dimensions(global_webcam_ctx, &width, &height) == ASCIICHAT_OK) {
49 log_info("Webcam opened successfully! Resolution: %dx%d", width, height);
50 } else {
51 SET_ERRNO(ERROR_WEBCAM, "Webcam opened but failed to get dimensions");
52 }
53
54 return result;
55}
asciichat_error_t webcam_init_context(webcam_context_t **ctx, unsigned short int device_index)
Initialize webcam context for advanced operations.
Definition webcam.c:306
asciichat_error_t webcam_get_dimensions(webcam_context_t *ctx, int *width, int *height)
Get webcam frame dimensions.
Definition webcam.c:329

References ASCIICHAT_OK, ERROR_WEBCAM, GET_OPTION, log_info, SET_ERRNO, webcam_get_dimensions(), and webcam_init_context().

Referenced by ascii_read_init(), capture_init(), and mirror_main().

◆ webcam_init_context()

asciichat_error_t webcam_init_context ( webcam_context_t **  ctx,
unsigned short int  device_index 
)

#include <webcam.h>

Initialize webcam context for advanced operations.

Parameters
ctxOutput pointer to webcam context (must not be NULL)
device_indexWebcam device index (0 for default device)
Returns
ASCIICHAT_OK on success, error code on failure

Initializes a new webcam context for context-based webcam management. This allows multiple webcams to be used simultaneously or provides more control over webcam lifecycle. Context must be cleaned up with webcam_cleanup_context() when done.

Note
Context is allocated by this function and must be freed with webcam_cleanup_context().
Use webcam_read_context() to capture frames from this context.
Use webcam_get_dimensions() to query frame dimensions.
Warning
On failure, use webcam_print_init_error_help() for diagnostics.

Definition at line 306 of file webcam.c.

306 {
307 (void)ctx;
308 (void)device_index;
309 SET_ERRNO(ERROR_WEBCAM, "Webcam platform not supported on this system");
310 return ERROR_WEBCAM;
311}

References ERROR_WEBCAM, and SET_ERRNO.

Referenced by webcam_init().

◆ webcam_list_devices()

asciichat_error_t webcam_list_devices ( webcam_device_info_t **  devices,
unsigned int *  count 
)

#include <webcam.h>

Enumerate available webcam devices.

Parameters
devicesOutput pointer to array of device info structures (must not be NULL)
countOutput pointer to number of devices found (must not be NULL)
Returns
ASCIICHAT_OK on success, error code on failure

Enumerates all available webcam devices and returns their information. The devices array is allocated by this function and must be freed with webcam_free_device_list().

Note
On success, *devices will point to a dynamically allocated array.
If no devices are found, *count will be 0 and *devices will be NULL.
Call webcam_free_device_list() to free the returned array.

Example:

webcam_device_info_t *devices = NULL;
unsigned int count = 0;
if (webcam_list_devices(&devices, &count) == ASCIICHAT_OK) {
for (unsigned int i = 0; i < count; i++) {
printf("Device %u: %s\n", devices[i].index, devices[i].name);
}
}
void webcam_free_device_list(webcam_device_info_t *devices)
Free device list returned by webcam_list_devices()
Definition webcam.c:344
Webcam device information structure.
Definition webcam.h:89

Definition at line 336 of file webcam.c.

336 {
337 if (out_devices)
338 *out_devices = NULL;
339 if (out_count)
340 *out_count = 0;
341 return SET_ERRNO(ERROR_WEBCAM, "Webcam device enumeration not supported on this platform");
342}

References ERROR_WEBCAM, and SET_ERRNO.

Referenced by action_list_webcams().

◆ webcam_print_init_error_help()

void webcam_print_init_error_help ( asciichat_error_t  error_code)

#include <webcam.h>

Print helpful error diagnostics for webcam initialization failures.

Parameters
error_codeError code from webcam_init() or webcam_init_context()

Prints human-readable error diagnostics to help diagnose webcam initialization failures. Includes platform-specific troubleshooting advice for common issues (permission denied, device in use, etc.).

Note
This function prints to stderr with detailed diagnostics.
Useful for debugging webcam access issues.

Definition at line 229 of file webcam.c.

229 {
230 // Platform-specific error messages and troubleshooting help
231#ifdef __linux__
232 safe_fprintf(stderr, "\n");
233
234 if (error_code == ERROR_WEBCAM) {
235 safe_fprintf(stderr, "Webcam initialization failed on Linux.\n\n");
236 safe_fprintf(stderr, "Common solutions:\n");
237 safe_fprintf(stderr, " 1. Check if a camera is connected:\n");
238 safe_fprintf(stderr, " ls /dev/video*\n\n");
239 safe_fprintf(stderr, " 2. If no camera is available, use test pattern mode:\n");
240 safe_fprintf(stderr, " ascii-chat client --test-pattern\n\n");
241 safe_fprintf(stderr, " 3. Install V4L2 drivers if needed:\n");
242 safe_fprintf(stderr, " sudo apt-get install v4l-utils\n");
243 } else if (error_code == ERROR_WEBCAM_PERMISSION) {
244 safe_fprintf(stderr, "Camera permission denied.\n\n");
245 safe_fprintf(stderr, "Fix permissions with:\n");
246 safe_fprintf(stderr, " sudo usermod -a -G video $USER\n");
247 safe_fprintf(stderr, "Then log out and log back in for changes to take effect.\n");
248 } else if (error_code == ERROR_WEBCAM_IN_USE) {
249 safe_fprintf(stderr, "Camera is already in use by another application.\n\n");
250 safe_fprintf(stderr, "Try closing other camera apps or use test pattern mode:\n");
251 safe_fprintf(stderr, " ascii-chat client --test-pattern\n");
252 } else {
253 safe_fprintf(stderr, "Webcam error on Linux.\n\n");
254 safe_fprintf(stderr, "General troubleshooting:\n");
255 safe_fprintf(stderr, "* Check camera: ls /dev/video*\n");
256 safe_fprintf(stderr, "* Check permissions: groups | grep video\n");
257 safe_fprintf(stderr, "* Use test pattern: ascii-chat client --test-pattern\n");
258 }
259 (void)fflush(stderr);
260#elif defined(__APPLE__)
261 (void)error_code;
262 safe_fprintf(stderr, "\n");
263 safe_fprintf(stderr, "On macOS, you may need to grant camera permissions:\n");
264 safe_fprintf(stderr,
265 "* Say \"yes\" to the popup about system camera access that you see when running this program for the "
266 "first time.\n");
268 stderr, "* If you said \"no\" to the popup, go to System Preferences > Security & Privacy > Privacy > Camera.\n");
269 safe_fprintf(stderr,
270 " Now flip the switch next to your terminal application in that privacy list to allow ascii-chat to "
271 "access your camera.\n");
272 safe_fprintf(stderr, " Then just run this program again.\n");
273 (void)fflush(stderr);
274#elif defined(_WIN32)
276 // Device is in use by another application - this is a fatal error on Windows
277 safe_fprintf(stderr, "\n");
278 safe_fprintf(stderr, "Webcam is already in use by another application.\n");
279 safe_fprintf(stderr, "Windows allows only one application to access the webcam at a time.\n");
280 safe_fprintf(stderr, "\n");
281 safe_fprintf(stderr, "To use ascii-chat with multiple clients, try these alternatives:\n");
282 safe_fprintf(stderr, " --test-pattern Generate a colorful test pattern instead of using webcam\n");
283 safe_fprintf(stderr, " --file VIDEO.mp4 Use a video file as input (to be implemented)\n");
284 safe_fprintf(stderr, "\n");
285 safe_fprintf(stderr, "Example: ascii-chat client --test-pattern\n");
286 (void)fflush(stderr);
287 } else {
288 // Other webcam errors - general failure
289 safe_fprintf(stderr, "\n");
290 safe_fprintf(stderr, "On Windows, this might be because:\n");
291 safe_fprintf(stderr, "* Camera permissions are not granted\n");
292 safe_fprintf(stderr, "* Camera driver issues\n");
293 safe_fprintf(stderr, "* No webcam device found\n");
294 (void)fflush(stderr);
295 }
296#else
297 // Unknown platform
298 (void)error_code;
299 safe_fprintf(stderr, "\nWebcam initialization failed on unsupported platform.\n");
300 (void)fflush(stderr);
301#endif
302}
asciichat_error_t error_code
@ ERROR_WEBCAM_IN_USE
Definition error_codes.h:62
@ ERROR_WEBCAM_PERMISSION
Definition error_codes.h:63
int safe_fprintf(FILE *stream, const char *format,...)
Safe version of fprintf.

References error_code, ERROR_WEBCAM, ERROR_WEBCAM_IN_USE, ERROR_WEBCAM_PERMISSION, and safe_fprintf().

Referenced by client_main(), and mirror_main().

◆ webcam_read()

image_t * webcam_read ( void  )

#include <webcam.h>

Capture a frame from global webcam.

Returns
Pointer to captured image, or NULL on error

Captures a single video frame from the global webcam interface. Returns an image_t structure containing the frame data in RGB format. The image is automatically converted from native webcam format to RGB.

Note
Returns NULL on error (device disconnected, I/O error, etc.).
Image structure is allocated internally and must NOT be freed by caller.
Subsequent calls reuse the same buffer (frame overwrites previous frame).
Frame rate is limited by webcam hardware and format negotiation.
For context-based operations, use webcam_read_context() instead.

Definition at line 57 of file webcam.c.

57 {
58 // Check if test pattern mode is enabled
59 if (GET_OPTION(test_pattern)) {
60 // Use cached test pattern for 60 FPS performance
61 // Generate once on first call, reuse for subsequent calls
62 static image_t *cached_pattern = NULL;
63 static int frame_counter = 0;
64
65 if (!cached_pattern) {
66 // Generate a colorful test pattern ONCE on first call
67 cached_pattern = image_new(1280, 720);
68 if (!cached_pattern) {
69 SET_ERRNO(ERROR_MEMORY, "Failed to allocate test pattern frame");
70 return NULL;
71 }
72
73 // Generate a simple color bar pattern (FAST - no per-pixel calculations)
74 for (int y = 0; y < cached_pattern->h; y++) {
75 for (int x = 0; x < cached_pattern->w; x++) {
76 rgb_pixel_t *pixel = &cached_pattern->pixels[y * cached_pattern->w + x];
77
78 // Simple color bars (8 vertical sections)
79 int grid_x = x / 160;
80
81 // Base pattern: color bars (no floating-point math)
82 switch (grid_x) {
83 case 0: // Red
84 pixel->r = 255;
85 pixel->g = 0;
86 pixel->b = 0;
87 break;
88 case 1: // Green
89 pixel->r = 0;
90 pixel->g = 255;
91 pixel->b = 0;
92 break;
93 case 2: // Blue
94 pixel->r = 0;
95 pixel->g = 0;
96 pixel->b = 255;
97 break;
98 case 3: // Yellow
99 pixel->r = 255;
100 pixel->g = 255;
101 pixel->b = 0;
102 break;
103 case 4: // Cyan
104 pixel->r = 0;
105 pixel->g = 255;
106 pixel->b = 255;
107 break;
108 case 5: // Magenta
109 pixel->r = 255;
110 pixel->g = 0;
111 pixel->b = 255;
112 break;
113 case 6: // White
114 pixel->r = 255;
115 pixel->g = 255;
116 pixel->b = 255;
117 break;
118 case 7: // Gray gradient
119 default: {
120 uint8_t gray = (uint8_t)((y * 255) / cached_pattern->h);
121 pixel->r = gray;
122 pixel->g = gray;
123 pixel->b = gray;
124 break;
125 }
126 }
127
128 // Add grid lines for visual separation
129 if (x % 160 == 0 || y % 120 == 0) {
130 pixel->r = 0;
131 pixel->g = 0;
132 pixel->b = 0;
133 }
134 }
135 }
136 }
137
138 frame_counter++;
139
140 // Clone the cached pattern for each call (caller owns and frees it)
141 // This is MUCH faster than regenerating the pattern each time
142 image_t *test_frame = image_new(cached_pattern->w, cached_pattern->h);
143 if (!test_frame) {
144 SET_ERRNO(ERROR_MEMORY, "Failed to allocate test pattern frame");
145 return NULL;
146 }
147
148 // Fast memcpy instead of per-pixel loop
149 memcpy(test_frame->pixels, cached_pattern->pixels,
150 (size_t)cached_pattern->w * cached_pattern->h * sizeof(rgb_pixel_t));
151
152 // Apply horizontal flip if requested (same as real webcam)
153 if (GET_OPTION(webcam_flip)) {
154 for (int y = 0; y < test_frame->h; y++) {
155 for (int x = 0; x < test_frame->w / 2; x++) {
156 rgb_pixel_t temp = test_frame->pixels[y * test_frame->w + x];
157 test_frame->pixels[y * test_frame->w + x] = test_frame->pixels[y * test_frame->w + (test_frame->w - 1 - x)];
158 test_frame->pixels[y * test_frame->w + (test_frame->w - 1 - x)] = temp;
159 }
160 }
161 }
162
163 return test_frame;
164 }
165
166 if (!global_webcam_ctx) {
167 SET_ERRNO(ERROR_WEBCAM, "Webcam not initialized - global_webcam_ctx is NULL");
168 return NULL;
169 }
170
171 image_t *frame = webcam_read_context(global_webcam_ctx);
172
173 if (!frame) {
174 return NULL;
175 }
176
177 // Apply horizontal flip if requested
178 if (GET_OPTION(webcam_flip) && frame->w > 1) {
179 // Flip the image horizontally - optimized for large images
180 // Process entire rows to improve cache locality
181 rgb_pixel_t *left = frame->pixels;
182 rgb_pixel_t *right = frame->pixels + frame->w - 1;
183
184 for (int y = 0; y < frame->h; y++) {
185 rgb_pixel_t *row_left = left;
186 rgb_pixel_t *row_right = right;
187
188 // Swap pixels from both ends moving inward
189 for (int x = 0; x < frame->w / 2; x++) {
190 rgb_pixel_t temp = *row_left;
191 *row_left++ = *row_right;
192 *row_right-- = temp;
193 }
194
195 // Move to next row
196 left += frame->w;
197 right += frame->w;
198 }
199 }
200
201 return frame;
202}
@ ERROR_MEMORY
Definition error_codes.h:53
image_t * image_new(size_t width, size_t height)
Create a new image with standard allocation.
Definition video/image.c:36
image_t * webcam_read_context(webcam_context_t *ctx)
Capture a frame from webcam context.
Definition webcam.c:323
Image structure.
int w
Image width in pixels (must be > 0)
int h
Image height in pixels (must be > 0)
rgb_pixel_t * pixels
Pixel data array (width * height RGB pixels, row-major order)

References ERROR_MEMORY, ERROR_WEBCAM, GET_OPTION, image_t::h, image_new(), image_t::pixels, SET_ERRNO, image_t::w, and webcam_read_context().

Referenced by mirror_main().

◆ webcam_read_context()

image_t * webcam_read_context ( webcam_context_t ctx)

#include <webcam.h>

Capture a frame from webcam context.

Parameters
ctxWebcam context (must not be NULL)
Returns
Pointer to captured image, or NULL on error

Captures a single video frame from the specified webcam context. Returns an image_t structure containing the frame data in RGB format. The image is automatically converted from native webcam format to RGB.

Note
Returns NULL on error (device disconnected, I/O error, etc.).
Image structure is allocated internally and must NOT be freed by caller.
Subsequent calls reuse the same buffer (frame overwrites previous frame).
Frame rate is limited by webcam hardware and format negotiation.

Definition at line 323 of file webcam.c.

323 {
324 (void)ctx;
325 SET_ERRNO(ERROR_WEBCAM, "Webcam read not supported on this platform");
326 return NULL;
327}

References ERROR_WEBCAM, and SET_ERRNO.

Referenced by webcam_read().