1
+ #pragma once
2
+ #include " AudioTools/Buffers.h"
3
+ #include " stdint.h"
4
+
5
+ namespace audio_tools {
6
+
7
+ class ParseBuffer : public SingleBuffer {
8
+ void consume (int size) {}
9
+ };
10
+
11
+ struct AVIStreamHeader {
12
+ FOURCC fccType;
13
+ FOURCC fccHandler;
14
+ DWORD dwFlags;
15
+ WORD wPriority;
16
+ WORD wLanguage;
17
+ DWORD dwInitialFrames;
18
+ DWORD dwScale;
19
+ DWORD dwRate;
20
+ DWORD dwStart;
21
+ DWORD dwLength;
22
+ DWORD dwSuggestedBufferSize;
23
+ DWORD dwQuality;
24
+ DWORD dwSampleSize;
25
+ RECT rcFrame;
26
+ };
27
+
28
+ typedef struct BITMAPINFOHEADER {
29
+ DWORD biSize;
30
+ LONG biWidth;
31
+ LONG biHeight;
32
+ WORD biPlanes;
33
+ WORD biBitCount;
34
+ DWORD biCompression;
35
+ DWORD biSizeImage;
36
+ LONG biXPelsPerMeter;
37
+ LONG biYPelsPerMeter;
38
+ DWORD biClrUsed;
39
+ DWORD biClrImportant;
40
+ };
41
+
42
+ struct WAVEFORMATEX {
43
+ WORD wFormatTag;
44
+ WORD nChannels;
45
+ DWORD nSamplesPerSec;
46
+ DWORD nAvgBytesPerSec;
47
+ WORD nBlockAlign;
48
+ WORD wBitsPerSample;
49
+ WORD cbSize;
50
+ };
51
+
52
+ struct WAVEFORMAT {
53
+ WORD wFormatTag;
54
+ WORD nChannels;
55
+ DWORD nSamplesPerSec;
56
+ DWORD nAvgBytesPerSec;
57
+ WORD nBlockAlign;
58
+ };
59
+
60
+ struct WAVEFORMATEXTENSIBLE {
61
+ WAVEFORMATEX Format;
62
+ union {
63
+ WORD wValidBitsPerSample;
64
+ WORD wSamplesPerBlock;
65
+ WORD wReserved;
66
+ } Samples;
67
+ DWORD dwChannelMask;
68
+ GUID SubFormat;
69
+ };
70
+
71
+ class List {
72
+ List (const char *id, int size) {
73
+ list_id.set (id, 4 );
74
+ list_size = size;
75
+ }
76
+ Str *id () { return list_id; }
77
+ int size () { return list_size; }
78
+ int open () { return open }
79
+ void consume (int len){open -= len};
80
+
81
+ protected:
82
+ StrExt list_id (5 );
83
+ int list_size;
84
+
85
+ }
86
+
87
+ class Chunk {
88
+ Chunk () = default ;
89
+ Chunk (const char *id, int size) {
90
+ data_buffer.resize (size);
91
+ chunk_size = size;
92
+ chunk_id.set (id, 4 );
93
+ }
94
+ Str *id () { return Strchunk_id; }
95
+ uint8_t *data () { return data_buffer ().data (); }
96
+ int size () { return chunk_size; }
97
+ int available () { return data_buffer.available (); }
98
+ int open () { return chunk_size - data_buffer.available (); }
99
+ void consume (int len) { data_buffer.consum (); }
100
+
101
+ AVIStreamHeader *asAVIStreamHeader () { return (AVIStreamHeader *)data (); }
102
+ bool isValid () { return data_buffer.size () > 0 ; }
103
+
104
+ protected:
105
+ ParseBuffer data_buffer{0 };
106
+ StrExt chunk_id (5 );
107
+ int chunk_size;
108
+ };
109
+
110
+ /* *
111
+ * Decoder which can be fed with smake chunks of data. The minimum length must
112
+ * be bigger then the header size!
113
+ */
114
+
115
+ class RIFFDecoder : public AudioDecoder {
116
+ public:
117
+ RIFFDecoder (int bufferSize = 8192 ) {}
118
+
119
+ ~RIFFDecoder () {}
120
+
121
+ void begin () {
122
+ parse_state = ParseHader;
123
+ header_is_avi = false ;
124
+ is_parsing_active = true ;
125
+ }
126
+
127
+ virtual void setOutputStream (Print &out_stream) {
128
+ p_print_audio = &out_stream;
129
+ }
130
+
131
+ virtual void setOutputVideoStream (Print &out_stream) {
132
+ p_print_video = &out_stream;
133
+ }
134
+
135
+ virtual size_t write (const void *data, size_t length) {
136
+ LOGD (" write: %d" , length);
137
+ int result = parse_buffer.writeArray (data, length);
138
+ if (is_parsing_active) {
139
+ if (!parse ()) {
140
+ LOGI (" Parse Error" );
141
+ parse_buffer.clear ();
142
+ result = length;
143
+ is_parsing_active;
144
+ } else {
145
+ result = length;
146
+ }
147
+ }
148
+ return result;
149
+ }
150
+
151
+ protected:
152
+ enum ParseState { ParseHader, ParseMovi };
153
+ using FOURCC = uint8_t [4 ];
154
+ int32_t header_file_size;
155
+ bool header_is_avi = false ;
156
+ bool is_parsing_active = true ;
157
+ ParseState parse_state = ParseHader;
158
+ ParseBuffer parse_buffer;
159
+ Print *p_print_audio = nullptr ;
160
+ Print *p_print_video = nullptr ;
161
+ AVIStreamHeader header;
162
+ List hdrl;
163
+
164
+ // we return true if at least one parse step was successful
165
+ bool parse () {
166
+ bool result = false ;
167
+ switch (parse_state) {
168
+ case ParseHader:
169
+ if (parseHeader ()) {
170
+ parse_state = ParseHdrl;
171
+ result = true ;
172
+ } else {
173
+ LOGE (" Not an AVI!" )
174
+ }
175
+ break ;
176
+ case ParseHdrl:
177
+ hdrl = parseList (" hdrl" );
178
+ parse_state = ParseAvih;
179
+ break ;
180
+
181
+ case ParseAvih:
182
+ header = parseChunk (" avih" ).asAVIStreamHeader ();
183
+ parse_state = ParseStrl;
184
+ break ;
185
+
186
+ case ParseStrl:
187
+ int len_strl = parseListStart (" strl" );
188
+ Chunk strh = parseChunk (" strh" );
189
+ parse_state = ParseStrf;
190
+
191
+ case ParseStrf:
192
+ Chunk strf = parseChunk (" strf" );
193
+ endList () break ;
194
+
195
+ case ParseMovi:
196
+ break ;
197
+ }
198
+ }
199
+
200
+ Chunk parseChunk (const char *id) {
201
+ Chunk result;
202
+ if (getStr (0 , 4 ).equals (" id" )) {
203
+ int chunk_size = getInt (4 );
204
+ resut = Chunk (id, chunk_size);
205
+ consume (8 );
206
+ }
207
+ return result;
208
+ }
209
+
210
+ // 'RIFF' fileSize fileType (data)
211
+ bool parseHeader () {
212
+ int headerSize = 12 ;
213
+ if (getStr (0 , 4 ).equals (" RIFF" )) {
214
+ header_file_size = getInt (4 );
215
+ header_is_avi = getStr (8 , 4 ).equals (" AVI " );
216
+ consume (12 );
217
+ }
218
+ return header_is_avi;
219
+ }
220
+
221
+ // 'LIST' ( listType ( listData ) )
222
+ int parseListStart (const char *type) {
223
+ int result = 0 ;
224
+ if (getStr (0 , 4 ).equals (" LIST" )) {
225
+ int list_size = getInt (4 );
226
+ result = getStr (8 , 4 ).equals (type);
227
+ consume (8 );
228
+ }
229
+ return result;
230
+ }
231
+
232
+ Str &getStr (int offset = 0 , int len) {
233
+ static StrExt str;
234
+ if (str.size () < len) {
235
+ str.resize (len + 1 );
236
+ }
237
+ memcpy (str.c_str (), parse_buffer.data () + offset, len);
238
+ str.c_str ()[len] = 0 ;
239
+ return str;
240
+ }
241
+
242
+ int32_t getInt (int offset) { return (int32_t )(parse_buffer.data () + offset); }
243
+
244
+ void consume (int len) { parse_buffer.consume (len); }
245
+ };
246
+
247
+ } // namespace audio_tools
0 commit comments