1 /*
2 mkvmerge -- utility for splicing together matroska files
3 from component media subtypes
4
5 Distributed under the GPL v2
6 see the file COPYING for details
7 or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
8
9 helper functions for WAVPACK data
10
11 Written by Steve Lhomme <steve.lhomme@free.fr>.
12 Based on a software from David Bryant <dbryant@impulse.net>.
13 Modified by Moritz Bunkus <moritz@bunkus.org>.
14 */
15
16 #include <cctype>
17
18 #include "common/common_pch.h"
19 #include "common/debugging.h"
20 #include "common/endian.h"
21 #include "common/wavpack.h"
22
23 namespace mtx::wavpack {
24
25 constexpr auto ID_DSD_BLOCK = 0x0e;
26 constexpr auto ID_OPTIONAL_DATA = 0x20;
27 constexpr auto ID_UNIQUE = 0x3f;
28 constexpr auto ID_ODD_SIZE = 0x40;
29 constexpr auto ID_LARGE = 0x80;
30
31 constexpr auto ID_BLOCK_CHECKSUM = (ID_OPTIONAL_DATA | 0xf);
32 constexpr auto ID_SAMPLE_RATE = (ID_OPTIONAL_DATA | 0x7);
33
34 namespace {
35 debugging_option_c s_debug{"wavpack"};
36
37 constexpr uint32_t s_sample_rates [] = {
38 6000, 8000, 9600, 11025, 12000, 16000, 22050,
39 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000
40 };
41
42 } // anonymous namespace
43
meta_t()44 meta_t::meta_t()
45 : channel_count(0)
46 , bits_per_sample(0)
47 , sample_rate(0)
48 , samples_per_block(0)
49 , has_correction(false)
50 {
51 }
52
53 static int32_t
read_next_header(mm_io_c & in,header_t * wphdr)54 read_next_header(mm_io_c &in,
55 header_t *wphdr) {
56 char buffer[sizeof(*wphdr)], *sp = buffer + sizeof(*wphdr), *ep = sp;
57 uint32_t bytes_skipped = 0;
58 int bleft;
59
60 while (true) {
61 if (sp < ep) {
62 bleft = ep - sp;
63 memmove(buffer, sp, bleft);
64 } else
65 bleft = 0;
66
67 if (in.read(buffer + bleft, sizeof(*wphdr) - bleft) != static_cast<unsigned int>(sizeof(*wphdr) - bleft))
68 return -1;
69
70 sp = buffer;
71
72 if ((*sp++ == 'w') && (*sp == 'v') && (*++sp == 'p') && (*++sp == 'k') &&
73 !(*++sp & 1) && (sp[2] < 16) && !sp[3] && (sp[5] == 4)) {
74 memcpy(wphdr, buffer, sizeof(*wphdr));
75 return bytes_skipped;
76 }
77
78 while ((sp < ep) && (*sp != 'w'))
79 sp++;
80
81 if ((bytes_skipped += sp - buffer) > 1024 * 1024)
82 return -1;
83 }
84 }
85
86 // Given a WavPack block (complete, but not including the 32-byte header), parse the metadata
87 // blocks to the end and return the number of bytes used by the trailing block checksum if one
88 // is found, otherwise return zero. This is the number of bytes that can be deleted from the
89 // end of the block to erase the checksum. Also, the HAS_CHECKSUM bit in the header flags
90 // must be reset.
91
92 int
checksum_byte_count(unsigned char const * buffer,int bcount)93 checksum_byte_count(unsigned char const *buffer,
94 int bcount) {
95 while (bcount >= 2) {
96 auto meta_id = *buffer++;
97 auto c1 = *buffer++;
98
99 int meta_bc = c1 << 1;
100 bcount -= 2;
101
102 if (meta_id & ID_LARGE) {
103 if (bcount < 2)
104 return 0;
105
106 c1 = *buffer++;
107 auto c2 = *buffer++;
108 meta_bc += (static_cast<uint32_t>(c1) << 9) + (static_cast<uint32_t>(c2) << 17);
109 bcount -= 2;
110 }
111
112 if (bcount < meta_bc)
113 return 0;
114
115 // if we got a block-checksum and we're at the end of the block, return its size
116
117 if ((meta_id == ID_BLOCK_CHECKSUM) && (meta_bc == bcount))
118 return meta_bc + 2;
119
120 bcount -= meta_bc;
121 buffer += meta_bc;
122 }
123
124 return 0;
125 }
126
127 // Given a WavPack block (complete, but not including the 32-byte header), parse the metadata
128 // blocks until an ID_SAMPLE_RATE block is found and return the non-standard sample rate
129 // contained there, or zero if no such block is found.
130
131 static int
get_non_standard_rate(unsigned char const * buffer,int bcount)132 get_non_standard_rate(unsigned char const *buffer,
133 int bcount) {
134 while (bcount >= 2) {
135 auto meta_id = *buffer++;
136 auto c1 = *buffer++;
137
138 auto meta_bc = c1 << 1;
139 bcount -= 2;
140
141 if (meta_id & ID_LARGE) {
142 if (bcount < 2)
143 return 0;
144
145 c1 = *buffer++;
146 auto c2 = *buffer++;
147 meta_bc += (static_cast<uint32_t>(c1) << 9) + (static_cast<uint32_t>(c2) << 17);
148 bcount -= 2;
149 }
150
151 if (bcount < meta_bc)
152 return 0;
153
154 // if we got a sample rate, return it
155
156 if (((meta_id & ID_UNIQUE) == ID_SAMPLE_RATE) && (meta_bc == 4)) {
157 int sample_rate = get_uint24_le(buffer);
158
159 // only use 4th byte if it's really there (i.e., size is even)
160
161 if (!(meta_id & ID_ODD_SIZE))
162 sample_rate |= static_cast<int32_t>(buffer[3] & 0x7f) << 24;
163
164 return sample_rate;
165 }
166
167 bcount -= meta_bc;
168 buffer += meta_bc;
169 }
170
171 return 0;
172 }
173
174 // Given a WavPack block (complete, but not including the 32-byte header), parse the metadata
175 // blocks until a DSD audio data block is found and return the sample-rate shift value
176 // contained there, or zero if no such block is found. The nominal sample rate of DSD audio
177 // files (found in the header) must be left-shifted by this amount to get the actual "byte"
178 // sample rate. Note that 8-bit bytes are the "atoms" of the DSD audio coding (for decoding,
179 // seeking, etc), so the shifted rate must be further multiplied by 8 to get the actual DSD
180 // bit sample rate.
181
182 static int
get_dsd_rate_shifter(unsigned char const * buffer,int bcount)183 get_dsd_rate_shifter(unsigned char const *buffer,
184 int bcount) {
185 while (bcount >= 2) {
186 auto meta_id = *buffer++;
187 auto c1 = *buffer++;
188
189 auto meta_bc = c1 << 1;
190 bcount -= 2;
191
192 if (meta_id & ID_LARGE) {
193 if (bcount < 2)
194 return 0;
195
196 c1 = *buffer++;
197 auto c2 = *buffer++;
198 meta_bc += (static_cast<uint32_t>(c1) << 9) + (static_cast<uint32_t>(c2) << 17);
199 bcount -= 2;
200 }
201
202 if (bcount < meta_bc)
203 return 0;
204
205 // if we got DSD block, return the specified rate shift amount
206
207 if (((meta_id & ID_UNIQUE) == ID_DSD_BLOCK) && meta_bc && (*buffer <= 31))
208 return *buffer;
209
210 bcount -= meta_bc;
211 buffer += meta_bc;
212 }
213
214 return 0;
215 }
216
217 int32_t
parse_frame(mm_io_c & in,header_t & wphdr,meta_t & meta,bool read_blocked_frames,bool keep_initial_position)218 parse_frame(mm_io_c &in,
219 header_t &wphdr,
220 meta_t &meta,
221 bool read_blocked_frames,
222 bool keep_initial_position) {
223 uint32_t bcount, ck_size{};
224 uint64_t first_data_pos = in.getFilePointer();
225 bool can_leave = !read_blocked_frames;
226
227 do {
228 // read next WavPack header
229 bcount = read_next_header(in, &wphdr);
230
231 if (bcount == (uint32_t) -1) {
232 return -1;
233 }
234
235 // if there's audio samples in there...
236 auto block_samples = get_uint32_le(&wphdr.block_samples);
237 ck_size = get_uint32_le(&wphdr.ck_size);
238
239 if (block_samples) {
240 auto flags = get_uint32_le(&wphdr.flags);
241 meta.channel_count += (flags & MONO_FLAG) ? 1 : 2;
242 if (flags & INITIAL_BLOCK) {
243 int non_standard_rate = 0, dsd_rate_shifter = 0;
244
245 meta.sample_rate = (flags & SRATE_MASK) >> SRATE_LSB;
246
247 // For non-standard sample rates or DSD audio files, we must read and parse the block
248 // to actually determine the sample rate. Note that for correction files this will
249 // silently fail, but that doesn't seem to cause trouble. An optimization would be to
250 // do this only on the very first block of the file since it can't change after that.
251
252 if (meta.sample_rate == 15 || flags & DSD_FLAG) {
253 auto adjusted_block_size = ck_size - sizeof(header_t) + 8;
254 auto buffer = memory_c::alloc(adjusted_block_size);
255
256 if (in.read(buffer, adjusted_block_size) != static_cast<unsigned int>(adjusted_block_size))
257 return -1;
258
259 if (meta.sample_rate == 15)
260 non_standard_rate = get_non_standard_rate(buffer->get_buffer(), adjusted_block_size);
261
262 if (flags & DSD_FLAG)
263 dsd_rate_shifter = get_dsd_rate_shifter(buffer->get_buffer(), adjusted_block_size);
264
265 in.skip(-adjusted_block_size);
266 }
267
268 if (meta.sample_rate < 15)
269 meta.sample_rate = s_sample_rates[meta.sample_rate];
270 else if (non_standard_rate)
271 meta.sample_rate = non_standard_rate;
272
273 if (flags & DSD_FLAG)
274 meta.sample_rate <<= dsd_rate_shifter;
275
276 if (flags & INT32_DATA || flags & FLOAT_DATA)
277 meta.bits_per_sample = 32;
278 else
279 meta.bits_per_sample = ((flags & BYTES_STORED) + 1) << 3;
280
281 meta.samples_per_block = block_samples;
282
283 first_data_pos = in.getFilePointer();
284 meta.channel_count = (flags & MONO_FLAG) ? 1 : 2;
285 if (flags & FINAL_BLOCK) {
286 can_leave = true;
287 mxdebug_if(s_debug, fmt::format("reader: {0} block: {1}, {2} bytes\n", flags & MONO_FLAG ? "mono" : "stereo", flags & HYBRID_FLAG ? "hybrid" : "lossless", ck_size + 8));
288 }
289 } else {
290 if (flags & FINAL_BLOCK) {
291 can_leave = true;
292 mxdebug_if(s_debug, fmt::format("reader: {0} chans, mode: {1}, {2} bytes\n", meta.channel_count, flags & HYBRID_FLAG ? "hybrid" : "lossless", ck_size + 8));
293 }
294 }
295 } else
296 mxwarn(Y("reader: non-audio block found\n"));
297 if (!can_leave) {
298 in.skip(ck_size - sizeof(header_t) + 8);
299 }
300 } while (!can_leave);
301
302 if (keep_initial_position)
303 in.setFilePointer(first_data_pos);
304
305 return ck_size - sizeof(header_t) + 8;
306 }
307
308 } // namespace mtx::wavpack
309