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

HEVC/H.265 decoder for ASCII art frames using libde265. More...

Go to the source code of this file.

Macros

#define H265_DECODER_FLAG_KEYFRAME   0x01
 
#define H265_DECODER_FLAG_SIZE_CHANGE   0x02
 

Typedefs

typedef struct h265_decoder h265_decoder_t
 

Functions

h265_decoder_t * h265_decoder_create (void)
 
void h265_decoder_destroy (h265_decoder_t *decoder)
 
asciichat_error_t h265_decode (h265_decoder_t *decoder, const uint8_t *encoded_packet, size_t packet_size, uint16_t *output_width, uint16_t *output_height, uint8_t *output_buf, size_t *output_size)
 
void h265_decoder_get_stats (h265_decoder_t *decoder, uint64_t *total_frames, uint64_t *keyframes, uint16_t *last_width, uint16_t *last_height)
 

Detailed Description

HEVC/H.265 decoder for ASCII art frames using libde265.

Decodes x265-encoded ASCII art frames back into terminal grid data. Automatically reconfigures when frame size changes.

FRAME SIZE CHANGES: The decoder reads width/height from each packet and reconfigures as needed. No explicit API call required - handled transparently during decode.

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

Definition in file decoder.h.

Macro Definition Documentation

◆ H265_DECODER_FLAG_KEYFRAME

#define H265_DECODER_FLAG_KEYFRAME   0x01

Decoder flags (from packet)

Definition at line 28 of file decoder.h.

◆ H265_DECODER_FLAG_SIZE_CHANGE

#define H265_DECODER_FLAG_SIZE_CHANGE   0x02

Definition at line 29 of file decoder.h.

Typedef Documentation

◆ h265_decoder_t

typedef struct h265_decoder h265_decoder_t

Definition at line 23 of file decoder.h.

Function Documentation

◆ h265_decode()

asciichat_error_t h265_decode ( h265_decoder_t *  decoder,
const uint8_t *  encoded_packet,
size_t  packet_size,
uint16_t *  output_width,
uint16_t *  output_height,
uint8_t *  output_buf,
size_t *  output_size 
)

Decode an x265-encoded ASCII frame

The decoder reads width/height from the packet and automatically reconfigures when frame dimensions change.

Parameters
decoderDecoder handle
encoded_packetEncoded packet (flags+width+height+x265_data)
packet_sizeSize of encoded packet
output_widthOutput: decoded frame width
output_heightOutput: decoded frame height
output_bufBuffer for decoded ASCII data (should be at least width×height)
output_sizeInput: buffer size, Output: actual decoded size
Returns
Error code (ASCIICHAT_OK on success)

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

Call this as: uint16_t width, height; uint8_t ascii_grid[256*64]; size_t decoded_size = sizeof(ascii_grid); h265_decode(decoder, packet, packet_size, &width, &height, ascii_grid, &decoded_size);

Definition at line 109 of file decoder.c.

111 {
112 if (!decoder || !encoded_packet || !output_width || !output_height || !output_buf || !output_size) {
113 return SET_ERRNO(ERROR_INTERNAL, "Invalid decoder arguments");
114 }
115
116 if (packet_size < 5) {
117 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Packet too small (minimum 5 bytes)");
118 }
119
120 // Parse header
121 uint8_t flags = encoded_packet[0];
122 uint16_t width = ((uint16_t)encoded_packet[1] << 8) | encoded_packet[2];
123 uint16_t height = ((uint16_t)encoded_packet[3] << 8) | encoded_packet[4];
124
125 if (width == 0 || height == 0) {
126 return SET_ERRNO(ERROR_NETWORK_PROTOCOL, "Invalid frame dimensions: %ux%u", width, height);
127 }
128
129 size_t required_output = width * height;
130 if (*output_size < required_output) {
131 *output_size = required_output;
132 return SET_ERRNO(ERROR_NETWORK_SIZE, "Output buffer too small: need %zu, have %zu", required_output, *output_size);
133 }
134
135 // Decode HEVC data
136 if (packet_size > 5) {
137 const uint8_t *hevc_data = encoded_packet + 5;
138 size_t hevc_size = packet_size - 5;
139
140 // Send packet to decoder
141 av_packet_from_data(decoder->packet, (uint8_t *)hevc_data, hevc_size);
142
143 if (avcodec_send_packet(decoder->codec_ctx, decoder->packet) < 0) {
144 return SET_ERRNO(ERROR_MEDIA_DECODE, "Failed to send packet to decoder");
145 }
146
147 if (avcodec_receive_frame(decoder->codec_ctx, decoder->frame) < 0) {
148 return SET_ERRNO(ERROR_MEDIA_DECODE, "Failed to receive decoded frame");
149 }
150 } else {
151 // Empty packet - just signal a frame boundary
152 if (avcodec_send_packet(decoder->codec_ctx, NULL) < 0) {
153 return SET_ERRNO(ERROR_MEDIA_DECODE, "Failed to flush decoder");
154 }
155 }
156
157 // Extract Y plane (grayscale intensity)
158 uint8_t *y_plane = decoder->frame->data[0];
159 int y_stride = decoder->frame->linesize[0];
160 int img_width = decoder->frame->width;
161 int img_height = decoder->frame->height;
162
163 if (img_width != (int)width || img_height != (int)height) {
164 log_warn("Image dimensions mismatch: expected %ux%u, got %dx%d", width, height, img_width, img_height);
165 }
166
167 // Copy Y plane to output (ASCII intensity values)
168 for (int y = 0; y < img_height && y < (int)height; y++) {
169 memcpy(output_buf + y * width, y_plane + y * y_stride, width);
170 }
171
172 *output_width = width;
173 *output_height = height;
174 *output_size = width * height;
175
176 decoder->last_width = width;
177 decoder->last_height = height;
178 decoder->total_frames++;
179
180 if (flags & H265_DECODER_FLAG_KEYFRAME) {
181 decoder->keyframes++;
182 }
183
184 return ASCIICHAT_OK;
185}
#define H265_DECODER_FLAG_KEYFRAME
Definition decoder.h:28
unsigned short uint16_t
Definition common.h:57
unsigned char uint8_t
Definition common.h:56
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
@ ERROR_NETWORK_PROTOCOL
Definition error_codes.h:81
@ ASCIICHAT_OK
Definition error_codes.h:51
@ ERROR_MEDIA_DECODE
Definition error_codes.h:72
@ ERROR_NETWORK_SIZE
Definition error_codes.h:82
@ ERROR_INTERNAL
Definition error_codes.h:92
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
AVFrame * frame
Definition decoder.c:20
uint64_t keyframes
Definition decoder.c:28
uint16_t last_width
Definition decoder.c:24
uint64_t total_frames
Definition decoder.c:27
uint16_t last_height
Definition decoder.c:25
AVCodecContext * codec_ctx
Definition decoder.c:19
AVPacket * packet
Definition decoder.c:21

References ASCIICHAT_OK, h265_decoder::codec_ctx, ERROR_INTERNAL, ERROR_MEDIA_DECODE, ERROR_NETWORK_PROTOCOL, ERROR_NETWORK_SIZE, h265_decoder::frame, H265_DECODER_FLAG_KEYFRAME, h265_decoder::keyframes, h265_decoder::last_height, h265_decoder::last_width, log_warn, h265_decoder::packet, SET_ERRNO, and h265_decoder::total_frames.

Referenced by h265_server_decode_and_convert().

◆ h265_decoder_create()

h265_decoder_t * h265_decoder_create ( void  )

Create a new x265 decoder for ASCII frames

Returns
Decoder handle, or NULL on error

Definition at line 31 of file decoder.c.

31 {
33 if (!dec) {
34 SET_ERRNO(ERROR_MEMORY, "Failed to allocate decoder structure");
35 return NULL;
36 }
37
38 // Find HEVC decoder
39 const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_HEVC);
40 if (!codec) {
41 SET_ERRNO(ERROR_MEDIA_INIT, "HEVC decoder not found");
42 SAFE_FREE(dec);
43 return NULL;
44 }
45
46 dec->codec_ctx = avcodec_alloc_context3(codec);
47 if (!dec->codec_ctx) {
48 SET_ERRNO(ERROR_MEMORY, "Failed to allocate codec context");
49 SAFE_FREE(dec);
50 return NULL;
51 }
52
53 // Open decoder (capture x265 library output during initialization)
54 int codec_open_result = 0;
55 LOG_IO("hevc", { codec_open_result = avcodec_open2(dec->codec_ctx, codec, NULL); });
56
57 if (codec_open_result < 0) {
58 SET_ERRNO(ERROR_MEDIA_INIT, "Failed to open HEVC decoder");
59 avcodec_free_context(&dec->codec_ctx);
60 SAFE_FREE(dec);
61 return NULL;
62 }
63
64 // Allocate frame and packet
65 dec->frame = av_frame_alloc();
66 dec->packet = av_packet_alloc();
67 dec->parser = av_parser_init(AV_CODEC_ID_HEVC);
68
69 if (!dec->frame || !dec->packet || !dec->parser) {
70 SET_ERRNO(ERROR_MEMORY, "Failed to allocate frame/packet/parser");
71 if (dec->frame)
72 av_frame_free(&dec->frame);
73 if (dec->packet)
74 av_packet_free(&dec->packet);
75 if (dec->parser)
76 av_parser_close(dec->parser);
77 avcodec_free_context(&dec->codec_ctx);
78 SAFE_FREE(dec);
79 return NULL;
80 }
81
82 log_info("FFmpeg HEVC decoder created");
83
84 // Register decoder for debugging
85 NAMED_REGISTER_H265_DECODER(dec, "h265_decoder", NULL);
86
87 return dec;
88}
#define SAFE_FREE(ptr)
Definition common.h:376
#define SAFE_CALLOC(count, size, cast)
Definition common.h:274
#define NAMED_REGISTER_H265_DECODER(decoder, name, parent_ptr)
Register an H.265 decoder with automatic format specifier.
@ ERROR_MEMORY
Definition error_codes.h:56
@ ERROR_MEDIA_INIT
Definition error_codes.h:70
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
#define LOG_IO(prefix, block)
Capture output from a code block and log it.
Definition io.h:81
AVCodecParserContext * parser
Definition decoder.c:22

References h265_decoder::codec_ctx, ERROR_MEDIA_INIT, ERROR_MEMORY, h265_decoder::frame, log_info, LOG_IO, NAMED_REGISTER_H265_DECODER, h265_decoder::packet, h265_decoder::parser, SAFE_CALLOC, SAFE_FREE, and SET_ERRNO.

Referenced by h265_server_get_client_decoder().

◆ h265_decoder_destroy()

void h265_decoder_destroy ( h265_decoder_t *  decoder)

Destroy an x265 decoder

Parameters
decoderDecoder to destroy (may be NULL)

Definition at line 90 of file decoder.c.

90 {
91 if (!decoder)
92 return;
93
94 if (decoder->frame) {
95 av_frame_free(&decoder->frame);
96 }
97 if (decoder->packet) {
98 av_packet_free(&decoder->packet);
99 }
100 if (decoder->parser) {
101 av_parser_close(decoder->parser);
102 }
103 if (decoder->codec_ctx) {
104 avcodec_free_context(&decoder->codec_ctx);
105 }
106 SAFE_FREE(decoder);
107}

References h265_decoder::codec_ctx, h265_decoder::frame, h265_decoder::packet, h265_decoder::parser, and SAFE_FREE.

Referenced by h265_server_context_destroy(), and h265_server_remove_client().

◆ h265_decoder_get_stats()

void h265_decoder_get_stats ( h265_decoder_t *  decoder,
uint64_t *  total_frames,
uint64_t *  keyframes,
uint16_t *  last_width,
uint16_t *  last_height 
)

Get decoder statistics

Parameters
decoderDecoder handle
total_framesOutput: total frames decoded
keyframesOutput: total keyframes decoded
last_widthOutput: width of last decoded frame
last_heightOutput: height of last decoded frame

Definition at line 187 of file decoder.c.

188 {
189 if (!decoder)
190 return;
191
192 if (total_frames)
193 *total_frames = decoder->total_frames;
194 if (keyframes)
195 *keyframes = decoder->keyframes;
196 if (last_width)
197 *last_width = decoder->last_width;
198 if (last_height)
199 *last_height = decoder->last_height;
200}

References h265_decoder::keyframes, h265_decoder::last_height, h265_decoder::last_width, and h265_decoder::total_frames.

Referenced by h265_server_client_get_stats().