arduino-audio-tools
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 
12 namespace audio_tools {
13 
21 class ParseBuffer {
22 public:
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 
56 protected:
57  Vector<uint8_t> vector{0};
58  size_t available_byte_count = 0;
59 };
60 
61 using FOURCC = char[4];
62 
63 struct AVIMainHeader {
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 
79 struct 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 
115 struct WAVFormatX {
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 
133 enum StreamContentType { Audio, Video };
134 
135 enum ParseObjectType { AVIList, AVIChunk, AVIStreamData };
136 
137 enum 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  */
156 class ParseObject {
157 public:
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 
231 protected:
232  // ParseBuffer data_buffer;
233  char chunk_id[5] = {};
234  ParseObjectType object_type;
235 };
236 
249 class AVIDecoder : public ContainerDecoder {
250 public:
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 
352 protected:
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
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
StrView & getStr(int offset, int len)
Provides the string at the indicated byte offset with the indicated length.
Definition: ContainerAVI.h:696
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
Docoding of encoded audio into PCM data.
Definition: AudioCodecsBase.h:16
Parent class for all container formats.
Definition: AudioCodecsBase.h:74
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)
Defines/Changes the output target.
Definition: AudioEncoded.h:96
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:58
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:23
void copyFrom(const char *source, int len, int maxlen=0)
assigns a memory buffer
Definition: Str.h:95
void setChars(char c, int len)
Fills the string with len chars.
Definition: Str.h:107
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
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: AudioConfig.h:868
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