Line data Source code
1 : /*
2 : * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : // Based on the WAV file format documentation at
12 : // https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ and
13 : // http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
14 :
15 : #include "webrtc/common_audio/wav_header.h"
16 :
17 : #include <algorithm>
18 : #include <cstring>
19 : #include <limits>
20 : #include <string>
21 :
22 : #include "webrtc/base/checks.h"
23 : #include "webrtc/common_audio/include/audio_util.h"
24 :
25 : namespace webrtc {
26 : namespace {
27 :
28 : struct ChunkHeader {
29 : uint32_t ID;
30 : uint32_t Size;
31 : };
32 : static_assert(sizeof(ChunkHeader) == 8, "ChunkHeader size");
33 :
34 : // We can't nest this definition in WavHeader, because VS2013 gives an error
35 : // on sizeof(WavHeader::fmt): "error C2070: 'unknown': illegal sizeof operand".
36 : struct FmtSubchunk {
37 : ChunkHeader header;
38 : uint16_t AudioFormat;
39 : uint16_t NumChannels;
40 : uint32_t SampleRate;
41 : uint32_t ByteRate;
42 : uint16_t BlockAlign;
43 : uint16_t BitsPerSample;
44 : };
45 : static_assert(sizeof(FmtSubchunk) == 24, "FmtSubchunk size");
46 : const uint32_t kFmtSubchunkSize = sizeof(FmtSubchunk) - sizeof(ChunkHeader);
47 :
48 : struct WavHeader {
49 : struct {
50 : ChunkHeader header;
51 : uint32_t Format;
52 : } riff;
53 : FmtSubchunk fmt;
54 : struct {
55 : ChunkHeader header;
56 : } data;
57 : };
58 : static_assert(sizeof(WavHeader) == kWavHeaderSize, "no padding in header");
59 :
60 : } // namespace
61 :
62 0 : bool CheckWavParameters(size_t num_channels,
63 : int sample_rate,
64 : WavFormat format,
65 : size_t bytes_per_sample,
66 : size_t num_samples) {
67 : // num_channels, sample_rate, and bytes_per_sample must be positive, must fit
68 : // in their respective fields, and their product must fit in the 32-bit
69 : // ByteRate field.
70 0 : if (num_channels == 0 || sample_rate <= 0 || bytes_per_sample == 0)
71 0 : return false;
72 0 : if (static_cast<uint64_t>(sample_rate) > std::numeric_limits<uint32_t>::max())
73 0 : return false;
74 0 : if (num_channels > std::numeric_limits<uint16_t>::max())
75 0 : return false;
76 0 : if (static_cast<uint64_t>(bytes_per_sample) * 8 >
77 0 : std::numeric_limits<uint16_t>::max())
78 0 : return false;
79 0 : if (static_cast<uint64_t>(sample_rate) * num_channels * bytes_per_sample >
80 0 : std::numeric_limits<uint32_t>::max())
81 0 : return false;
82 :
83 : // format and bytes_per_sample must agree.
84 0 : switch (format) {
85 : case kWavFormatPcm:
86 : // Other values may be OK, but for now we're conservative:
87 0 : if (bytes_per_sample != 1 && bytes_per_sample != 2)
88 0 : return false;
89 0 : break;
90 : case kWavFormatALaw:
91 : case kWavFormatMuLaw:
92 0 : if (bytes_per_sample != 1)
93 0 : return false;
94 0 : break;
95 : default:
96 0 : return false;
97 : }
98 :
99 : // The number of bytes in the file, not counting the first ChunkHeader, must
100 : // be less than 2^32; otherwise, the ChunkSize field overflows.
101 0 : const size_t header_size = kWavHeaderSize - sizeof(ChunkHeader);
102 : const size_t max_samples =
103 0 : (std::numeric_limits<uint32_t>::max() - header_size) / bytes_per_sample;
104 0 : if (num_samples > max_samples)
105 0 : return false;
106 :
107 : // Each channel must have the same number of samples.
108 0 : if (num_samples % num_channels != 0)
109 0 : return false;
110 :
111 0 : return true;
112 : }
113 :
114 : #ifdef WEBRTC_ARCH_LITTLE_ENDIAN
115 0 : static inline void WriteLE16(uint16_t* f, uint16_t x) { *f = x; }
116 0 : static inline void WriteLE32(uint32_t* f, uint32_t x) { *f = x; }
117 0 : static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) {
118 0 : *f = static_cast<uint32_t>(a)
119 0 : | static_cast<uint32_t>(b) << 8
120 0 : | static_cast<uint32_t>(c) << 16
121 0 : | static_cast<uint32_t>(d) << 24;
122 0 : }
123 :
124 0 : static inline uint16_t ReadLE16(uint16_t x) { return x; }
125 0 : static inline uint32_t ReadLE32(uint32_t x) { return x; }
126 0 : static inline std::string ReadFourCC(uint32_t x) {
127 0 : return std::string(reinterpret_cast<char*>(&x), 4);
128 : }
129 : #else
130 : static inline void WriteLE16(uint16_t* f, uint16_t x) {
131 : *f = ((x << 8) & 0xff00) | ( ( x >> 8) & 0x00ff);
132 : }
133 :
134 : static inline void WriteLE32(uint32_t* f, uint32_t x) {
135 : *f = ( (x & 0x000000ff) << 24 )
136 : | ((x & 0x0000ff00) << 8)
137 : | ((x & 0x00ff0000) >> 8)
138 : | ((x & 0xff000000) >> 24 );
139 : }
140 :
141 : static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) {
142 : *f = (static_cast<uint32_t>(a) << 24 )
143 : | (static_cast<uint32_t>(b) << 16)
144 : | (static_cast<uint32_t>(c) << 8)
145 : | (static_cast<uint32_t>(d) );
146 : }
147 :
148 : static inline uint16_t ReadLE16(uint16_t x) {
149 : return (( x & 0x00ff) << 8 )| ((x & 0xff00)>>8);
150 : }
151 :
152 : static inline uint32_t ReadLE32(uint32_t x) {
153 : return ( (x & 0x000000ff) << 24 )
154 : | ( (x & 0x0000ff00) << 8 )
155 : | ( (x & 0x00ff0000) >> 8)
156 : | ( (x & 0xff000000) >> 24 );
157 : }
158 :
159 : static inline std::string ReadFourCC(uint32_t x) {
160 : x = ReadLE32(x);
161 : return std::string(reinterpret_cast<char*>(&x), 4);
162 : }
163 : #endif
164 :
165 0 : static inline uint32_t RiffChunkSize(size_t bytes_in_payload) {
166 : return static_cast<uint32_t>(
167 0 : bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader));
168 : }
169 :
170 0 : static inline uint32_t ByteRate(size_t num_channels, int sample_rate,
171 : size_t bytes_per_sample) {
172 0 : return static_cast<uint32_t>(num_channels * sample_rate * bytes_per_sample);
173 : }
174 :
175 0 : static inline uint16_t BlockAlign(size_t num_channels,
176 : size_t bytes_per_sample) {
177 0 : return static_cast<uint16_t>(num_channels * bytes_per_sample);
178 : }
179 :
180 0 : void WriteWavHeader(uint8_t* buf,
181 : size_t num_channels,
182 : int sample_rate,
183 : WavFormat format,
184 : size_t bytes_per_sample,
185 : size_t num_samples) {
186 0 : RTC_CHECK(CheckWavParameters(num_channels, sample_rate, format,
187 0 : bytes_per_sample, num_samples));
188 :
189 : WavHeader header;
190 0 : const size_t bytes_in_payload = bytes_per_sample * num_samples;
191 :
192 0 : WriteFourCC(&header.riff.header.ID, 'R', 'I', 'F', 'F');
193 0 : WriteLE32(&header.riff.header.Size, RiffChunkSize(bytes_in_payload));
194 0 : WriteFourCC(&header.riff.Format, 'W', 'A', 'V', 'E');
195 :
196 0 : WriteFourCC(&header.fmt.header.ID, 'f', 'm', 't', ' ');
197 0 : WriteLE32(&header.fmt.header.Size, kFmtSubchunkSize);
198 0 : WriteLE16(&header.fmt.AudioFormat, format);
199 0 : WriteLE16(&header.fmt.NumChannels, static_cast<uint16_t>(num_channels));
200 0 : WriteLE32(&header.fmt.SampleRate, sample_rate);
201 0 : WriteLE32(&header.fmt.ByteRate, ByteRate(num_channels, sample_rate,
202 0 : bytes_per_sample));
203 0 : WriteLE16(&header.fmt.BlockAlign, BlockAlign(num_channels, bytes_per_sample));
204 0 : WriteLE16(&header.fmt.BitsPerSample,
205 0 : static_cast<uint16_t>(8 * bytes_per_sample));
206 :
207 0 : WriteFourCC(&header.data.header.ID, 'd', 'a', 't', 'a');
208 0 : WriteLE32(&header.data.header.Size, static_cast<uint32_t>(bytes_in_payload));
209 :
210 : // Do an extra copy rather than writing everything to buf directly, since buf
211 : // might not be correctly aligned.
212 0 : memcpy(buf, &header, kWavHeaderSize);
213 0 : }
214 :
215 0 : bool ReadWavHeader(ReadableWav* readable,
216 : size_t* num_channels,
217 : int* sample_rate,
218 : WavFormat* format,
219 : size_t* bytes_per_sample,
220 : size_t* num_samples) {
221 : WavHeader header;
222 0 : if (readable->Read(&header, kWavHeaderSize - sizeof(header.data)) !=
223 : kWavHeaderSize - sizeof(header.data))
224 0 : return false;
225 :
226 0 : const uint32_t fmt_size = ReadLE32(header.fmt.header.Size);
227 0 : if (fmt_size != kFmtSubchunkSize) {
228 : // There is an optional two-byte extension field permitted to be present
229 : // with PCM, but which must be zero.
230 : int16_t ext_size;
231 0 : if (kFmtSubchunkSize + sizeof(ext_size) != fmt_size)
232 0 : return false;
233 0 : if (readable->Read(&ext_size, sizeof(ext_size)) != sizeof(ext_size))
234 0 : return false;
235 0 : if (ext_size != 0)
236 0 : return false;
237 : }
238 0 : if (readable->Read(&header.data, sizeof(header.data)) != sizeof(header.data))
239 0 : return false;
240 :
241 : // Parse needed fields.
242 0 : *format = static_cast<WavFormat>(ReadLE16(header.fmt.AudioFormat));
243 0 : *num_channels = ReadLE16(header.fmt.NumChannels);
244 0 : *sample_rate = ReadLE32(header.fmt.SampleRate);
245 0 : *bytes_per_sample = ReadLE16(header.fmt.BitsPerSample) / 8;
246 0 : const size_t bytes_in_payload = ReadLE32(header.data.header.Size);
247 0 : if (*bytes_per_sample == 0)
248 0 : return false;
249 0 : *num_samples = bytes_in_payload / *bytes_per_sample;
250 :
251 : // Sanity check remaining fields.
252 0 : if (ReadFourCC(header.riff.header.ID) != "RIFF")
253 0 : return false;
254 0 : if (ReadFourCC(header.riff.Format) != "WAVE")
255 0 : return false;
256 0 : if (ReadFourCC(header.fmt.header.ID) != "fmt ")
257 0 : return false;
258 0 : if (ReadFourCC(header.data.header.ID) != "data")
259 0 : return false;
260 :
261 0 : if (ReadLE32(header.riff.header.Size) < RiffChunkSize(bytes_in_payload))
262 0 : return false;
263 0 : if (ReadLE32(header.fmt.ByteRate) !=
264 0 : ByteRate(*num_channels, *sample_rate, *bytes_per_sample))
265 0 : return false;
266 0 : if (ReadLE16(header.fmt.BlockAlign) !=
267 0 : BlockAlign(*num_channels, *bytes_per_sample))
268 0 : return false;
269 :
270 0 : return CheckWavParameters(*num_channels, *sample_rate, *format,
271 0 : *bytes_per_sample, *num_samples);
272 : }
273 :
274 :
275 : } // namespace webrtc
|