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

📹 Webcam video capture and transmission to server More...

Files

file  capture.c
 ðŸ“¹ Client webcam capture: dedicated capture thread with frame rate limiting and network transmission
 
file  capture.h
 ascii-chat Client Media Capture Management Interface
 

Functions

 __attribute__ ((unused))
 Webcam capture thread handle.
 
int capture_init ()
 Initialize capture subsystem.
 
int capture_start_thread ()
 Start capture thread.
 
void capture_stop_thread ()
 Stop capture thread.
 
bool capture_thread_exited ()
 Check if capture thread has exited.
 
void capture_cleanup ()
 Cleanup capture subsystem.
 

Detailed Description

📹 Webcam video capture and transmission to server

Media Capture

Overview

The media capture subsystem manages webcam video capture, frame compression, and transmission to the server. Supports platform-specific webcam backends and test pattern mode for testing without hardware.

Implementation: src/client/capture.c, src/client/capture.h

Platform Support

Webcam Backends:

Capture Thread

static void *capture_thread_func(void *arg)
{
(void)arg;
// Calculate frame interval for target FPS
uint64_t frame_interval_usec = 1000000 / VIDEO_CAPTURE_FPS;
uint64_t start_time = get_monotonic_time_usec();
// Capture frame from webcam
video_frame_t *frame = webcam_capture();
if (!frame) {
platform_sleep_usec(frame_interval_usec);
continue;
}
// Optional compression
void *send_data = frame->data;
size_t send_size = frame->data_size;
void *compressed_data = NULL;
if (opt_compress) {
compressed_data = compress_frame(frame->data, frame->data_size, &send_size);
if (compressed_data) {
send_data = compressed_data;
}
}
// Send frame to server
send_packet_to_server(PACKET_TYPE_IMAGE_FRAME, send_data, send_size,
if (compressed_data) free(compressed_data);
if (frame->owns_data && frame->data) free(frame->data);
free(frame);
// Rate limiting
platform_sleep_usec(frame_interval_usec);
// Snapshot mode: exit after delay
if (opt_snapshot) {
uint64_t elapsed = (get_monotonic_time_usec() - start_time) / 1000000;
if (elapsed >= opt_snapshot_delay) {
break;
}
}
}
atomic_store(&g_capture_thread_exited, true);
return NULL;
}
void signal_exit()
Signal client to exit.
bool should_exit()
Check if client should exit.
bool server_connection_is_active()
Check if server connection is currently active.
uint32_t server_connection_get_client_id()
Get client ID assigned by server.
unsigned long long uint64_t
Definition common.h:59
@ PACKET_TYPE_IMAGE_FRAME
Complete RGB image with dimensions.
Definition packet.h:288
void platform_sleep_usec(unsigned int usec)
High-precision sleep function with microsecond precision.
ASCIICHAT_API float opt_snapshot_delay
Video frame structure.
void * data
Frame data pointer (points to pre-allocated buffer)

Snapshot Mode

Snapshot mode (--snapshot, --snapshot-delay <seconds>):

  • Useful for testing without continuous streaming
  • --snapshot: Capture single frame and exit
  • --snapshot-delay N: Capture for N seconds then exit
# Single frame test
./bin/ascii-chat client --snapshot
# 5-second test
./bin/ascii-chat client --snapshot --snapshot-delay 5

Test Pattern Mode

Test pattern mode (--test-pattern):

  • Generates synthetic video frames without webcam hardware
  • Useful for testing on Windows or systems without webcam
  • Uses platform-specific test pattern generation
# Use test pattern instead of webcam
./bin/ascii-chat client --test-pattern
See also
src/client/capture.c
src/client/capture.h
lib/video/webcam/webcam.h
Client Overview

Function Documentation

◆ __attribute__()

__attribute__ ( (unused)  )

#include <capture.c>

Webcam capture thread handle.

Thread handle for the background thread that captures video frames from the webcam device. Created during connection establishment, joined during shutdown.

Definition at line 125 of file capture.c.

184 {
185 // Calculate original aspect ratio
186 float img_aspect = (float)original_width / (float)original_height;
187 // Check if image needs resizing
188 if (original_width <= max_width && original_height <= max_height) {
189 // Image is already within bounds - use as-is
190 *result_width = original_width;
191 *result_height = original_height;
192 return;
193 }
194 // Determine scaling factor based on which dimension is the limiting factor
195 if ((float)max_width / (float)max_height > img_aspect) {
196 // Max box is wider than image aspect - scale by height
197 *result_height = max_height;
198 *result_width = (ssize_t)(max_height * img_aspect);
199 } else {
200 // Max box is taller than image aspect - scale by width
201 *result_width = max_width;
202 *result_height = (ssize_t)(max_width / img_aspect);
203 }
204}

◆ capture_cleanup()

void capture_cleanup ( )

#include <capture.c>

Cleanup capture subsystem.

Cleanup capture subsystem

Stops capture thread and cleans up webcam resources. Called during client shutdown.

Definition at line 526 of file capture.c.

526 {
529}
void capture_stop_thread()
Stop capture thread.
Definition capture.c:481
void webcam_cleanup(void)
Clean up global webcam interface.
Definition webcam.c:204

References capture_stop_thread(), and webcam_cleanup().

Referenced by client_crypto_handshake().

◆ capture_init()

int capture_init ( )

#include <capture.c>

Initialize capture subsystem.

Initialize capture subsystem

Sets up webcam device and prepares capture system for operation. Must be called once during client initialization.

Returns
0 on success, negative on error
0 on success, negative on error

Definition at line 428 of file capture.c.

428 {
429 // Initialize webcam capture
430 int webcam_index = GET_OPTION(webcam_index);
431 int result = webcam_init(webcam_index);
432 if (result != 0) {
433 SET_ERRNO(ERROR_WEBCAM, "Failed to initialize webcam (error code: %d)", result);
434 // Preserve specific error code (e.g., WEBCAM vs WEBCAM_IN_USE)
435 return result;
436 }
437 return 0;
438}
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ERROR_WEBCAM
Definition error_codes.h:61
#define GET_OPTION(field)
Safely get a specific option field (lock-free read)
Definition options.h:644
asciichat_error_t webcam_init(unsigned short int webcam_index)
Initialize global webcam interface.
Definition webcam.c:18

References ERROR_WEBCAM, GET_OPTION, SET_ERRNO, and webcam_init().

◆ capture_start_thread()

int capture_start_thread ( )

#include <capture.c>

Start capture thread.

Start capture thread

Creates and starts the webcam capture thread. Also sends stream start notification to server.

Returns
0 on success, negative on error
0 on success, negative on error

Definition at line 449 of file capture.c.

449 {
450 if (THREAD_IS_CREATED(g_capture_thread_created)) {
451 log_warn("Capture thread already created");
452 return 0;
453 }
454
455 // Start webcam capture thread
456 atomic_store(&g_capture_thread_exited, false);
457 if (thread_pool_spawn(g_client_worker_pool, webcam_capture_thread_func, NULL, 2, "webcam_capture") != ASCIICHAT_OK) {
458 SET_ERRNO(ERROR_THREAD, "Webcam capture thread creation failed");
459 LOG_ERRNO_IF_SET("Webcam capture thread creation failed");
460 return -1;
461 }
462
463 g_capture_thread_created = true;
464 log_info("Webcam capture thread created successfully");
465
466 // Notify server we're starting to send video
468 LOG_ERRNO_IF_SET("Failed to send stream start packet");
469 }
470
471 return 0;
472}
#define LOG_ERRNO_IF_SET(message)
Check if any error occurred and log it if so.
thread_pool_t * g_client_worker_pool
Global client worker thread pool.
int threaded_send_stream_start_packet(uint32_t stream_type)
Thread-safe stream start packet transmission.
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_THREAD
Definition error_codes.h:95
#define log_warn(...)
Log a WARN message.
#define log_info(...)
Log an INFO message.
#define STREAM_TYPE_VIDEO
Video stream.
Definition packet.h:829
asciichat_error_t thread_pool_spawn(thread_pool_t *pool, void *(*thread_func)(void *), void *thread_arg, int stop_id, const char *thread_name)
Spawn a worker thread in the pool.
Definition thread_pool.c:65
#define THREAD_IS_CREATED(created_flag)
Definition util/thread.h:62

References ASCIICHAT_OK, ERROR_THREAD, g_client_worker_pool, LOG_ERRNO_IF_SET, log_info, log_warn, SET_ERRNO, STREAM_TYPE_VIDEO, THREAD_IS_CREATED, thread_pool_spawn(), and threaded_send_stream_start_packet().

Referenced by protocol_start_connection().

◆ capture_stop_thread()

void capture_stop_thread ( )

#include <capture.c>

Stop capture thread.

Stop capture thread

Gracefully stops the capture thread and cleans up resources. Safe to call multiple times.

Definition at line 481 of file capture.c.

481 {
482 if (!THREAD_IS_CREATED(g_capture_thread_created)) {
483 return;
484 }
485
486 // Flush webcam to interrupt any blocking ReadSample operations
487 // This allows the capture thread to notice should_exit() and exit cleanly
488 webcam_flush();
489
490 // Wait for thread to exit gracefully
491 int wait_count = 0;
492 while (wait_count < 20 && !atomic_load(&g_capture_thread_exited)) {
493 platform_sleep_usec(100000); // 100ms
494 // Keep flushing in case the thread went back into a blocking read
495 if (wait_count % 5 == 0) {
496 webcam_flush();
497 }
498 wait_count++;
499 }
500
501 if (!atomic_load(&g_capture_thread_exited)) {
502 log_warn("Capture thread not responding after 2 seconds - will be joined by thread pool");
503 }
504
505 // Thread will be joined by thread_pool_stop_all() in protocol_stop_connection()
506 g_capture_thread_created = false;
507}
void webcam_flush(void)
Flush/interrupt any pending webcam read operations.
Definition webcam.c:219

References log_warn, platform_sleep_usec(), THREAD_IS_CREATED, and webcam_flush().

Referenced by capture_cleanup(), and protocol_stop_connection().

◆ capture_thread_exited()

bool capture_thread_exited ( )

#include <capture.c>

Check if capture thread has exited.

Check if capture thread has exited

Returns
true if thread has exited, false otherwise
true if thread exited, false otherwise

Definition at line 515 of file capture.c.

515 {
516 return atomic_load(&g_capture_thread_exited);
517}