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

FFmpeg HEVC decoder for ASCII art frames. More...

Go to the source code of this file.

Data Structures

struct  h265_decoder
 

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

FFmpeg HEVC decoder for ASCII art frames.

Definition in file decoder.c.

Typedef Documentation

◆ h265_decoder_t

typedef struct h265_decoder h265_decoder_t

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().