arduino-audio-tools
Loading...
Searching...
No Matches
ContainerBinary.h
Go to the documentation of this file.
1
19#pragma once
20#include <string.h>
21
25
26namespace audio_tools {
27
28enum class ContainerType : uint8_t {
29 Header = 1,
30 Audio = 2,
31 Meta = 3,
32 VideoHeader = 4,
33 Video = 5,
34 Undefined = 0
35};
36
38 CommonHeader() = default;
40 this->type = type;
41 this->len = len;
42 }
43 char header[2] = {'\r','\n'};
45 uint16_t len;
46 uint8_t checksum = 0;
47};
48
54
58
62
68
72
73// struct ProcessedResult {
74// ContainerType type = ContainerType::Undefined;
75// // total length incl header
76// int total_len = 0;
77// // processed bytes incl header of last step
78// int processed = 0;
79// // still (total) open
80// int open = 0;
81// };
82
84static uint8_t checkSum(const uint8_t *data, size_t len) {
85 uint8_t result = 0;
86 for (int j = 0; j < len; j++) {
87 result ^= data[j];
88 }
89 return result;
90}
93
105public:
109
110 void setEncoder(AudioEncoder *encoder) { p_codec = encoder; }
111
112 void setOutput(Print &outStream) {
113 LOGD("BinaryContainerEncoder::setOutput");
114 p_out = &outStream;
115 }
116
117 bool begin() override {
118 TRACED();
119 // target.begin();
120 bool rc = p_codec->begin();
122 is_beginning = true;
123 is_video_beginning = true;
124 return rc;
125 }
126
127 void setAudioInfo(AudioInfo info) override {
128 TRACED();
129 if (info != audioInfo()) {
130 cfg.info = info;
131 }
132 }
133
134 AudioInfo audioInfo() override { return cfg.info; }
135
139 TRACED();
141 is_video_beginning = true;
142 }
143
145
147 size_t writeMeta(const uint8_t *data, size_t len) {
148 LOGD("BinaryContainerEncoder::writeMeta: %d", (int)len);
150 uint8_t tmp_array[meta.common.len];
151 memcpy(tmp_array, &meta, sizeof(meta));
152 memcpy(tmp_array + sizeof(meta), data, len);
153 output(tmp_array, meta.common.len);
154 return len;
155 }
156
158 size_t write(const uint8_t *data, size_t len) {
159 LOGD("BinaryContainerEncoder::write: %d", (int)len);
160 if (is_beginning) {
161 writeHeader();
162 is_beginning = false;
163 }
164 writeAudio((uint8_t *)data, len);
165 return len;
166 }
167
172 size_t writeVideo(const uint8_t *data, size_t len) {
173 LOGD("BinaryContainerEncoder::writeVideo: %d", (int)len);
174 if (is_video_beginning) {
176 is_video_beginning = false;
177 }
178 video_dh.common.len = len + sizeof(CommonHeader);
179 video_dh.common.checksum = checkSum(data, len);
180 output((uint8_t *)&video_dh, sizeof(video_dh));
181 output(data, len);
182 return len;
183 }
184
185 void end() { p_codec->end(); }
186
187 operator bool() { return true; };
188
189 virtual const char *mime() { return "audio/binary"; };
190
191protected:
192 uint64_t packet_count = 0;
193 bool is_beginning = true;
202 Print *p_out = nullptr;
203
204 void writeAudio(const uint8_t *data, size_t len) {
205 LOGD("writeAudio: %d", (int)len);
206 // encode data
207 SingleBuffer<uint8_t> tmp_buffer{(int)len};
208 QueueStream<uint8_t> tmp{tmp_buffer};
209 tmp.begin();
210 p_codec->setOutput(tmp);
211 p_codec->write(data, len);
212
213 // output of audio data header
214 dh.common.len = tmp.available() + sizeof(CommonHeader);
215 dh.common.checksum = checkSum(tmp_buffer.data(), tmp_buffer.available());
216 output((uint8_t *)&dh, sizeof(dh));
217
218 // output of data
219 output(tmp_buffer.data(), tmp_buffer.available());
220 }
221
222 void writeHeader() {
223 LOGD("writeHeader");
224 output((uint8_t *)&cfg, sizeof(cfg));
225 }
226
228 LOGD("writeVideoHeader");
229 output((uint8_t *)&video_cfg, sizeof(video_cfg));
230 }
231
232 size_t output(const uint8_t *data, size_t len) {
233 if (p_out != nullptr) {
234 int written = p_out->write((uint8_t *)data, len);
235 LOGD("output: %d -> %d", (int)len, written);
236 } else
237 LOGW("output not defined");
238 return len;
239 }
240};
241
250public:
254
255 void setDecoder(AudioDecoder *decoder){
256 p_codec = decoder;
257 }
258
260 const char *mime() override { return p_codec != nullptr ? p_codec->mime() : "audio/binary"; }
261
262 // Defines the output: this method is called 2 times: first to define
263 // output defined in the EnocdedAudioStream and then to define the
264 // real output in the output chain.
265 void setOutput(Print &outStream) {
266 LOGD("BinaryContainerDecoder::setOutput")
267 p_out = &outStream;
268 }
269
270 void setMetaCallback(void (*callback)(uint8_t*, int, void*)) {
271 meta_callback = callback;
272 }
273
278 LOGD("BinaryContainerDecoder::setOutputVideo");
279 p_out_video = &out;
280 }
282 LOGD("BinaryContainerDecoder::setOutputVideo");
283 p_out_video_video = &out;
284 }
285
288 void setVideoInfoCallback(void (*callback)(VideoInfo info, void* ref)) {
289 video_info_callback = callback;
290 }
291
296
297 bool begin() {
298 TRACED();
299 is_first = true;
300 return true;
301 }
302
303 void end() { TRACED(); }
304
305 size_t write(const uint8_t *data, size_t len) {
306 LOGD("write: %d", (int)len);
307 uint8_t *data8 = (uint8_t *)data;
308 if (buffer.size() < len) {
310 std::max(static_cast<int>(DEFAULT_BUFFER_SIZE + header_size),
311 static_cast<int>(len * 4 + header_size)));
312 }
313
314 size_t result = buffer.writeArray(data8, len);
315 while (parseBuffer())
316 ;
317 return ignore_write_errors ? len : result;
318 }
319
320 operator bool() { return true; };
321
325
327 void setIgnoreWriteErrors(bool flag){
328 ignore_write_errors = flag;
329 }
330
332 void setReference(void* ref){
333 reference = ref;
334 }
335
336protected:
337 bool is_first = true;
339 const size_t header_size = sizeof(header);
342 Print *p_out = nullptr;
343 Print *p_out_video = nullptr;
346 void (*meta_callback)(uint8_t* data, int len, void* ref) = nullptr;
347 void (*video_info_callback)(VideoInfo info, void* ref) = nullptr;
348 void (*error_handler)(BinaryContainerEncoderError error, BinaryContainerDecoder* source, void* ref) = nullptr;
350 void * reference = nullptr;
351
352
353 bool parseBuffer() {
354 LOGD("parseBuffer");
355 bool result = false;
356
357 StrView str{(const char *)buffer.data()};
358 int start = str.indexOf("\r\n");
359 LOGD("start: %d", start);
360 if (start < 0) {
361 return false;
362 }
363 // get next record
364 if (buffer.available() - start > sizeof(header)) {
365 // determine header
366 memmove((uint8_t *)&header, buffer.data() + start, sizeof(header));
367
368 // check header
369 if (!isValidHeader()) {
370 LOGW("invalid header: %d", header.type);
372 nextRecord();
373 return false;
374 };
375
376 if (buffer.available() - start >= header.len) {
377 // move to start of frame
378 buffer.clearArray(start);
379 // process frame
380 result = processData();
381 } else {
382 LOGD("not enough data - available %d / req: %d", buffer.available(),
383 header.len);
385
386 }
387 } else {
388 LOGD("not enough data for header: %d", buffer.available());
390 }
391 return result;
392 }
393
394 // processes the completed data from the buffer: e.g. writes it
395 bool processData() {
396 LOGD("processData");
397 bool rc = false;
398 switch (header.type) {
400 LOGD("Header");
402 buffer.readArray((uint8_t *)&config, sizeof(config));
403 info = config.info;
405 info.logInfo();
407 p_codec->begin();
408 rc = true;
409 } break;
410
412 LOGD("Audio");
413 buffer.clearArray(sizeof(header));
414 int data_len = header.len - header_size;
415 uint8_t crc = checkSum(buffer.data(), data_len);
416 if (header.checksum == crc) {
417 // decode
418 SingleBuffer<uint8_t> tmp_buffer{data_len * 5};
419 QueueStream<uint8_t> tmp{tmp_buffer};
420 tmp.begin();
421 p_codec->setOutput(tmp);
422 p_codec->write(buffer.data(), data_len);
423
424 // output decoded data
425 output(tmp_buffer.data(), tmp_buffer.available());
426 buffer.clearArray(data_len);
427 } else {
428 LOGW("invalid checksum");
430 // move to next record
431 nextRecord();
432 return false;
433 }
434 rc = true;
435 } break;
436
437 case ContainerType::Meta: {
438 LOGD("Meta");
439 buffer.clearArray(sizeof(header));
440 int data_len = header.len - header_size;
441 if (meta_callback != nullptr) {
442 meta_callback(buffer.data(), data_len, reference);
443 }
444 buffer.clearArray(data_len);
445 rc = true;
446 } break;
447
449 LOGD("VideoHeader");
451 buffer.readArray((uint8_t *)&config, sizeof(config));
452 video_info = config.info;
455 rc = true;
456 } break;
457
459 LOGD("Video");
460 buffer.clearArray(sizeof(header));
461 int data_len = header.len - header_size;
462 uint8_t crc = checkSum(buffer.data(), data_len);
463 if (header.checksum == crc) {
464 outputVideo(buffer.data(), data_len);
465 buffer.clearArray(data_len);
466 } else {
467 LOGW("invalid video checksum");
469 // move to next record
470 nextRecord();
471 return false;
472 }
473 rc = true;
474 } break;
475 }
476 return rc;
477 }
478
480 switch (header.type) {
482 return header.checksum == 0;
484 return true;
486 return header.checksum == 0;
488 return header.checksum == 0;
490 return true;
491 }
492 return false;
493 }
494
496 uint8_t byte_value=0;
497 buffer.peek(byte_value);
498 return byte_value;
499 }
500
501 void nextRecord() {
502 TRACED();
503 uint8_t byte_value;
504 while (buffer.available() && peekBufferValue() != '\n')
505 buffer.read(byte_value);
506 }
507
508 // writes the data to the decoder which forwards it to the output; if there
509 // is no coded we write to the output instead
510 size_t output(uint8_t *data, size_t len) {
511 LOGD("output: %d", (int)len);
512 if (p_out != nullptr)
513 p_out->write((uint8_t *)data, len);
514 else
515 LOGW("output not defined");
516
517 return len;
518 }
519
520 // writes a decoded video frame to setOutputVideo()'s target - no codec
521 // is involved (video frames are already-encoded, see writeVideo())
522 size_t outputVideo(uint8_t *data, size_t len) {
523 LOGD("outputVideo: %d", (int)len);
524 if (p_out_video != nullptr)
525 p_out_video->write((uint8_t *)data, len);
526 if (p_out_video_video != nullptr)
527 p_out_video_video->write((uint8_t *)data, len);
528 if (p_out_video == nullptr && p_out_video_video == nullptr)
529 LOGW("output video not defined");
530
531 return len;
532 }
533};
534
535} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
#define TRACED()
Definition AudioLoggerIDF.h:31
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define DEFAULT_BUFFER_SIZE
Definition avr.h:20
minimial implementtion of Meta which just ignores the data
Definition AudioFaustDSP.h:40
Definition Arduino.h:56
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:19
AudioInfo info
Definition AudioCodecsBase.h:80
virtual bool begin(AudioInfo info) override
Definition AudioCodecsBase.h:58
void setAudioInfo(AudioInfo from) override
for most decoders this is not needed
Definition AudioCodecsBase.h:32
virtual void setOutput(AudioStream &out_stream)
Defines where the decoded result is written to.
Definition AudioCodecsBase.h:40
virtual const char * mime()=0
Provides the mime type of the data that is expected by this decoder.
Encoding of PCM data.
Definition AudioCodecsBase.h:101
AudioInfo info
Definition AudioCodecsBase.h:120
void setAudioInfo(AudioInfo from) override
Defines the sample rate, number of channels and bits per sample.
Definition AudioCodecsBase.h:110
virtual void setOutput(Print &out_stream) override
Default output assignment (encoders may override to store Print reference)
Definition AudioCodecsBase.h:113
void notifyAudioChange(AudioInfo info)
Definition AudioTypes.h:175
virtual size_t write(const uint8_t *data, size_t len)=0
virtual void end()=0
virtual bool begin()=0
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:34
Decodes the provided data from the DAT and CFG segments.
Definition ContainerBinary.h:249
void(* error_handler)(BinaryContainerEncoderError error, BinaryContainerDecoder *source, void *ref)
Definition ContainerBinary.h:348
bool ignore_write_errors
Definition ContainerBinary.h:349
size_t outputVideo(uint8_t *data, size_t len)
Definition ContainerBinary.h:522
void setOutputVideo(VideoOutput &out)
Definition ContainerBinary.h:281
void setIgnoreWriteErrors(bool flag)
If set to true we do not expect a retry to write the missing data but continue just with the next....
Definition ContainerBinary.h:327
void(* video_info_callback)(VideoInfo info, void *ref)
Definition ContainerBinary.h:347
void setOutput(Print &outStream)
Defines where the decoded result is written to.
Definition ContainerBinary.h:265
bool is_first
Definition ContainerBinary.h:337
CommonHeader header
Definition ContainerBinary.h:338
void addErrorHandler(void(*error_handler)(BinaryContainerEncoderError error, BinaryContainerDecoder *source, void *ref))
Definition ContainerBinary.h:322
bool begin()
Definition ContainerBinary.h:297
Print * p_out_video
Definition ContainerBinary.h:343
void(* meta_callback)(uint8_t *data, int len, void *ref)
Definition ContainerBinary.h:346
VideoInfo videoInfo()
Definition ContainerBinary.h:295
AudioDecoder * p_codec
Definition ContainerBinary.h:340
size_t output(uint8_t *data, size_t len)
Definition ContainerBinary.h:510
VideoInfo video_info
Definition ContainerBinary.h:345
void setReference(void *ref)
Provide additional information for callback.
Definition ContainerBinary.h:332
BinaryContainerDecoder(AudioDecoder *decoder)
Definition ContainerBinary.h:253
void setMetaCallback(void(*callback)(uint8_t *, int, void *))
Definition ContainerBinary.h:270
void setVideoInfoCallback(void(*callback)(VideoInfo info, void *ref))
Definition ContainerBinary.h:288
Print * p_out
Definition ContainerBinary.h:342
bool isValidHeader()
Definition ContainerBinary.h:479
bool parseBuffer()
Definition ContainerBinary.h:353
SingleBuffer< uint8_t > buffer
Definition ContainerBinary.h:341
void end()
Definition ContainerBinary.h:303
bool processData()
Definition ContainerBinary.h:395
const char * mime() override
Provides the mime type of the wrapped codec, or "audio/binary" if none is set.
Definition ContainerBinary.h:260
void setOutputVideo(Print &out)
Definition ContainerBinary.h:277
const size_t header_size
Definition ContainerBinary.h:339
void setDecoder(AudioDecoder *decoder)
Definition ContainerBinary.h:255
VideoOutput * p_out_video_video
Definition ContainerBinary.h:344
void nextRecord()
Definition ContainerBinary.h:501
void * reference
Definition ContainerBinary.h:350
uint8_t peekBufferValue()
Definition ContainerBinary.h:495
size_t write(const uint8_t *data, size_t len)
Definition ContainerBinary.h:305
BinaryContainerDecoder(AudioDecoder &decoder)
Definition ContainerBinary.h:252
Wraps the encoded data into Config, Data, and Meta segments so that we can recover the audio configur...
Definition ContainerBinary.h:104
AudioEncoder * p_codec
Definition ContainerBinary.h:201
SimpleContainerMetaDataHeader meta
Definition ContainerBinary.h:198
size_t writeVideo(const uint8_t *data, size_t len)
Definition ContainerBinary.h:172
void writeHeader()
Definition ContainerBinary.h:222
size_t writeMeta(const uint8_t *data, size_t len)
Adds meta data segment.
Definition ContainerBinary.h:147
void setOutput(Print &outStream)
Default output assignment (encoders may override to store Print reference)
Definition ContainerBinary.h:112
void setEncoder(AudioEncoder *encoder)
Definition ContainerBinary.h:110
int repeat_header
Definition ContainerBinary.h:195
VideoInfo videoInfo()
Definition ContainerBinary.h:144
virtual const char * mime()
Provides the mime type of the encoded result.
Definition ContainerBinary.h:189
void writeAudio(const uint8_t *data, size_t len)
Definition ContainerBinary.h:204
BinaryContainerEncoder(AudioEncoder &encoder)
Definition ContainerBinary.h:107
size_t output(const uint8_t *data, size_t len)
Definition ContainerBinary.h:232
SimpleContainerVideoDataHeader video_dh
Definition ContainerBinary.h:200
bool is_beginning
Definition ContainerBinary.h:193
Print * p_out
Definition ContainerBinary.h:202
void end()
Definition ContainerBinary.h:185
SimpleContainerDataHeader dh
Definition ContainerBinary.h:197
void setVideoInfo(VideoInfo info)
Definition ContainerBinary.h:138
uint64_t packet_count
Definition ContainerBinary.h:192
bool begin() override
Definition ContainerBinary.h:117
BinaryContainerEncoder(AudioEncoder *encoder)
Definition ContainerBinary.h:108
void setAudioInfo(AudioInfo info) override
Defines the sample rate, number of channels and bits per sample.
Definition ContainerBinary.h:127
SimpleContainerConfig cfg
Definition ContainerBinary.h:196
void writeVideoHeader()
Definition ContainerBinary.h:227
SimpleContainerVideoConfig video_cfg
Definition ContainerBinary.h:199
AudioInfo audioInfo() override
provides the actual input AudioInfo
Definition ContainerBinary.h:134
bool is_video_beginning
Definition ContainerBinary.h:194
size_t write(const uint8_t *data, size_t len)
Add data segment. On first write we also add a AudioInfo header.
Definition ContainerBinary.h:158
Parent class for all container formats.
Definition AudioCodecsBase.h:90
Stream class which stores the data in a temporary queue buffer. The queue can be consumed e....
Definition BaseStream.h:359
virtual bool begin() override
Activates the output.
Definition BaseStream.h:387
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:189
size_t size() override
Definition Buffers.h:320
bool peek(T &result) override
peeks the actual entry from the buffer
Definition Buffers.h:241
bool read(T &result) override
reads a single value
Definition Buffers.h:232
int available() override
provides the number of entries that are available to read
Definition Buffers.h:250
int writeArray(const T data[], int len) override
Fills the buffer data.
Definition Buffers.h:218
T * data()
Provides address of actual data.
Definition Buffers.h:301
bool resize(size_t size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:322
int clearArray(int len) override
consumes len bytes and moves current data to the beginning
Definition Buffers.h:269
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:28
Abstract class for video playback. This class is used to assemble a complete video frame in memory....
Definition Video.h:210
virtual size_t write(const uint8_t *data, size_t len)=0
@ Audio
Definition Video.h:19
@ Video
Definition Video.h:19
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
static uint8_t checkSum(const uint8_t *data, size_t len)
Calculates the checksum.
Definition ContainerBinary.h:84
ContainerType
Definition ContainerBinary.h:28
BinaryContainerEncoderError
Error types.
Definition ContainerBinary.h:92
@ InvalidChecksum
Definition ContainerBinary.h:92
@ InvalidHeader
Definition ContainerBinary.h:92
@ DataMissing
Definition ContainerBinary.h:92
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:51
virtual void logInfo(const char *source="")
Definition AudioTypes.h:122
Definition ContainerBinary.h:37
uint8_t checksum
Definition ContainerBinary.h:46
uint16_t len
Definition ContainerBinary.h:45
char header[2]
Definition ContainerBinary.h:43
CommonHeader(ContainerType type, uint16_t len)
Definition ContainerBinary.h:39
ContainerType type
Definition ContainerBinary.h:44
Definition ContainerBinary.h:49
CommonHeader common
Definition ContainerBinary.h:51
AudioInfo info
Definition ContainerBinary.h:52
Definition ContainerBinary.h:55
CommonHeader common
Definition ContainerBinary.h:56
Definition ContainerBinary.h:59
CommonHeader common
Definition ContainerBinary.h:60
Definition ContainerBinary.h:63
CommonHeader common
Definition ContainerBinary.h:65
VideoInfo info
Definition ContainerBinary.h:66
Definition ContainerBinary.h:69
CommonHeader common
Definition ContainerBinary.h:70
Basic video information (width/height/codec/frame size), analogous to AudioInfo - common to both Demu...
Definition Video.h:121
void logInfo(const char *source="")
Definition Video.h:150