arduino-audio-tools
Loading...
Searching...
No Matches
CodecH264.h
Go to the documentation of this file.
1#pragma once
2
5#include "TinyH264Decoder.h"
6#include "TinyH264Encoder.h"
7
20#ifndef H264_DEFAULT_ALLOCATOR
21#ifdef ESP32
22#define H264_DEFAULT_ALLOCATOR tinyh264::PSRAMAllocatorESP32<uint8_t>
23#else
24#define H264_DEFAULT_ALLOCATOR tinyh264::StdAllocator<uint8_t>
25#endif
26#endif
27
28namespace audio_tools {
29
58 public:
59 H264Decoder() { decoder_.setCallback(onFrame, this); }
60
62
64
68 void setOutput(Print &out) { p_out = &out; }
69 void setOutput(VideoOutput &out) { p_out_video = &out; }
70
71
78 void setVideoFormat(VideoFormat format) override {
79 switch (format) {
84 pixel_format = format;
85 break;
86 default:
87 LOGW("H264Decoder: unsupported VideoFormat %d", (int)format);
88 break;
89 }
90 }
91
96 VideoInfo videoInfo() override {
97 VideoInfo info;
98 info.format = pixel_format;
99 info.width = (uint16_t)decoder_.width();
100 info.height = (uint16_t)decoder_.height();
101 return info;
102 }
103
106 void setMaxRefFrames(int n) { decoder_.setMaxRefFrames(n); }
107
110 bool begin() override {
111 decoder_.begin();
112 return true;
113 }
114
116 void end() override { decoder_.end(); }
117
122 size_t write(const uint8_t *data, size_t len) override {
123 decoder_.write(data, len);
124 return len;
125 }
126
129 void flush() override {}
130
133 bool hasError() { return decoder_.hasError(); }
134
137 tinyh264::TinyH264Decoder<H264_DEFAULT_ALLOCATOR> &driver() { return decoder_; }
138
139 protected:
140 tinyh264::TinyH264Decoder<H264_DEFAULT_ALLOCATOR> decoder_;
141 Print *p_out = nullptr;
145
146 static void onFrame(tinyh264::TinyH264Decoder<H264_DEFAULT_ALLOCATOR> &decoder,
147 void *userData) {
148 static_cast<H264Decoder *>(userData)->writeToOutput();
149 }
150
152 if (p_out == nullptr && p_out_video == nullptr) return;
153 size_t w = decoder_.width();
154 size_t h = decoder_.height();
155 size_t n = 0;
156 switch (pixel_format) {
157 case VideoFormat::RGB565: {
158 size_t needed = w * h;
159 if (frame_buffer.size() < needed * 2) {
160 frame_buffer.resize(needed * 2);
161 if (frame_buffer.data() == nullptr) {
162 LOGE("H264Decoder: frame buffer allocation failed (RGB565)");
163 return;
164 }
165 }
166 n = decoder_.toRGB565((uint16_t *)frame_buffer.data(), needed);
167 if (n > 0) writeToOutput(frame_buffer.data(), n * 2);
168 break;
169 }
170 case VideoFormat::RGB666: {
171 size_t needed = w * h * 3;
172 if (frame_buffer.size() < needed) {
173 frame_buffer.resize(needed);
174 if (frame_buffer.data() == nullptr) {
175 LOGE("H264Decoder: frame buffer allocation failed (RGB666)");
176 return;
177 }
178 }
179 n = decoder_.toRGB666(frame_buffer.data(), needed);
180 if (n > 0) writeToOutput(frame_buffer.data(), n);
181 break;
182 }
183 case VideoFormat::RGB888: {
184 size_t needed = w * h * 3;
185 if (frame_buffer.size() < needed) {
186 frame_buffer.resize(needed);
187 if (frame_buffer.data() == nullptr) {
188 LOGE("H264Decoder: frame buffer allocation failed (RGB888)");
189 return;
190 }
191 }
192 n = decoder_.toRGB888(frame_buffer.data(), needed);
193 if (n > 0) writeToOutput(frame_buffer.data(), n);
194 break;
195 }
196 case VideoFormat::I420: {
197 size_t needed = w * h + 2 * (w / 2) * (h / 2);
198 if (frame_buffer.size() < needed) {
199 frame_buffer.resize(needed);
200 if (frame_buffer.data() == nullptr) {
201 LOGE("H264Decoder: frame buffer allocation failed (I420)");
202 return;
203 }
204 }
205 n = decoder_.toYUV420(frame_buffer.data(), needed);
206 if (n > 0) writeToOutput(frame_buffer.data(), n);
207 break;
208 }
209 default:
210 break;
211 }
212 }
213
214 size_t writeToOutput(uint8_t *data, size_t len) {
215 size_t result = 0;
216 if (p_out != nullptr) result = p_out->write((const uint8_t *)data, len);
217 if (p_out_video != nullptr) result += p_out_video->write((const uint8_t *)data, len);
218 return result;
219 }
220};
221
247class H264Encoder : public VideoEncoder {
248 public:
251 static constexpr size_t kDefaultBitstreamBufferSize = 16384;
252
253 H264Encoder(int width = 0, int height = 0, int keyframeInterval = 0)
254 : encoder_(width, height, keyframeInterval) {
255 width_ = width;
256 height_ = height;
257 }
258
260 setOutput(out);
261 }
262
264 setOutput(out);
265 }
266
269 void setOutput(Print &out) override { p_out = &out; }
270 void setOutput(VideoOutput &out) { p_out_video = &out; }
271
279 void setVideoFormat(VideoFormat format) override {
280 switch (format) {
286 input_format = format;
287 break;
288 default:
289 LOGW("H264Encoder: unsupported VideoFormat %d", (int)format);
290 break;
291 }
292 }
293
298 VideoInfo videoInfo() override {
299 VideoInfo info;
301 info.width = (uint16_t)width_;
302 info.height = (uint16_t)height_;
303 return info;
304 }
305
307 void setSize(int width, int height) {
308 width_ = width;
309 height_ = height;
310 encoder_.setSize(width, height);
311 }
313 void setQp(int qp) { encoder_.setQp(qp); }
315 void setTargetBitrate(int bitsPerSecond, double fps) {
316 encoder_.setTargetBitrate(bitsPerSecond, fps);
317 }
319 void setKeyframeInterval(int frames) {
320 encoder_.setKeyframeInterval(frames);
321 }
323 void setStride(int strideY, int strideC) {
324 encoder_.setStride(strideY, strideC);
325 }
327 void setPackedStride(int stride) { encoder_.setPackedStride(stride); }
328
334 void setBitstreamBufferSize(size_t size) {
335 if (size > bitstream.size()) {
336 bitstream.resize(size);
337 if (bitstream.data() == nullptr) {
338 LOGE("H264Encoder: bitstream buffer allocation failed");
339 }
340 }
341 }
342
346 bool begin() override { return begin(false); }
348 bool begin(bool reserveColorConversionScratch) {
349 encoder_.begin(reserveColorConversionScratch);
350 return true;
351 }
353 void end() override { encoder_.end(); }
354
356 int lastQp() const { return encoder_.lastQp(); }
357
367 size_t write(const uint8_t *data, size_t len) override {
368 switch (input_format) {
369 case VideoFormat::I420: {
370 size_t ySize = (size_t)width_ * height_;
371 size_t cSize = (size_t)(width_ / 2) * (height_ / 2);
372 if (len < ySize + 2 * cSize) return 0;
373 const uint8_t *srcY = data;
374 const uint8_t *srcU = data + ySize;
375 const uint8_t *srcV = data + ySize + cSize;
376 return writeOut([&](uint8_t *dst, size_t cap) {
377 return encoder_.encodeFrame(srcY, srcU, srcV, dst, cap);
378 });
379 }
381 return writeOut([&](uint8_t *dst, size_t cap) {
382 return encoder_.encodeFrameYuv422(data, dst, cap);
383 });
385 return writeOut([&](uint8_t *dst, size_t cap) {
386 return encoder_.encodeFrameRgb565((const uint16_t *)data, dst, cap);
387 });
389 return writeOut([&](uint8_t *dst, size_t cap) {
390 return encoder_.encodeFrameRgb666(data, dst, cap);
391 });
393 return writeOut([&](uint8_t *dst, size_t cap) {
394 return encoder_.encodeFrameRgb888(data, dst, cap);
395 });
396 default:
397 return 0;
398 }
399 }
400
403 tinyh264::TinyH264Encoder<H264_DEFAULT_ALLOCATOR> &driver() { return encoder_; }
404
405 protected:
408 static constexpr int kMaxGrowRetries = 4;
409
410 tinyh264::TinyH264Encoder<H264_DEFAULT_ALLOCATOR> encoder_;
411 Print *p_out = nullptr;
415 int width_ = 0;
416 int height_ = 0;
417
418 template <typename Fn>
419 size_t writeOut(Fn encodeInto) {
420 if (p_out == nullptr && p_out_video == nullptr) return 0;
421 if (bitstream.size() == 0) {
423 if (bitstream.data() == nullptr) {
424 LOGE("H264Encoder: bitstream buffer allocation failed");
425 return 0;
426 }
427 }
428 size_t n = encodeInto(bitstream.data(), bitstream.size());
429 for (int attempt = 0; n == 0 && attempt < kMaxGrowRetries; ++attempt) {
431 if (bitstream.data() == nullptr) {
432 LOGE("H264Encoder: bitstream buffer grow failed");
433 return 0;
434 }
435 n = encodeInto(bitstream.data(), bitstream.size());
436 }
437 if (p_out !=nullptr && n > 0) p_out->write(bitstream.data(), n);
438 if (p_out_video !=nullptr && n > 0) p_out_video->write(bitstream.data(), n);
439 return n;
440 }
441};
442
443} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define LOGE(...)
Definition AudioLoggerIDF.h:30
Definition Arduino.h:56
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
H.264 video decoder: wraps TinyH264Decoder (https://github.com/pschatzmann/TinyH264) as a VideoOutput...
Definition CodecH264.h:57
void flush() override
Definition CodecH264.h:129
VideoInfo videoInfo() override
Definition CodecH264.h:96
VideoOutput * p_out_video
Definition CodecH264.h:142
tinyh264::TinyH264Decoder< tinyh264::PSRAMAllocatorESP32< uint8_t > > & driver()
Definition CodecH264.h:137
void writeToOutput()
Definition CodecH264.h:151
void end() override
Releases the decoder's picture buffers - see TinyH264Decoder::end().
Definition CodecH264.h:116
H264Decoder()
Definition CodecH264.h:59
size_t write(const uint8_t *data, size_t len) override
Definition CodecH264.h:122
void setOutput(VideoOutput &out)
Definition CodecH264.h:69
H264Decoder(VideoOutput &out)
Definition CodecH264.h:63
Print * p_out
Definition CodecH264.h:141
VideoFormat pixel_format
Definition CodecH264.h:143
size_t writeToOutput(uint8_t *data, size_t len)
Definition CodecH264.h:214
void setVideoFormat(VideoFormat format) override
Definition CodecH264.h:78
void setMaxRefFrames(int n)
Definition CodecH264.h:106
tinyh264::TinyH264Decoder< tinyh264::PSRAMAllocatorESP32< uint8_t > > decoder_
Definition CodecH264.h:140
H264Decoder(Print &out)
Definition CodecH264.h:61
bool begin() override
Definition CodecH264.h:110
void setOutput(Print &out)
Definition CodecH264.h:68
bool hasError()
Definition CodecH264.h:133
Vector< uint8_t > frame_buffer
Definition CodecH264.h:144
static void onFrame(tinyh264::TinyH264Decoder< tinyh264::PSRAMAllocatorESP32< uint8_t > > &decoder, void *userData)
Definition CodecH264.h:146
H.264 video encoder: wraps TinyH264Encoder (https://github.com/pschatzmann/TinyH264)....
Definition CodecH264.h:247
tinyh264::TinyH264Encoder< tinyh264::PSRAMAllocatorESP32< uint8_t > > & driver()
Definition CodecH264.h:403
void setOutput(Print &out) override
Definition CodecH264.h:269
VideoInfo videoInfo() override
Definition CodecH264.h:298
Vector< uint8_t > bitstream
Definition CodecH264.h:413
void setBitstreamBufferSize(size_t size)
Definition CodecH264.h:334
H264Encoder(VideoOutput &out)
Definition CodecH264.h:263
VideoFormat input_format
Definition CodecH264.h:414
H264Encoder(int width=0, int height=0, int keyframeInterval=0)
Definition CodecH264.h:253
void setPackedStride(int stride)
See TinyH264Encoder::setPackedStride()
Definition CodecH264.h:327
bool begin(bool reserveColorConversionScratch)
See TinyH264Encoder::begin()
Definition CodecH264.h:348
void setSize(int width, int height)
See TinyH264Encoder::setSize()
Definition CodecH264.h:307
VideoOutput * p_out_video
Definition CodecH264.h:412
int height_
Definition CodecH264.h:416
H264Encoder(Print &out)
Definition CodecH264.h:259
size_t writeOut(Fn encodeInto)
Definition CodecH264.h:419
tinyh264::TinyH264Encoder< tinyh264::PSRAMAllocatorESP32< uint8_t > > encoder_
Definition CodecH264.h:410
void end() override
See TinyH264Encoder::end()
Definition CodecH264.h:353
size_t write(const uint8_t *data, size_t len) override
Definition CodecH264.h:367
void setTargetBitrate(int bitsPerSecond, double fps)
See TinyH264Encoder::setTargetBitrate()
Definition CodecH264.h:315
static constexpr size_t kDefaultBitstreamBufferSize
Definition CodecH264.h:251
static constexpr int kMaxGrowRetries
Definition CodecH264.h:408
void setQp(int qp)
See TinyH264Encoder::setQp()
Definition CodecH264.h:313
void setOutput(VideoOutput &out)
Definition CodecH264.h:270
Print * p_out
Definition CodecH264.h:411
void setVideoFormat(VideoFormat format) override
Definition CodecH264.h:279
int lastQp() const
The QP actually used by the most recent write() call.
Definition CodecH264.h:356
bool begin() override
Definition CodecH264.h:346
void setKeyframeInterval(int frames)
See TinyH264Encoder::setKeyframeInterval()
Definition CodecH264.h:319
int width_
Definition CodecH264.h:415
void setStride(int strideY, int strideC)
See TinyH264Encoder::setStride()
Definition CodecH264.h:323
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(size_t newSize, T value)
Definition Vector.h:266
T * data()
Definition Vector.h:316
int size()
Definition Vector.h:178
Common interface for video decoders (e.g. H264Decoder, H264DecoderESP32S3 - CodecH264....
Definition CodecVideo.h:18
Common interface for video encoders (e.g. H264Encoder, H264EncoderESP32S3 - CodecH264....
Definition CodecVideo.h:59
Definition Video.h:176
Abstract class for video playback. This class is used to assemble a complete video frame in memory....
Definition Video.h:192
virtual size_t write(const uint8_t *data, size_t len)=0
VideoFormat
Video codec/pixel-format identifier, shared by two unrelated uses: the (single) video stream of a con...
Definition Video.h:43
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
Basic video information (width/height/codec/frame size), analogous to AudioInfo - common to both Demu...
Definition Video.h:102
uint16_t height
Frame height in pixels.
Definition Video.h:106
uint16_t width
Frame width in pixels.
Definition Video.h:104
VideoFormat format
Video codec - VideoFormat::UNKNOWN if not (yet) determined.
Definition Video.h:111