ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
encoder.h File Reference

HEVC/H.265 encoder for ASCII art frames using libx265. More...

Go to the source code of this file.

Macros

#define H265_ENCODER_FLAG_KEYFRAME   0x01
 
#define H265_ENCODER_FLAG_SIZE_CHANGE   0x02
 

Typedefs

typedef struct h265_encoder h265_encoder_t
 

Functions

h265_encoder_t * h265_encoder_create (uint16_t initial_width, uint16_t initial_height)
 
void h265_encoder_destroy (h265_encoder_t *encoder)
 
asciichat_error_t h265_encode (h265_encoder_t *encoder, uint16_t width, uint16_t height, const uint8_t *ascii_data, uint8_t *output_buf, size_t *output_size)
 
void h265_encoder_request_keyframe (h265_encoder_t *encoder)
 
asciichat_error_t h265_encoder_flush (h265_encoder_t *encoder, uint8_t *output_buf, size_t *output_size)
 
void h265_encoder_get_stats (h265_encoder_t *encoder, uint64_t *total_frames, uint64_t *keyframes, uint32_t *avg_bitrate)
 

Detailed Description

HEVC/H.265 encoder for ASCII art frames using libx265.

Encodes terminal ASCII grid data using x265 for efficient compression. Handles variable-sized frames by storing dimensions in the encoded packet.

FRAME SIZE CHANGES: When terminal resize occurs (width/height change), the encoder must be reconfigured. This is handled transparently - the encoder detects size changes and reinitializes as needed.

PACKET FORMAT: [flags: u8][width: u16][height: u16][encoded_data: x265]

  • flags: Encoding flags (keyframe, etc.)
  • width: Frame width in characters
  • height: Frame height in characters
  • encoded_data: x265-encoded frame data

Definition in file encoder.h.

Macro Definition Documentation

◆ H265_ENCODER_FLAG_KEYFRAME

#define H265_ENCODER_FLAG_KEYFRAME   0x01

Encoder flags

Definition at line 33 of file encoder.h.

◆ H265_ENCODER_FLAG_SIZE_CHANGE

#define H265_ENCODER_FLAG_SIZE_CHANGE   0x02

Definition at line 34 of file encoder.h.

Typedef Documentation

◆ h265_encoder_t

typedef struct h265_encoder h265_encoder_t

Definition at line 28 of file encoder.h.

Function Documentation

◆ h265_encode()

asciichat_error_t h265_encode ( h265_encoder_t *  encoder,
uint16_t  width,
uint16_t  height,
const uint8_t *  ascii_data,
uint8_t *  output_buf,
size_t *  output_size 
)

Encode an ASCII art frame

The encoder automatically detects size changes and reinitializes when needed. The output packet includes frame dimensions so decoder can reconfigure.

Parameters
encoderEncoder handle
widthCurrent frame width (characters)
heightCurrent frame height (characters)
ascii_dataRaw ASCII character grid (width × height bytes)
output_bufBuffer for encoded output
output_sizeInput: buffer size, Output: actual encoded size
Returns
Error code (ASCIICHAT_OK on success)

OUTPUT PACKET FORMAT: [flags: u8][width: u16][height: u16][x265_data...]

Definition at line 91 of file comprehensive.c.

92 {
93 (void)encoder;
94 (void)width;
95 (void)height;
96 (void)pixel_data;
97 (void)out_data;
98 (void)out_len;
99 return SET_ERRNO(ERROR_NOT_SUPPORTED, "H.265 encoding not supported in WASM");
100}
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
@ ERROR_NOT_SUPPORTED
Definition error_codes.h:74

References ASCIICHAT_OK, EAGAIN, ERROR_INTERNAL, ERROR_MEDIA_DECODE, ERROR_NETWORK_SIZE, ERROR_NOT_SUPPORTED, H265_ENCODER_FLAG_KEYFRAME, H265_ENCODER_FLAG_SIZE_CHANGE, log_debug, log_dev, log_error, log_info, and SET_ERRNO.

Referenced by acip_send_image_frame_h265(), h265_client_capture_and_encode(), and threaded_send_image_frame_h265().

◆ h265_encoder_create()

h265_encoder_t * h265_encoder_create ( uint16_t  initial_width,
uint16_t  initial_height 
)

Create a new x265 encoder for ASCII frames

Parameters
initial_widthInitial frame width (characters)
initial_heightInitial frame height (characters)
Returns
Encoder handle, or NULL on error

Definition at line 55 of file encoder.c.

55 {
56 if (initial_width == 0 || initial_height == 0) {
57 SET_ERRNO(ERROR_MEDIA_INIT, "Frame dimensions must be non-zero");
58 return NULL;
59 }
60
62 if (!enc) {
63 SET_ERRNO(ERROR_MEMORY, "Failed to allocate encoder structure");
64 return NULL;
65 }
66
67 // Find best available HEVC encoder (try by ID first, then by name for specific implementations)
68 const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_HEVC);
69
70 // If generic HEVC encoder not found, try specific implementations by name
71 if (!codec) {
72 codec = avcodec_find_encoder_by_name("libx265");
73 }
74 if (!codec) {
75 codec = avcodec_find_encoder_by_name("hevc_vaapi");
76 }
77 if (!codec) {
78 codec = avcodec_find_encoder_by_name("hevc_videotoolbox");
79 }
80 if (!codec) {
81 codec = avcodec_find_encoder_by_name("hevc_nvenc");
82 }
83 if (!codec) {
84 codec = avcodec_find_encoder_by_name("hevc_qsv");
85 }
86
87 if (!codec) {
88 SET_ERRNO(ERROR_MEDIA_INIT, "HEVC encoder not found");
89 SAFE_FREE(enc);
90 return NULL;
91 }
92
93 enc->codec_ctx = avcodec_alloc_context3(codec);
94 if (!enc->codec_ctx) {
95 SET_ERRNO(ERROR_MEMORY, "Failed to allocate codec context");
96 SAFE_FREE(enc);
97 return NULL;
98 }
99
100 // Configure codec context
101 enc->codec_ctx->width = initial_width;
102 enc->codec_ctx->height = initial_height;
103 enc->codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
104 enc->codec_ctx->time_base = (AVRational){1, 30};
105 enc->codec_ctx->framerate = (AVRational){30, 1};
106
107 // Set ultrafast preset for low-latency encoding
108 if (av_opt_set(enc->codec_ctx->priv_data, "preset", "ultrafast", 0) < 0) {
109 log_warn("Failed to set preset to ultrafast, using default");
110 }
111 if (av_opt_set(enc->codec_ctx->priv_data, "tune", "zerolatency", 0) < 0) {
112 log_warn("Failed to set tune to zerolatency, using default");
113 }
114
115 enc->codec_ctx->thread_count = h265_thread_count();
116
117 // Defer avcodec_open2 to first encode call. The initial resolution (800x600) is
118 // usually wrong — the actual frame resolution is only known when the first capture
119 // arrives. Opening the codec here would create an x265 thread pool (~1s) that gets
120 // immediately discarded on reconfigure, wasting startup time.
121 enc->codec_opened = false;
122
123 // Allocate frame and packet
124 enc->frame = av_frame_alloc();
125 enc->packet = av_packet_alloc();
126
127 if (!enc->frame || !enc->packet) {
128 SET_ERRNO(ERROR_MEMORY, "Failed to allocate frame/packet");
129 if (enc->frame)
130 av_frame_free(&enc->frame);
131 if (enc->packet)
132 av_packet_free(&enc->packet);
133 avcodec_free_context(&enc->codec_ctx);
134 SAFE_FREE(enc);
135 return NULL;
136 }
137
138 enc->current_width = initial_width;
139 enc->current_height = initial_height;
140
141 // Allocate YUV420P buffer (Y plane + U/V planes)
142 size_t stride = initial_width;
143 enc->yuv_buf_size = stride * initial_height * 3 / 2;
144 enc->yuv_buf = SAFE_MALLOC(enc->yuv_buf_size, uint8_t *);
145 if (!enc->yuv_buf) {
146 SET_ERRNO(ERROR_MEMORY, "Failed to allocate YUV buffer");
147 av_frame_free(&enc->frame);
148 av_packet_free(&enc->packet);
149 avcodec_free_context(&enc->codec_ctx);
150 SAFE_FREE(enc);
151 return NULL;
152 }
153
154 log_info("FFmpeg HEVC encoder created: %ux%u (codec: %s)", initial_width, initial_height, codec->name);
155
156 // Register encoder for debugging
157 NAMED_REGISTER_H265_ENCODER(enc, "h265_encoder", NULL);
158
159 return enc;
160}
void h265_encoder_t
#define SAFE_FREE(ptr)
Definition common.h:376
#define SAFE_MALLOC(size, cast)
Definition common.h:264
#define SAFE_CALLOC(count, size, cast)
Definition common.h:274
unsigned char uint8_t
Definition common.h:56
#define NAMED_REGISTER_H265_ENCODER(encoder, name, parent_ptr)
Register an H.265 encoder with automatic format specifier.
@ ERROR_MEMORY
Definition error_codes.h:56
@ ERROR_MEDIA_INIT
Definition error_codes.h:70
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
#define log_info(...)
Log an INFO message.
Definition log/log.h:561

References ERROR_MEDIA_INIT, ERROR_MEMORY, log_info, log_warn, NAMED_REGISTER_H265_ENCODER, SAFE_CALLOC, SAFE_FREE, SAFE_MALLOC, and SET_ERRNO.

◆ h265_encoder_destroy()

void h265_encoder_destroy ( h265_encoder_t *  encoder)

Destroy an x265 encoder

Parameters
encoderEncoder to destroy (may be NULL)

Definition at line 102 of file comprehensive.c.

102 {
103 (void)encoder;
104}

References LOG_IO, and SAFE_FREE.

Referenced by h265_client_context_create(), and h265_client_context_destroy().

◆ h265_encoder_flush()

asciichat_error_t h265_encoder_flush ( h265_encoder_t *  encoder,
uint8_t *  output_buf,
size_t *  output_size 
)

Flush remaining buffered frames from encoder

Sends a NULL frame to the encoder to flush all buffered frames. This should be called before destroying the encoder or when you need to ensure all encoded data is retrieved.

Parameters
encoderEncoder handle
output_bufBuffer for encoded output
output_sizeInput: buffer size, Output: actual encoded size
Returns
Error code (ASCIICHAT_OK on success, ASCIICHAT_OK with size=0 when no more data)

USAGE: // After final h265_encode() call, flush remaining frames while (size > 0) { size = max_size; h265_encoder_flush(encoder, buf, &size); if (size > 0) { // Send the flushed frame... } }

Definition at line 106 of file comprehensive.c.

106 {
107 (void)encoder;
108 (void)out_data;
109 (void)out_len;
110 return ASCIICHAT_OK;
111}
@ ASCIICHAT_OK
Definition error_codes.h:51

References ASCIICHAT_OK, EAGAIN, ERROR_INTERNAL, ERROR_MEDIA_DECODE, ERROR_NETWORK_SIZE, H265_ENCODER_FLAG_KEYFRAME, log_debug, log_dev, log_error, and SET_ERRNO.

Referenced by protocol_stop_connection().

◆ h265_encoder_get_stats()

void h265_encoder_get_stats ( h265_encoder_t *  encoder,
uint64_t *  total_frames,
uint64_t *  keyframes,
uint32_t *  avg_bitrate 
)

Get encoder statistics

Parameters
encoderEncoder handle
total_framesOutput: total frames encoded
keyframesOutput: total keyframes encoded
avg_bitrateOutput: average bitrate in bits per second

Definition at line 464 of file encoder.c.

465 {
466 if (!encoder)
467 return;
468
469 if (total_frames)
470 *total_frames = encoder->total_frames;
471 if (keyframes)
472 *keyframes = encoder->keyframes;
473 if (avg_bitrate)
474 *avg_bitrate = encoder->avg_bitrate;
475}

Referenced by h265_client_get_stats().

◆ h265_encoder_request_keyframe()

void h265_encoder_request_keyframe ( h265_encoder_t *  encoder)

Request a keyframe on the next encode

Forces the encoder to produce an I-frame (keyframe) on the next call to h265_encoder_encode(). Useful for error recovery or stream synchronization.

Parameters
encoderEncoder handle

Definition at line 113 of file comprehensive.c.

113 {
114 (void)encoder;
115}

Referenced by h265_client_request_keyframe().