10#include <ascii-chat/video/webcam/webcam.h>
11#include <ascii-chat/common.h>
12#include <ascii-chat/options/options.h>
13#include <ascii-chat/video/image.h>
14#include <ascii-chat/platform/string.h>
16static webcam_context_t *global_webcam_ctx = NULL;
17static image_t *cached_webcam_frame = NULL;
18static unsigned int frame_counter = 0;
20asciichat_error_t
webcam_init(
unsigned short int webcam_index) {
22 if (GET_OPTION(test_pattern)) {
23 log_info(
"Test pattern mode enabled - not opening real webcam");
24 log_info(
"Test pattern resolution: 320x240");
29 log_info(
"Initializing webcam with V4L2 (Linux)");
30 log_info(
"Attempting to open webcam with index %d using V4L2 (Linux)...", webcam_index);
31#elif defined(__APPLE__)
32 log_info(
"Initializing webcam with AVFoundation (macOS)");
33 log_info(
"Attempting to open webcam with index %d using AVFoundation (macOS)...", webcam_index);
35 log_info(
"Initializing webcam with Media Foundation (Windows)");
36 log_info(
"Attempting to open webcam with index %d using Media Foundation (Windows)...", webcam_index);
38 log_info(
"Initializing webcam with Unknown platform");
39 log_info(
"Attempting to open webcam with index %d using Unknown platform...", webcam_index);
43 if (result != ASCIICHAT_OK) {
44 SET_ERRNO(result,
"Failed to connect to webcam (error code: %d)", result);
51 log_info(
"Webcam opened successfully! Resolution: %dx%d", width, height);
53 SET_ERRNO(ERROR_WEBCAM,
"Webcam opened but failed to get dimensions");
61 if (GET_OPTION(test_pattern)) {
64 if (!cached_webcam_frame) {
65 cached_webcam_frame =
image_new(320, 240);
66 if (!cached_webcam_frame) {
67 SET_ERRNO(ERROR_MEMORY,
"Failed to allocate test pattern frame");
74 unsigned int animation_phase = frame_counter / 2;
77 for (
int y = 0; y < cached_webcam_frame->h; y++) {
78 for (
int x = 0; x < cached_webcam_frame->w; x++) {
79 rgb_pixel_t *pixel = &cached_webcam_frame->pixels[y * cached_webcam_frame->w + x];
82 int animated_x = (x + animation_phase) % cached_webcam_frame->w;
83 int grid_x = animated_x / 40;
106 if (animated_x % 40 == 0 || y % 30 == 0) {
114 return cached_webcam_frame;
117 if (!global_webcam_ctx) {
118 SET_ERRNO(ERROR_WEBCAM,
"Webcam not initialized - global_webcam_ctx is NULL");
133 if (cached_webcam_frame) {
135 cached_webcam_frame = NULL;
138 if (GET_OPTION(test_pattern)) {
139 log_debug(
"Test pattern mode - webcam context cleanup skipped");
143 if (global_webcam_ctx) {
145 global_webcam_ctx = NULL;
148 log_dev(
"Webcam was not opened, nothing to release");
153 if (GET_OPTION(test_pattern)) {
157 if (global_webcam_ctx) {
168 safe_fprintf(stderr,
"Webcam initialization failed on Linux.\n\n");
170 safe_fprintf(stderr,
" 1. Check if a camera is connected:\n");
172 safe_fprintf(stderr,
" 2. If no camera is available, use test pattern mode:\n");
173 safe_fprintf(stderr,
" ascii-chat client --test-pattern\n\n");
174 safe_fprintf(stderr,
" 3. Install V4L2 drivers if needed:\n");
175 safe_fprintf(stderr,
" sudo apt-get install v4l-utils\n");
176 }
else if (
error_code == ERROR_WEBCAM_PERMISSION) {
179 safe_fprintf(stderr,
" sudo usermod -a -G video $USER\n");
180 safe_fprintf(stderr,
"Then log out and log back in for changes to take effect.\n");
181 }
else if (
error_code == ERROR_WEBCAM_IN_USE) {
182 safe_fprintf(stderr,
"Camera is already in use by another application.\n\n");
183 safe_fprintf(stderr,
"Try closing other camera apps or use test pattern mode:\n");
184 safe_fprintf(stderr,
" ascii-chat client --test-pattern\n");
188 safe_fprintf(stderr,
"* Check camera: ls /dev/video*\n");
189 safe_fprintf(stderr,
"* Check permissions: groups | grep video\n");
190 safe_fprintf(stderr,
"* Use test pattern: ascii-chat client --test-pattern\n");
192 (void)fflush(stderr);
193#elif defined(__APPLE__)
196 safe_fprintf(stderr,
"On macOS, you may need to grant camera permissions:\n");
198 "* Say \"yes\" to the popup about system camera access that you see when running this program for the "
201 stderr,
"* If you said \"no\" to the popup, go to System Preferences > Security & Privacy > Privacy > Camera.\n");
203 " Now flip the switch next to your terminal application in that privacy list to allow ascii-chat to "
204 "access your camera.\n");
205 safe_fprintf(stderr,
" Then just run this program again.\n");
206 (void)fflush(stderr);
211 safe_fprintf(stderr,
"Webcam is already in use by another application.\n");
212 safe_fprintf(stderr,
"Windows allows only one application to access the webcam at a time.\n");
214 safe_fprintf(stderr,
"To use ascii-chat with multiple clients, try these alternatives:\n");
215 safe_fprintf(stderr,
" --test-pattern Generate a colorful test pattern instead of using webcam\n");
216 safe_fprintf(stderr,
" --file VIDEO.mp4 Use a video file as input (to be implemented)\n");
218 safe_fprintf(stderr,
"Example: ascii-chat client --test-pattern\n");
219 (void)fflush(stderr);
223 safe_fprintf(stderr,
"On Windows, this might be because:\n");
224 safe_fprintf(stderr,
"* Camera permissions are not granted\n");
227 (void)fflush(stderr);
232 safe_fprintf(stderr,
"\nWebcam initialization failed on unsupported platform.\n");
233 (void)fflush(stderr);
238#if !defined(__linux__) && !defined(__APPLE__) && !defined(_WIN32)
242 SET_ERRNO(ERROR_WEBCAM,
"Webcam platform not supported on this system");
248 log_warn(
"Webcam cleanup called on unsupported platform");
258 SET_ERRNO(ERROR_WEBCAM,
"Webcam read not supported on this platform");
266 return SET_ERRNO(ERROR_WEBCAM,
"Webcam get dimensions not supported on this platform");
274 return SET_ERRNO(ERROR_WEBCAM,
"Webcam device enumeration not supported on this platform");
asciichat_error_t error_code
int safe_fprintf(FILE *stream, const char *format,...)
Safe formatted output to file stream.
void image_destroy(image_t *p)
image_t * image_new(size_t width, size_t height)
asciichat_error_t webcam_init_context(webcam_context_t **ctx, unsigned short int device_index)
void webcam_free_device_list(webcam_device_info_t *devices)
void webcam_destroy(void)
asciichat_error_t webcam_init(unsigned short int webcam_index)
void webcam_flush_context(webcam_context_t *ctx)
image_t * webcam_read(void)
void webcam_print_init_error_help(asciichat_error_t error_code)
asciichat_error_t webcam_list_devices(webcam_device_info_t **out_devices, unsigned int *out_count)
asciichat_error_t webcam_get_dimensions(webcam_context_t *ctx, int *width, int *height)
image_t * webcam_read_context(webcam_context_t *ctx)
void webcam_cleanup_context(webcam_context_t *ctx)