4
5
6
7
8
9
10
11
12
13
14
15
16
25#include "h264/esp_h264_arduino.h"
26#include "h264/esp_h264_dec.h"
27#include "h264/esp_h264_dec_sw.h"
28#include "h264/esp_h264_dec_param.h"
29#include "h264/esp_h264_types.h"
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77template <
typename Alloc = H264_DEFAULT_ALLOCATOR>
81 static constexpr const char*
TAG =
"H264Decoder";
84
85
86
87
88
89
104 std::function<
void(
const uint8_t* frame_data, uint32_t width, uint32_t height,
109
110
111
112
113
114
115
116
117
118
120 ESP_LOGD(
TAG,
"defaultConfig");
123 cfg.input_buffer_size = 400 * 1024;
124 cfg.output_buffer_size = 640 * 480 * 3 / 2;
125 cfg.max_read_bytes = 1500;
126 cfg.frame_callback =
nullptr;
131
132
133
134
135
136
137
138
139
140
142 ESP_LOGD(
TAG,
"H264Decoder(Stream&)");
146
147
148
149
150
151
152
153
157
158
159
160
161
162
164 ESP_LOGD(
TAG,
"~H264Decoder");
169
170
171
172
173
174
175
176
177
179 ESP_LOGD(
TAG,
"setInputStream");
180 input_stream_ = input_stream;
184
185
186
187
188
189
190
191
192
193
194
195
197 ESP_LOGD(
TAG,
"begin");
199 if (!initDecoder())
return false;
200 if (!initBuffers())
return false;
205
206
207
208
209
210
211
212
213
214
215
216
217
219 ESP_LOGD(
TAG,
"processStream");
220 if (!input_stream_) {
221 ESP_LOGW(
TAG,
"No input stream configured");
225 int available = input_stream_->available();
226 if (available <= 0)
return true;
228 size_t bytes_to_read = cfg_.max_read_bytes > 0 ?
229 std::min((size_t)available, cfg_.max_read_bytes) :
232 if (temp_buf_.size() < bytes_to_read) {
233 temp_buf_.resize(bytes_to_read);
236 size_t bytes_read = input_stream_->readBytes(temp_buf_.data(), bytes_to_read);
237 if (bytes_read > 0) {
238 return decode(temp_buf_.data(), bytes_read);
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259 bool decode(
const uint8_t* h264_data, size_t h264_len) {
260 ESP_LOGD(
TAG,
"decode");
261 if (!dec_handle_ || !h264_data || h264_len == 0)
return false;
263 esp_h264_dec_in_frame_t in_frame{};
264 esp_h264_dec_out_frame_t out_frame{};
267 if (input_buf_.size() < h264_len) {
268 input_buf_.resize(h264_len);
270 memcpy(input_buf_.data(), h264_data, h264_len);
273 in_frame.raw_data.len = h264_len;
284 ESP_LOGW(
TAG,
"Decode error: %d", (
int)res);
296 esp_h264_resolution_t resolution;
298 frame_width_ = resolution
.width;
299 frame_height_ = resolution
.height;
317
318
319
320
321
322
323
325 ESP_LOGD(
TAG,
"hasFrame");
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345 bool getFrame(uint8_t* dst, size_t dst_len, uint32_t& width, uint32_t& height) {
346 ESP_LOGD(
TAG,
"getFrame");
347 if (!frame_ready_ || !dst)
return false;
349 size_t frame_size = frame_width_ * frame_height_ *
352 if (dst_len < frame_size) {
353 ESP_LOGE(TAG,
"Destination buffer too small: need %u got %u",
354 (
unsigned)frame_size, (
unsigned)dst_len);
358 memcpy(dst, output_buf_.data(), frame_size);
359 width = frame_width_;
360 height = frame_height_;
361 frame_ready_ =
false;
367
368
369
370
371
372
373
375 ESP_LOGD(
TAG,
"getFrameCount");
380
381
382
383
384
385
386
388 ESP_LOGD(
TAG,
"getDecodeErrors");
389 return decode_errors_;
393
394
395
396
397
398
399
400
401
403 ESP_LOGD(
TAG,
"getFrameDimensions");
404 if (frame_count_ == 0 || frame_width_ == 0 || frame_height_ == 0)
return false;
405 width = frame_width_;
406 height = frame_height_;
411
412
413
414
415
416
417
418
419
420
422 ESP_LOGD(
TAG,
"end");
426 dec_handle_ =
nullptr;
428 if (!input_buf_.empty()) {
431 if (!output_buf_.empty()) {
434 if (!temp_buf_.empty()) {
437 frame_ready_ =
false;
446 Stream* input_stream_;
448 std::vector<uint8_t, Alloc> input_buf_;
449 std::vector<uint8_t, Alloc> output_buf_;
450 std::vector<uint8_t, Alloc> temp_buf_;
453 uint32_t frame_width_ = 0;
454 uint32_t frame_height_ = 0;
455 bool frame_ready_ =
false;
458 uint32_t frame_count_ = 0;
459 uint32_t decode_errors_ = 0;
462
463
464
465
466
468 ESP_LOGD(
TAG,
"initDecoder");
474 ESP_LOGE(
TAG,
"esp_h264_dec_sw_new failed: %d", (
int)res);
480 ESP_LOGE(
TAG,
"esp_h264_dec_open failed: %d", (
int)res);
482 dec_handle_ =
nullptr;
490
491
492
493
494
496 ESP_LOGD(
TAG,
"initBuffers");
502 input_buf_.resize(cfg_.input_buffer_size);
503 output_buf_.resize(cfg_.output_buffer_size);
504 temp_buf_.resize(cfg_.max_read_bytes > 0 ? cfg_.max_read_bytes : 1500);
505 }
catch (
const std::bad_alloc& e) {
506 ESP_LOGE(
TAG,
"Failed to allocate buffers: %s", e.what());
516
517
518
519
520
521
522
523
524
525
526 bool processDecodedFrame(
const uint8_t* frame_data, uint32_t frame_size) {
527 ESP_LOGD(
TAG,
"processDecodedFrame");
528 if (!frame_data || frame_size == 0)
return false;
531 size_t required_size = frame_width_ * frame_height_ *
534 if (output_buf_.size() < required_size) {
535 output_buf_.resize(required_size);
541 memcpy(output_buf_.data(), frame_data, std::min(frame_size, (uint32_t)output_buf_.size()));
544 if (!convertFormat(frame_data, frame_size)) {
545 ESP_LOGE(
TAG,
"Format conversion failed");
551 if (cfg_.frame_callback) {
552 cfg_.frame_callback(output_buf_.data(), frame_width_, frame_height_, cfg_.output_format);
559
560
561
562
563
564
565
566
567
568
569 bool convertFormat(
const uint8_t* i420_data, uint32_t i420_size) {
570 ESP_LOGD(
TAG,
"convertFormat");
571 switch (cfg_.output_format) {
573 return convertI420ToRGB565(i420_data, i420_size);
578 ESP_LOGE(
TAG,
"Unsupported output format: %d", (
int)cfg_.output_format);
584
585
586
587
588
589
590
591
592
593
594 bool convertI420ToRGB565(
const uint8_t* i420_data, uint32_t i420_size) {
595 ESP_LOGD(
TAG,
"convertI420ToRGB565");
596 if (!i420_data || frame_width_ == 0 || frame_height_ == 0)
return false;
598 const uint8_t* y_plane = i420_data;
599 const uint8_t* u_plane = y_plane + frame_width_ * frame_height_;
600 const uint8_t* v_plane = u_plane + (frame_width_ / 2) * (frame_height_ / 2);
602 uint16_t* rgb565_out = (uint16_t*)output_buf_.data();
604 for (uint32_t y = 0; y < frame_height_; y++) {
605 for (uint32_t x = 0; x < frame_width_; x++) {
607 uint8_t Y = y_plane[y * frame_width_ + x];
608 uint8_t U = u_plane[(y / 2) * (frame_width_ / 2) + (x / 2)];
609 uint8_t V = v_plane[(y / 2) * (frame_width_ / 2) + (x / 2)];
616 int R = (298 * C + 409 * E + 128) >> 8;
617 int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
618 int B = (298 * C + 516 * D + 128) >> 8;
621 R = std::max(0, std::min(255, R));
622 G = std::max(0, std::min(255, G));
623 B = std::max(0, std::min(255, B));
626 uint16_t rgb565 = ((R & 0xF8) << 8) | ((G & 0xFC) << 3) | ((B & 0xF8) >> 3);
627 rgb565_out[y * frame_width_ + x] = rgb565;
636
637
638
639
640
641
642
643
644
645
649
650
651
652
653
654
655
656
657
658
664using namespace esp_h264;
Template class for decoding H.264 streams to raw video frames.
Definition: H264Decoder.h:78
bool getFrame(uint8_t *dst, size_t dst_len, uint32_t &width, uint32_t &height)
Retrieve decoded frame data.
Definition: H264Decoder.h:345
uint32_t getDecodeErrors() const
Get total number of decode errors.
Definition: H264Decoder.h:387
void setInputStream(Stream *input_stream)
Set input stream for H.264 data.
Definition: H264Decoder.h:178
bool decode(const uint8_t *h264_data, size_t h264_len)
Decode H.264 data from buffer.
Definition: H264Decoder.h:259
H264Decoder(Stream &input_stream)
Constructor with input stream.
Definition: H264Decoder.h:141
bool getFrameDimensions(uint32_t &width, uint32_t &height) const
Get current frame dimensions.
Definition: H264Decoder.h:402
bool hasFrame() const
Check if a decoded frame is available.
Definition: H264Decoder.h:324
H264Decoder()
Default constructor (no input stream)
Definition: H264Decoder.h:154
bool begin(Config cfg)
Initialize H.264 decoder and allocate buffers.
Definition: H264Decoder.h:196
void end()
Cleanup and release decoder resources.
Definition: H264Decoder.h:421
bool processStream()
Process H.264 data from configured input stream.
Definition: H264Decoder.h:218
~H264Decoder()
Destructor.
Definition: H264Decoder.h:163
Config defaultConfig()
Create a default configuration with reasonable defaults.
Definition: H264Decoder.h:119
uint32_t getFrameCount() const
Get total number of successfully decoded frames.
Definition: H264Decoder.h:374
static constexpr const char * TAG
Logging tag for ESP32 log system.
Definition: H264Decoder.h:81
esp_h264_err_t esp_h264_dec_process(esp_h264_dec_handle_t dec, esp_h264_dec_in_frame_t *in_frame, esp_h264_dec_out_frame_t *out_frame)
This function performs decoding of H.264 video frames.
Definition: esp_h264_dec.c:19
esp_h264_err_t esp_h264_dec_del(esp_h264_dec_handle_t dec)
This function is used to delete an H.264 decoder.
Definition: esp_h264_dec.c:34
esp_h264_err_t esp_h264_dec_open(esp_h264_dec_handle_t dec)
This function opens an H.264 decoder in stream.
Definition: esp_h264_dec.c:12
esp_h264_err_t esp_h264_dec_close(esp_h264_dec_handle_t dec)
This function closes the H.264 decoder instance specified by dec
Definition: esp_h264_dec.c:27
struct esp_h264_dec_if * esp_h264_dec_handle_t
H.264 stream decoder handle.
Definition: esp_h264_dec.h:25
esp_h264_err_t esp_h264_dec_get_resolution(esp_h264_dec_param_handle_t handle, esp_h264_resolution_t *out_res)
This function retrieves the resolution of the video decoder specified by the handle parameter The dec...
Definition: esp_h264_dec_param.c:12
struct esp_h264_dec_param_if * esp_h264_dec_param_handle_t
It is a pointer to the H.264 decoding parameters structure.
Definition: esp_h264_dec_param.h:18
esp_h264_err_t esp_h264_dec_sw_new(const esp_h264_dec_cfg_sw_t *cfg, esp_h264_dec_handle_t *out_dec)
This function is used to create a new instance of the esp_h264_dec_t data structure,...
Definition: esp_h264_dec_sw.c:94
esp_h264_err_t esp_h264_dec_sw_get_param_hd(esp_h264_dec_handle_t dec, esp_h264_dec_param_sw_handle_t *out_param)
This function returns a pointer to the software-decoded parameter structure associated with the given...
Definition: esp_h264_dec_sw.c:132
esp_h264_dec_cfg_t esp_h264_dec_cfg_sw_t
Configuration type for software-based H.264 decoder.
Definition: esp_h264_dec_sw.h:25
@ ESP_H264_RAW_FMT_I420
Definition: esp_h264_types.h:61
@ ESP_H264_RAW_FMT_RGB565_LE
Definition: esp_h264_types.h:57
#define ESP_H264_GET_BPP_BY_PIC_TYPE(pic_type)
Get bytes per pixel (BPP) by picture type.
Definition: esp_h264_types.h:247
@ ESP_H264_ERR_OK
Definition: esp_h264_types.h:24
Definition: H264Decoder.h:31
Configuration structure for H.264 decoder and output settings.
Definition: H264Decoder.h:90
esp_h264_raw_format_t output_format
Output pixel format after decoding (I420, RGB565, etc.)
Definition: H264Decoder.h:92
size_t max_read_bytes
Maximum bytes to read per processStream() call (0 = read all available)
Definition: H264Decoder.h:101
size_t output_buffer_size
Output buffer size for decoded frame data (bytes)
Definition: H264Decoder.h:98
std::function< void(const uint8_t *frame_data, uint32_t width, uint32_t height, esp_h264_raw_format_t format)> frame_callback
Optional frame callback for real-time processing.
Definition: H264Decoder.h:105
size_t input_buffer_size
Input buffer size for H.264 stream data (bytes)
Definition: H264Decoder.h:95
esp_h264_raw_format_t pic_type
Definition: esp_h264_dec.h:19
esp_h264_pkt_t raw_data
Definition: esp_h264_types.h:228
uint32_t consume
Definition: esp_h264_types.h:229
uint32_t out_size
Definition: esp_h264_types.h:197
uint8_t * outbuf
Definition: esp_h264_types.h:196
uint8_t * buffer
Definition: esp_h264_types.h:100
uint32_t len
Definition: esp_h264_types.h:101
uint16_t height
Definition: esp_h264_types.h:119
uint16_t width
Definition: esp_h264_types.h:110