arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
ContainerAVI.h
1#pragma once
2#include <string.h>
3#include "AudioTools/AudioCodecs/AudioCodecsBase.h"
4#include "AudioTools/CoreAudio/AudioBasic/Str.h"
6#include "AudioTools/Video/Video.h"
7#include "AudioTools/CoreAudio/Buffers.h"
8
9#define LIST_HEADER_SIZE 12
10#define CHUNK_HEADER_SIZE 8
11
12namespace audio_tools {
13
22public:
23 size_t writeArray(uint8_t *data, size_t len) {
24 int to_write = min(availableToWrite(), (size_t)len);
25 memmove(vector.data() + available_byte_count, data, to_write);
26 available_byte_count += to_write;
27 return to_write;
28 }
29 void consume(int size) {
30 memmove(vector.data(), &vector[size], available_byte_count - size);
31 available_byte_count -= size;
32 }
33 void resize(int size) { vector.resize(size + 4); }
34
35 uint8_t *data() { return vector.data(); }
36
37 size_t availableToWrite() { return size() - available_byte_count; }
38
39 size_t available() { return available_byte_count; }
40
41 void clear() {
42 available_byte_count = 0;
43 memset(vector.data(), 0, vector.size());
44 }
45
46 bool isEmpty() { return available_byte_count == 0; }
47
48 size_t size() { return vector.size(); }
49
50 long indexOf(const char *str) {
51 uint8_t *ptr = (uint8_t *)memmem(vector.data(), available_byte_count, str,
52 strlen(str));
53 return ptr == nullptr ? -1l : ptr - vector.data();
54 }
55
56protected:
57 Vector<uint8_t> vector{0};
58 size_t available_byte_count = 0;
59};
60
61using FOURCC = char[4];
62
64 // FOURCC fcc;
65 // uint32_t cb;
66 uint32_t dwMicroSecPerFrame;
67 uint32_t dwMaxBytesPerSec;
68 uint32_t dwPaddingGranularity;
69 uint32_t dwFlags;
70 uint32_t dwTotalFrames;
71 uint32_t dwInitialFrames;
72 uint32_t dwStreams;
73 uint32_t dwSuggestedBufferSize;
74 uint32_t dwWidth;
75 uint32_t dwHeight;
76 uint32_t dwReserved[4];
77};
78
79struct RECT {
80 uint32_t dwWidth;
81 uint32_t dwHeight;
82};
83
85 FOURCC fccType;
86 FOURCC fccHandler;
87 uint32_t dwFlags;
88 uint16_t wPriority;
89 uint16_t wLanguage;
90 uint32_t dwInitialFrames;
91 uint32_t dwScale;
92 uint32_t dwRate;
93 uint32_t dwStart;
94 uint32_t dwLength;
95 uint32_t dwSuggestedBufferSize;
96 uint32_t dwQuality;
97 uint32_t dwSampleSize;
98 RECT rcFrame;
99};
100
102 uint32_t biSize;
103 uint64_t biWidth;
104 uint64_t biHeight;
105 uint16_t biPlanes;
106 uint16_t biBitCount;
107 uint32_t biCompression;
108 uint32_t biSizeImage;
109 uint64_t biXPelsPerMeter;
110 uint64_t biYPelsPerMeter;
111 uint32_t biClrUsed;
112 uint32_t biClrImportant;
113};
114
116 AudioFormat wFormatTag;
117 uint16_t nChannels;
118 uint32_t nSamplesPerSec;
119 uint32_t nAvgBytesPerSec;
120 uint16_t nBlockAlign;
121 uint16_t wBitsPerSample;
122 uint16_t cbSize;
123};
124
125// struct WAVFormat {
126// uint16_t wFormatTag;
127// uint16_t nChannels;
128// uint32_t nSamplesPerSec;
129// uint32_t nAvgBytesPerSec;
130// uint16_t nBlockAlign;
131// };
132
133enum StreamContentType { Audio, Video };
134
135enum ParseObjectType { AVIList, AVIChunk, AVIStreamData };
136
137enum ParseState {
138 ParseHeader,
139 ParseHdrl,
140 ParseAvih,
141 ParseStrl,
142 SubChunkContinue,
143 SubChunk,
144 ParseRec,
145 ParseStrf,
146 AfterStrf,
147 ParseMovi,
148 ParseIgnore,
149};
150/***
151 * @brief Represents a LIST or a CHUNK: The ParseObject represents the
152 * current parsing result. We just keep position information and ids
153 * @author Phil Schatzmann
154 * @copyright GPLv3
155 */
157public:
158 void set(size_t currentPos, StrView id, size_t size, ParseObjectType type) {
159 set(currentPos, id.c_str(), size, type);
160 }
161
162 void set(size_t currentPos, const char *id, size_t size,
163 ParseObjectType type) {
164 object_type = type;
165 data_size = size;
166 start_pos = currentPos;
167 // allign on word
168 if (size % 2 != 0) {
169 data_size++;
170 }
171 end_pos = currentPos + data_size + 4;
172 // save FOURCC
173 if (id != nullptr) {
174 memcpy(chunk_id, id, 4);
175 chunk_id[4] = 0;
176 }
177 open = data_size;
178 }
179 const char *id() { return chunk_id; }
180 size_t size() { return data_size; }
181
182 ParseObjectType type() { return object_type; }
183 bool isValid() {
184 switch (object_type) {
185 case AVIStreamData:
186 return isAudio() || isVideo();
187 case AVIChunk:
188 return open > 0;
189 case AVIList:
190 return true;
191 }
192 return false;
193 }
194
195 // for Chunk
196 AVIMainHeader *asAVIMainHeader(void *ptr) { return (AVIMainHeader *)ptr; }
197 AVIStreamHeader *asAVIStreamHeader(void *ptr) {
198 return (AVIStreamHeader *)ptr;
199 }
200 WAVFormatX *asAVIAudioFormat(void *ptr) { return (WAVFormatX *)ptr; }
201 BitmapInfoHeader *asAVIVideoFormat(void *ptr) {
202 return (BitmapInfoHeader *)ptr;
203 }
204
205 size_t open;
206 size_t end_pos;
207 size_t start_pos;
208 size_t data_size;
209
210 // for AVIStreamData
211 int streamNumber() {
212 return object_type == AVIStreamData ? (chunk_id[1] << 8) | chunk_id[0] : 0;
213 }
214 bool isAudio() {
215 return object_type == AVIStreamData
216 ? chunk_id[2] == 'w' && chunk_id[3] == 'b'
217 : false;
218 }
219 bool isVideoUncompressed() {
220 return object_type == AVIStreamData
221 ? chunk_id[2] == 'd' && chunk_id[3] == 'b'
222 : false;
223 }
224 bool isVideoCompressed() {
225 return object_type == AVIStreamData
226 ? chunk_id[2] == 'd' && chunk_id[3] == 'c'
227 : false;
228 }
229 bool isVideo() { return isVideoCompressed() || isVideoUncompressed(); }
230
231protected:
232 // ParseBuffer data_buffer;
233 char chunk_id[5] = {};
234 ParseObjectType object_type;
235};
236
250public:
251 AVIDecoder(int bufferSize = 1024) {
252 parse_buffer.resize(bufferSize);
253 p_decoder = &copy_decoder;
254 p_output_audio = new EncodedAudioOutput(&copy_decoder);
255 }
256
257 AVIDecoder(AudioDecoder *audioDecoder, VideoOutput *videoOut = nullptr,
258 int bufferSize = 1024) {
259 parse_buffer.resize(bufferSize);
260 p_decoder = audioDecoder;
261 p_output_audio = new EncodedAudioOutput(audioDecoder);
262 if (videoOut != nullptr) {
263 setOutputVideoStream(*videoOut);
264 }
265 }
266
267 ~AVIDecoder() {
268 if (p_output_audio != nullptr)
269 delete p_output_audio;
270 }
271
272 bool begin() override {
273 parse_state = ParseHeader;
274 header_is_avi = false;
275 is_parsing_active = true;
276 current_pos = 0;
277 header_is_avi = false;
278 stream_header_idx = -1;
279 is_metadata_ready = false;
280 return true;
281 }
282
284 virtual void setOutput(Print &out_stream) override {
285 // p_output_audio = &out_stream;
286 p_output_audio->setOutput(&out_stream);
287 }
288
290 void setMute(bool mute) { is_mute = mute; }
291
292 virtual void setOutputVideoStream(VideoOutput &out_stream) {
293 p_output_video = &out_stream;
294 }
295
296 virtual size_t write(const uint8_t *data, size_t len) override {
297 LOGD("write: %d", (int)len);
298 int result = parse_buffer.writeArray((uint8_t *)data, len);
299 if (is_parsing_active) {
300 // we expect the first parse to succeed
301 if (parse()) {
302 // if so we process the parse_buffer
303 while (parse_buffer.available() > 4) {
304 if (!parse())
305 break;
306 }
307 } else {
308 LOGD("Parse Error");
309 parse_buffer.clear();
310 result = len;
311 is_parsing_active = false;
312 }
313 }
314 return result;
315 }
316
317 operator bool() override { return is_parsing_active; }
318
319 void end() override { is_parsing_active = false; };
320
322 AVIMainHeader mainHeader() { return main_header; }
323
325 AVIStreamHeader streamHeader(int idx) { return stream_header[idx]; }
326
328 BitmapInfoHeader aviVideoInfo() { return video_info; };
329
330 const char *videoFormat() { return video_format; }
331
333 WAVFormatX aviAudioInfo() { return audio_info; }
334
336 AudioFormat audioFormat() { return audio_info.wFormatTag; }
337
339 bool isMetadataReady() { return is_metadata_ready; }
342 void setValidationCallback(bool (*cb)(AVIDecoder &avi)) {
343 validation_cb = cb;
344 }
345
347 int videoSeconds() { return video_seconds; }
348
350 void setVideoAudioSync(VideoAudioSync *yourSync) { p_synch = yourSync; }
351
352protected:
353 bool header_is_avi = false;
354 bool is_parsing_active = true;
355 ParseState parse_state = ParseHeader;
356 ParseBuffer parse_buffer;
357 AVIMainHeader main_header;
358 int stream_header_idx = -1;
359 Vector<AVIStreamHeader> stream_header;
360 BitmapInfoHeader video_info;
361 WAVFormatX audio_info;
362 Vector<StreamContentType> content_types;
363 Stack<ParseObject> object_stack;
364 ParseObject current_stream_data;
365 EncodedAudioOutput *p_output_audio = nullptr;
366 VideoOutput *p_output_video = nullptr;
367 long open_subchunk_len = 0;
368 long current_pos = 0;
369 long movi_end_pos = 0;
370 Str spaces;
371 Str str;
372 char video_format[5] = {0};
373 bool is_metadata_ready = false;
374 bool (*validation_cb)(AVIDecoder &avi) = nullptr;
375 bool is_mute = false;
376 CopyDecoder copy_decoder;
377 AudioDecoder *p_decoder = nullptr;
378 int video_seconds = 0;
379 VideoAudioSync defaultSynch;
380 VideoAudioSync *p_synch = &defaultSynch;
381
382 bool isCurrentStreamAudio() {
383 return strncmp(stream_header[stream_header_idx].fccType, "auds", 4) == 0;
384 }
385
386 bool isCurrentStreamVideo() {
387 return strncmp(stream_header[stream_header_idx].fccType, "vids", 4) == 0;
388 }
389
390 // we return true if at least one parse step was successful
391 bool parse() {
392 bool result = true;
393 switch (parse_state) {
394 case ParseHeader: {
395 result = parseHeader();
396 if (result)
397 parse_state = ParseHdrl;
398 } break;
399
400 case ParseHdrl: {
401 ParseObject hdrl = parseList("hdrl");
402 result = hdrl.isValid();
403 if (result) {
404 parse_state = ParseAvih;
405 }
406 } break;
407
408 case ParseAvih: {
409 ParseObject avih = parseChunk("avih");
410 result = avih.isValid();
411 if (result) {
412 main_header = *(avih.asAVIMainHeader(parse_buffer.data()));
413 stream_header.resize(main_header.dwStreams);
414 consume(avih.size());
415 parse_state = ParseStrl;
416 }
417 } break;
418
419 case ParseStrl: {
420 ParseObject strl = parseList("strl");
421 ParseObject strh = parseChunk("strh");
422 stream_header[++stream_header_idx] =
423 *(strh.asAVIStreamHeader(parse_buffer.data()));
424 consume(strh.size());
425 parse_state = ParseStrf;
426 } break;
427
428 case ParseStrf: {
429 ParseObject strf = parseChunk("strf");
430 if (isCurrentStreamAudio()) {
431 audio_info = *(strf.asAVIAudioFormat(parse_buffer.data()));
432 setupAudioInfo();
433 LOGI("audioFormat: %d (%x)", (int)audioFormat(),(int)audioFormat());
434 content_types.push_back(Audio);
435 consume(strf.size());
436 } else if (isCurrentStreamVideo()) {
437 video_info = *(strf.asAVIVideoFormat(parse_buffer.data()));
438 setupVideoInfo();
439 LOGI("videoFormat: %s", videoFormat());
440 content_types.push_back(Video);
441 video_format[4] = 0;
442 consume(strf.size());
443 } else {
444 result = false;
445 }
446 parse_state = AfterStrf;
447 } break;
448
449 case AfterStrf: {
450 // ignore all data until we find a new List
451 int pos = parse_buffer.indexOf("LIST");
452 if (pos >= 0) {
453 consume(pos);
454 ParseObject tmp = tryParseList();
455 if (StrView(tmp.id()).equals("strl")) {
456 parse_state = ParseStrl;
457 } else if (StrView(tmp.id()).equals("movi")) {
458 parse_state = ParseMovi;
459 } else {
460 // e.g. ignore info
461 consume(tmp.size() + LIST_HEADER_SIZE);
462 }
463 } else {
464 // no valid data, so throw it away, we keep the last 4 digits in case
465 // if it contains the beginning of a LIST
466 cleanupStack();
467 consume(parse_buffer.available() - 4);
468 }
469 } break;
470
471 case ParseMovi: {
472 ParseObject movi = tryParseList();
473 if (StrView(movi.id()).equals("movi")) {
474 consume(LIST_HEADER_SIZE);
475 is_metadata_ready = true;
476 if (validation_cb)
477 is_parsing_active = (validation_cb(*this));
478 processStack(movi);
479 movi_end_pos = movi.end_pos;
480 parse_state = SubChunk;
481 // trigger new write
482 result = false;
483 }
484 } break;
485
486 case SubChunk: {
487 // rec is optinal
488 ParseObject hdrl = tryParseList();
489 if (StrView(hdrl.id()).equals("rec")) {
490 consume(CHUNK_HEADER_SIZE);
491 processStack(hdrl);
492 }
493
494 current_stream_data = parseAVIStreamData();
495 parse_state = SubChunkContinue;
496 open_subchunk_len = current_stream_data.open;
497 if (current_stream_data.isVideo()) {
498 LOGI("video:[%d]->[%d]", (int)current_stream_data.start_pos,
499 (int)current_stream_data.end_pos);
500 if (p_output_video != nullptr)
501 p_output_video->beginFrame(current_stream_data.open);
502 } else if (current_stream_data.isAudio()) {
503 LOGI("audio:[%d]->[%d]", (int)current_stream_data.start_pos,
504 (int)current_stream_data.end_pos);
505 } else {
506 LOGW("unknown subchunk at %d", (int)current_pos);
507 }
508
509 } break;
510
511 case SubChunkContinue: {
512 writeData();
513 if (open_subchunk_len == 0) {
514 if (current_stream_data.isVideo() && p_output_video != nullptr) {
515 uint32_t time_used_ms = p_output_video->endFrame();
516 p_synch->delayVideoFrame(main_header.dwMicroSecPerFrame, time_used_ms);
517 }
518 if (tryParseChunk("idx").isValid()) {
519 parse_state = ParseIgnore;
520 } else if (tryParseList("rec").isValid()) {
521 parse_state = ParseRec;
522 } else {
523 if (current_pos >= movi_end_pos) {
524 parse_state = ParseIgnore;
525 } else {
526 parse_state = SubChunk;
527 }
528 }
529 }
530 } break;
531
532 case ParseIgnore: {
533 LOGD("ParseIgnore");
534 parse_buffer.clear();
535 } break;
536
537 default:
538 result = false;
539 break;
540 }
541 return result;
542 }
543
544 void setupAudioInfo() {
545 info.channels = audio_info.nChannels;
546 info.bits_per_sample = audio_info.wBitsPerSample;
547 info.sample_rate = audio_info.nSamplesPerSec;
548 info.logInfo();
549 // adjust the audio info if necessary
550 if (p_decoder != nullptr) {
551 p_decoder->setAudioInfo(info);
552 info = p_decoder->audioInfo();
553 }
554 notifyAudioChange(info);
555 }
556
557 void setupVideoInfo() {
558 memcpy(video_format, stream_header[stream_header_idx].fccHandler, 4);
559 AVIStreamHeader *vh = &stream_header[stream_header_idx];
560 if (vh->dwScale <= 0) {
561 vh->dwScale = 1;
562 }
563 int rate = vh->dwRate / vh->dwScale;
564 video_seconds = rate <= 0 ? 0 : vh->dwLength / rate;
565 LOGI("videoSeconds: %d seconds", video_seconds);
566 }
567
568 void writeData() {
569 long to_write = min((long)parse_buffer.available(), open_subchunk_len);
570 if (current_stream_data.isAudio()) {
571 LOGD("audio %d", (int)to_write);
572 if (!is_mute){
573 p_synch->writeAudio(p_output_audio, parse_buffer.data(), to_write);
574 }
575 open_subchunk_len -= to_write;
576 cleanupStack();
577 consume(to_write);
578 } else if (current_stream_data.isVideo()) {
579 LOGD("video %d", (int)to_write);
580 if (p_output_video != nullptr)
581 p_output_video->write(parse_buffer.data(), to_write);
582 open_subchunk_len -= to_write;
583 cleanupStack();
584 consume(to_write);
585 }
586 }
587
588 // 'RIFF' fileSize fileType (data)
589 bool parseHeader() {
590 bool header_is_avi = false;
591 int headerSize = 12;
592 if (getStr(0, 4).equals("RIFF")) {
593 ParseObject result;
594 uint32_t header_file_size = getInt(4);
595 header_is_avi = getStr(8, 4).equals("AVI ");
596 result.set(current_pos, "AVI ", header_file_size, AVIChunk);
597 processStack(result);
598 consume(headerSize);
599
600 } else {
601 LOGE("parseHeader");
602 }
603 return header_is_avi;
604 }
605
609 ParseObject result;
610 result.set(current_pos, getStr(0, 4), 0, AVIChunk);
611 return result;
612 }
613
616 ParseObject tryParseChunk(const char *id) {
617 ParseObject result;
618 if (getStr(0, 4).equals(id)) {
619 result.set(current_pos, id, 0, AVIChunk);
620 }
621 return result;
622 }
623
624 ParseObject tryParseList(const char *id) {
625 ParseObject result;
626 StrView &list_id = getStr(8, 4);
627 if (list_id.equals(id) && getStr(0, 3).equals("LIST")) {
628 result.set(current_pos, getStr(8, 4), getInt(4), AVIList);
629 }
630 return result;
631 }
632
635 ParseObject result;
636 if (getStr(0, 4).equals("LIST")) {
637 result.set(current_pos, getStr(8, 4), getInt(4), AVIList);
638 }
639 return result;
640 }
641
643 ParseObject parseChunk(const char *id) {
644 ParseObject result;
645 int chunk_size = getInt(4);
646 if (getStr(0, 4).equals(id) && parse_buffer.size() >= chunk_size) {
647 result.set(current_pos, id, chunk_size, AVIChunk);
648 processStack(result);
649 consume(CHUNK_HEADER_SIZE);
650 }
651 return result;
652 }
653
655 ParseObject parseList(const char *id) {
656 ParseObject result;
657 if (getStr(0, 4).equals("LIST") && getStr(8, 4).equals(id)) {
658 int size = getInt(4);
659 result.set(current_pos, id, size, AVIList);
660 processStack(result);
661 consume(LIST_HEADER_SIZE);
662 }
663 return result;
664 }
665
666 ParseObject parseAVIStreamData() {
667 ParseObject result;
668 int size = getInt(4);
669 result.set(current_pos, getStr(0, 4), size, AVIStreamData);
670 if (result.isValid()) {
671 processStack(result);
672 consume(8);
673 }
674 return result;
675 }
676
677 void processStack(ParseObject &result) {
678 cleanupStack();
679 object_stack.push(result);
680 spaces.setChars(' ', object_stack.size());
681 LOGD("%s - %s (%d-%d) size:%d", spaces.c_str(), result.id(),
682 (int)result.start_pos, (int)result.end_pos, (int)result.data_size);
683 }
684
685 void cleanupStack() {
686 ParseObject current;
687 // make sure that we remove the object from the stack of we past the end
688 object_stack.peek(current);
689 while (current.end_pos <= current_pos) {
690 object_stack.pop(current);
691 object_stack.peek(current);
692 }
693 }
694
696 StrView &getStr(int offset, int len) {
697 str.setCapacity(len + 1);
698 const char *data = (const char *)parse_buffer.data();
699 str.copyFrom((data + offset), len, 5);
700
701 return str;
702 }
703
705 uint32_t getInt(int offset) {
706 uint32_t *result = (uint32_t *)(parse_buffer.data() + offset);
707 return *result;
708 }
709
711 void consume(int len) {
712 current_pos += len;
713 parse_buffer.consume(len);
714 }
715};
716
717} // namespace audio_tools
WAV Audio Formats used by Microsoft e.g. in AVI video files.
AVI Container Decoder which can be fed with small chunks of data. The minimum length must be bigger t...
Definition ContainerAVI.h:249
StrView & getStr(int offset, int len)
Provides the string at the indicated byte offset with the indicated length.
Definition ContainerAVI.h:696
ParseObject parseList(const char *id)
We load the indicated list from the current data.
Definition ContainerAVI.h:655
void setVideoAudioSync(VideoAudioSync *yourSync)
Replace the synchronization logic with your implementation.
Definition ContainerAVI.h:350
ParseObject parseChunk(const char *id)
We load the indicated chunk from the current data.
Definition ContainerAVI.h:643
AudioFormat audioFormat()
Provides the audio_info.wFormatTag.
Definition ContainerAVI.h:336
AVIMainHeader mainHeader()
Provides the information from the main header chunk.
Definition ContainerAVI.h:322
int videoSeconds()
Provide the length of the video in seconds.
Definition ContainerAVI.h:347
uint32_t getInt(int offset)
Provides the int32 at the indicated byte offset.
Definition ContainerAVI.h:705
ParseObject tryParseList()
We try to parse the actual state for any list.
Definition ContainerAVI.h:634
bool isMetadataReady()
Returns true if all metadata has been parsed and is available.
Definition ContainerAVI.h:339
BitmapInfoHeader aviVideoInfo()
Provides the video information.
Definition ContainerAVI.h:328
void consume(int len)
We remove the processed bytes from the beginning of the buffer.
Definition ContainerAVI.h:711
virtual void setOutput(Print &out_stream) override
Defines the audio output stream - usually called by EncodedAudioStream.
Definition ContainerAVI.h:284
ParseObject tryParseChunk()
Definition ContainerAVI.h:608
void setValidationCallback(bool(*cb)(AVIDecoder &avi))
Definition ContainerAVI.h:342
WAVFormatX aviAudioInfo()
Provides the audio information.
Definition ContainerAVI.h:333
AVIStreamHeader streamHeader(int idx)
Provides the information from the stream header chunks.
Definition ContainerAVI.h:325
ParseObject tryParseChunk(const char *id)
Definition ContainerAVI.h:616
Decoding of encoded audio into PCM data.
Definition AudioCodecsBase.h:18
Parent class for all container formats.
Definition AudioCodecsBase.h:80
A more natural Print class to process encoded data (aac, wav, mp3...). Just define the output and the...
Definition AudioEncoded.h:21
void setOutput(Print &outputStream) override
Defines/Changes the output target.
Definition AudioEncoded.h:97
We try to keep the necessary buffer for parsing as small as possible, The data() method provides the ...
Definition ContainerAVI.h:21
Definition ContainerAVI.h:156
Definition NoArduino.h:62
LIFO Stack which is based on a List.
Definition Stack.h:14
Str which keeps the data on the heap. We grow the allocated memory only if the copy source is not fit...
Definition Str.h:24
void copyFrom(const char *source, int len, int maxlen=0)
assigns a memory buffer
Definition Str.h:96
void setChars(char c, int len)
Fills the string with len chars.
Definition Str.h:108
A simple wrapper to provide string functions on existing allocated char*. If the underlying char* is ...
Definition StrView.h:28
virtual bool equals(const char *str)
checks if the string equals indicated parameter string
Definition StrView.h:165
virtual const char * c_str()
provides the string value as const char*
Definition StrView.h:379
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Logic to Synchronize video and audio output: This is the minimum implementatin which actually does no...
Definition Video.h:37
Abstract class for video playback. This class is used to assemble a complete video frame in memory.
Definition Video.h:21
AudioFormat
Audio format codes used by Microsoft e.g. in avi or wav files.
Definition AudioFormat.h:19
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
Definition ContainerAVI.h:63
Definition ContainerAVI.h:84
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59
Definition ContainerAVI.h:101
Definition ContainerAVI.h:79
Definition ContainerAVI.h:115