arduino-audio-tools
ContainerAVI.h
1 #pragma once
2 #include <string.h>
3 
4 #include "AudioBasic/StrExt.h"
6 #include "Video/Video.h"
7 #include "AudioTools/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, Str 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 AudioDecoder {
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  void 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  }
281 
283  virtual void setOutput(Print &out_stream) override {
284  // p_output_audio = &out_stream;
285  p_output_audio->setOutput(&out_stream);
286  }
287 
289  void setMute(bool mute) { is_mute = mute; }
290 
291  virtual void setOutputVideoStream(VideoOutput &out_stream) {
292  p_output_video = &out_stream;
293  }
294 
295  virtual size_t write(const void *data, size_t length) override {
296  LOGD("write: %d", (int)length);
297  int result = parse_buffer.writeArray((uint8_t *)data, length);
298  if (is_parsing_active) {
299  // we expect the first parse to succeed
300  if (parse()) {
301  // if so we process the parse_buffer
302  while (parse_buffer.available() > 4) {
303  if (!parse())
304  break;
305  }
306  } else {
307  LOGD("Parse Error");
308  parse_buffer.clear();
309  result = length;
310  is_parsing_active = false;
311  }
312  }
313  return result;
314  }
315 
316  operator bool() override { return is_parsing_active; }
317 
318  void end() override { is_parsing_active = false; };
319 
321  AVIMainHeader mainHeader() { return main_header; }
322 
324  AVIStreamHeader streamHeader(int idx) { return stream_header[idx]; }
325 
327  BitmapInfoHeader aviVideoInfo() { return video_info; };
328 
329  const char *videoFormat() { return video_format; }
330 
332  WAVFormatX aviAudioInfo() { return audio_info; }
333 
335  AudioFormat audioFormat() { return audio_info.wFormatTag; }
336 
338  bool isMetadataReady() { return is_metadata_ready; }
341  void setValidationCallback(bool (*cb)(AVIDecoder &avi)) {
342  validation_cb = cb;
343  }
344 
346  int videoSeconds() { return video_seconds; }
347 
349  void setVideoAudioSync(VideoAudioSync *yourSync) { p_synch = yourSync; }
350 
351 protected:
352  bool header_is_avi = false;
353  bool is_parsing_active = true;
354  ParseState parse_state = ParseHeader;
355  ParseBuffer parse_buffer;
356  AVIMainHeader main_header;
357  int stream_header_idx = -1;
358  Vector<AVIStreamHeader> stream_header;
359  BitmapInfoHeader video_info;
360  WAVFormatX audio_info;
361  Vector<StreamContentType> content_types;
362  Stack<ParseObject> object_stack;
363  ParseObject current_stream_data;
364  EncodedAudioOutput *p_output_audio = nullptr;
365  VideoOutput *p_output_video = nullptr;
366  long open_subchunk_len = 0;
367  long current_pos = 0;
368  long movi_end_pos = 0;
369  StrExt spaces;
370  StrExt str;
371  char video_format[5] = {0};
372  bool is_metadata_ready = false;
373  bool (*validation_cb)(AVIDecoder &avi) = nullptr;
374  bool is_mute = false;
375  CopyDecoder copy_decoder;
376  AudioDecoder *p_decoder = nullptr;
377  int video_seconds = 0;
378  VideoAudioSync defaultSynch;
379  VideoAudioSync *p_synch = &defaultSynch;
380 
381  bool isCurrentStreamAudio() {
382  return strncmp(stream_header[stream_header_idx].fccType, "auds", 4) == 0;
383  }
384 
385  bool isCurrentStreamVideo() {
386  return strncmp(stream_header[stream_header_idx].fccType, "vids", 4) == 0;
387  }
388 
389  // we return true if at least one parse step was successful
390  bool parse() {
391  bool result = true;
392  switch (parse_state) {
393  case ParseHeader: {
394  result = parseHeader();
395  if (result)
396  parse_state = ParseHdrl;
397  } break;
398 
399  case ParseHdrl: {
400  ParseObject hdrl = parseList("hdrl");
401  result = hdrl.isValid();
402  if (result) {
403  parse_state = ParseAvih;
404  }
405  } break;
406 
407  case ParseAvih: {
408  ParseObject avih = parseChunk("avih");
409  result = avih.isValid();
410  if (result) {
411  main_header = *(avih.asAVIMainHeader(parse_buffer.data()));
412  stream_header.resize(main_header.dwStreams);
413  consume(avih.size());
414  parse_state = ParseStrl;
415  }
416  } break;
417 
418  case ParseStrl: {
419  ParseObject strl = parseList("strl");
420  ParseObject strh = parseChunk("strh");
421  stream_header[++stream_header_idx] =
422  *(strh.asAVIStreamHeader(parse_buffer.data()));
423  consume(strh.size());
424  parse_state = ParseStrf;
425  } break;
426 
427  case ParseStrf: {
428  ParseObject strf = parseChunk("strf");
429  if (isCurrentStreamAudio()) {
430  audio_info = *(strf.asAVIAudioFormat(parse_buffer.data()));
431  setupAudioInfo();
432  LOGI("audioFormat: %d (%x)", (int)audioFormat(),(int)audioFormat());
433  content_types.push_back(Audio);
434  consume(strf.size());
435  } else if (isCurrentStreamVideo()) {
436  video_info = *(strf.asAVIVideoFormat(parse_buffer.data()));
437  setupVideoInfo();
438  LOGI("videoFormat: %s", videoFormat());
439  content_types.push_back(Video);
440  video_format[4] = 0;
441  consume(strf.size());
442  } else {
443  result = false;
444  }
445  parse_state = AfterStrf;
446  } break;
447 
448  case AfterStrf: {
449  // ignore all data until we find a new List
450  int pos = parse_buffer.indexOf("LIST");
451  if (pos >= 0) {
452  consume(pos);
453  ParseObject tmp = tryParseList();
454  if (Str(tmp.id()).equals("strl")) {
455  parse_state = ParseStrl;
456  } else if (Str(tmp.id()).equals("movi")) {
457  parse_state = ParseMovi;
458  } else {
459  // e.g. ignore info
460  consume(tmp.size() + LIST_HEADER_SIZE);
461  }
462  } else {
463  // no valid data, so throw it away, we keep the last 4 digits in case
464  // if it contains the beginning of a LIST
465  cleanupStack();
466  consume(parse_buffer.available() - 4);
467  }
468  } break;
469 
470  case ParseMovi: {
471  ParseObject movi = tryParseList();
472  if (Str(movi.id()).equals("movi")) {
473  consume(LIST_HEADER_SIZE);
474  is_metadata_ready = true;
475  if (validation_cb)
476  is_parsing_active = (validation_cb(*this));
477  processStack(movi);
478  movi_end_pos = movi.end_pos;
479  parse_state = SubChunk;
480  // trigger new write
481  result = false;
482  }
483  } break;
484 
485  case SubChunk: {
486  // rec is optinal
487  ParseObject hdrl = tryParseList();
488  if (Str(hdrl.id()).equals("rec")) {
489  consume(CHUNK_HEADER_SIZE);
490  processStack(hdrl);
491  }
492 
493  current_stream_data = parseAVIStreamData();
494  parse_state = SubChunkContinue;
495  open_subchunk_len = current_stream_data.open;
496  if (current_stream_data.isVideo()) {
497  LOGI("video:[%d]->[%d]", (int)current_stream_data.start_pos,
498  (int)current_stream_data.end_pos);
499  if (p_output_video != nullptr)
500  p_output_video->beginFrame(current_stream_data.open);
501  } else if (current_stream_data.isAudio()) {
502  LOGI("audio:[%d]->[%d]", (int)current_stream_data.start_pos,
503  (int)current_stream_data.end_pos);
504  } else {
505  LOGW("unknown subchunk at %d", (int)current_pos);
506  }
507 
508  } break;
509 
510  case SubChunkContinue: {
511  writeData();
512  if (open_subchunk_len == 0) {
513  if (current_stream_data.isVideo() && p_output_video != nullptr) {
514  uint32_t time_used_ms = p_output_video->endFrame();
515  p_synch->delayVideoFrame(main_header.dwMicroSecPerFrame, time_used_ms);
516  }
517  if (tryParseChunk("idx").isValid()) {
518  parse_state = ParseIgnore;
519  } else if (tryParseList("rec").isValid()) {
520  parse_state = ParseRec;
521  } else {
522  if (current_pos >= movi_end_pos) {
523  parse_state = ParseIgnore;
524  } else {
525  parse_state = SubChunk;
526  }
527  }
528  }
529  } break;
530 
531  case ParseIgnore: {
532  LOGD("ParseIgnore");
533  parse_buffer.clear();
534  } break;
535 
536  default:
537  result = false;
538  break;
539  }
540  return result;
541  }
542 
543  void setupAudioInfo() {
544  info.channels = audio_info.nChannels;
545  info.bits_per_sample = audio_info.wBitsPerSample;
546  info.sample_rate = audio_info.nSamplesPerSec;
547  info.logInfo();
548  // adjust the audio info if necessary
549  if (p_decoder != nullptr) {
550  p_decoder->setAudioInfo(info);
551  info = p_decoder->audioInfo();
552  }
553  if (p_notify) {
554  p_notify->setAudioInfo(info);
555  }
556  }
557 
558  void setupVideoInfo() {
559  memcpy(video_format, stream_header[stream_header_idx].fccHandler, 4);
560  AVIStreamHeader *vh = &stream_header[stream_header_idx];
561  if (vh->dwScale <= 0) {
562  vh->dwScale = 1;
563  }
564  int rate = vh->dwRate / vh->dwScale;
565  video_seconds = rate <= 0 ? 0 : vh->dwLength / rate;
566  LOGI("videoSeconds: %d seconds", video_seconds);
567  }
568 
569  void writeData() {
570  long to_write = min((long)parse_buffer.available(), open_subchunk_len);
571  if (current_stream_data.isAudio()) {
572  LOGD("audio %d", (int)to_write);
573  if (!is_mute){
574  p_synch->writeAudio(p_output_audio, parse_buffer.data(), to_write);
575  }
576  open_subchunk_len -= to_write;
577  cleanupStack();
578  consume(to_write);
579  } else if (current_stream_data.isVideo()) {
580  LOGD("video %d", (int)to_write);
581  if (p_output_video != nullptr)
582  p_output_video->write(parse_buffer.data(), to_write);
583  open_subchunk_len -= to_write;
584  cleanupStack();
585  consume(to_write);
586  }
587  }
588 
589  // 'RIFF' fileSize fileType (data)
590  bool parseHeader() {
591  bool header_is_avi = false;
592  int headerSize = 12;
593  if (getStr(0, 4).equals("RIFF")) {
594  ParseObject result;
595  uint32_t header_file_size = getInt(4);
596  header_is_avi = getStr(8, 4).equals("AVI ");
597  result.set(current_pos, "AVI ", header_file_size, AVIChunk);
598  processStack(result);
599  consume(headerSize);
600 
601  } else {
602  LOGE("parseHeader");
603  }
604  return header_is_avi;
605  }
606 
610  ParseObject result;
611  result.set(current_pos, getStr(0, 4), 0, AVIChunk);
612  return result;
613  }
614 
617  ParseObject tryParseChunk(const char *id) {
618  ParseObject result;
619  if (getStr(0, 4).equals(id)) {
620  result.set(current_pos, id, 0, AVIChunk);
621  }
622  return result;
623  }
624 
625  ParseObject tryParseList(const char *id) {
626  ParseObject result;
627  Str &list_id = getStr(8, 4);
628  if (list_id.equals(id) && getStr(0, 3).equals("LIST")) {
629  result.set(current_pos, getStr(8, 4), getInt(4), AVIList);
630  }
631  return result;
632  }
633 
636  ParseObject result;
637  if (getStr(0, 4).equals("LIST")) {
638  result.set(current_pos, getStr(8, 4), getInt(4), AVIList);
639  }
640  return result;
641  }
642 
644  ParseObject parseChunk(const char *id) {
645  ParseObject result;
646  int chunk_size = getInt(4);
647  if (getStr(0, 4).equals(id) && parse_buffer.size() >= chunk_size) {
648  result.set(current_pos, id, chunk_size, AVIChunk);
649  processStack(result);
650  consume(CHUNK_HEADER_SIZE);
651  }
652  return result;
653  }
654 
656  ParseObject parseList(const char *id) {
657  ParseObject result;
658  if (getStr(0, 4).equals("LIST") && getStr(8, 4).equals(id)) {
659  int size = getInt(4);
660  result.set(current_pos, id, size, AVIList);
661  processStack(result);
662  consume(LIST_HEADER_SIZE);
663  }
664  return result;
665  }
666 
667  ParseObject parseAVIStreamData() {
668  ParseObject result;
669  int size = getInt(4);
670  result.set(current_pos, getStr(0, 4), size, AVIStreamData);
671  if (result.isValid()) {
672  processStack(result);
673  consume(8);
674  }
675  return result;
676  }
677 
678  void processStack(ParseObject &result) {
679  cleanupStack();
680  object_stack.push(result);
681  spaces.setChars(' ', object_stack.size());
682  LOGD("%s - %s (%d-%d) size:%d", spaces.c_str(), result.id(),
683  (int)result.start_pos, (int)result.end_pos, (int)result.data_size);
684  }
685 
686  void cleanupStack() {
687  ParseObject current;
688  // make sure that we remove the object from the stack of we past the end
689  object_stack.peek(current);
690  while (current.end_pos <= current_pos) {
691  object_stack.pop(current);
692  object_stack.peek(current);
693  }
694  }
695 
697  Str &getStr(int offset, int len) {
698  str.setCapacity(len + 1);
699  const char *data = (const char *)parse_buffer.data();
700  str.copyFrom((data + offset), len, 5);
701 
702  return str;
703  }
704 
706  uint32_t getInt(int offset) {
707  uint32_t *result = (uint32_t *)(parse_buffer.data() + offset);
708  return *result;
709  }
710 
712  void consume(int len) {
713  current_pos += len;
714  parse_buffer.consume(len);
715  }
716 };
717 
718 } // 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:656
void setVideoAudioSync(VideoAudioSync *yourSync)
Replace the synchronization logic with your implementation.
Definition: ContainerAVI.h:349
ParseObject parseChunk(const char *id)
We load the indicated chunk from the current data.
Definition: ContainerAVI.h:644
AudioFormat audioFormat()
Provides the audio_info.wFormatTag.
Definition: ContainerAVI.h:335
Str & getStr(int offset, int len)
Provides the string at the indicated byte offset with the indicated length.
Definition: ContainerAVI.h:697
AVIMainHeader mainHeader()
Provides the information from the main header chunk.
Definition: ContainerAVI.h:321
int videoSeconds()
Provide the length of the video in seconds.
Definition: ContainerAVI.h:346
uint32_t getInt(int offset)
Provides the int32 at the indicated byte offset.
Definition: ContainerAVI.h:706
ParseObject tryParseList()
We try to parse the actual state for any list.
Definition: ContainerAVI.h:635
bool isMetadataReady()
Returns true if all metadata has been parsed and is available.
Definition: ContainerAVI.h:338
BitmapInfoHeader aviVideoInfo()
Provides the video information.
Definition: ContainerAVI.h:327
void consume(int len)
We remove the processed bytes from the beginning of the buffer.
Definition: ContainerAVI.h:712
virtual void setOutput(Print &out_stream) override
Defines the audio output stream - usually called by EncodedAudioStream.
Definition: ContainerAVI.h:283
ParseObject tryParseChunk()
Definition: ContainerAVI.h:609
void setValidationCallback(bool(*cb)(AVIDecoder &avi))
Definition: ContainerAVI.h:341
WAVFormatX aviAudioInfo()
Provides the audio information.
Definition: ContainerAVI.h:332
AVIStreamHeader streamHeader(int idx)
Provides the information from the stream header chunks.
Definition: ContainerAVI.h:324
ParseObject tryParseChunk(const char *id)
Definition: ContainerAVI.h:617
Docoding of encoded audio into PCM data.
Definition: AudioEncoded.h:17
A more natural Print class to process encoded data (aac, wav, mp3...). Just define the output and the...
Definition: AudioEncoded.h:193
void setOutput(Print *outputStream)
Defines the output.
Definition: AudioEncoded.h:292
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:51
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: StrExt.h:23
void copyFrom(const char *source, int len, int maxlen=0)
assigns a memory buffer
Definition: StrExt.h:111
void setChars(char c, int len)
Fills the string with len chars.
Definition: StrExt.h:123
A simple wrapper to provide string functions on char*. If the underlying char* is a const we do not a...
Definition: Str.h:26
virtual bool equals(const char *str)
checks if the string equals indicated parameter string
Definition: Str.h:170
virtual const char * c_str()
provides the string value as const char*
Definition: Str.h:412
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: AnalogAudio.h:9
Definition: ContainerAVI.h:63
Definition: ContainerAVI.h:84
Definition: ContainerAVI.h:101
Definition: ContainerAVI.h:79
Definition: ContainerAVI.h:115