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