wav_audio_handler.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/audio/wav_audio_handler.h"
  5. #include <algorithm>
  6. #include <cstring>
  7. #include "base/big_endian.h"
  8. #include "base/logging.h"
  9. #include "base/memory/ptr_util.h"
  10. #include "base/notreached.h"
  11. #include "base/sys_byteorder.h"
  12. #include "build/build_config.h"
  13. #include "media/base/audio_bus.h"
  14. #include "media/base/limits.h"
  15. namespace media {
  16. namespace {
  17. const char kChunkId[] = "RIFF";
  18. const char kFormat[] = "WAVE";
  19. const char kFmtSubchunkId[] = "fmt ";
  20. const char kDataSubchunkId[] = "data";
  21. // The size of a chunk header in wav file format. A chunk header consists of a
  22. // tag ('fmt ' or 'data') and 4 bytes of chunk length.
  23. const size_t kChunkHeaderSize = 8;
  24. // The minimum size of 'fmt' chunk.
  25. const size_t kFmtChunkMinimumSize = 16;
  26. const size_t kFmtChunkExtensibleMinimumSize = 40;
  27. // The offsets of 'fmt' fields.
  28. const size_t kAudioFormatOffset = 0;
  29. const size_t kChannelOffset = 2;
  30. const size_t kSampleRateOffset = 4;
  31. const size_t kBitsPerSampleOffset = 14;
  32. const size_t kValidBitsPerSampleOffset = 18;
  33. const size_t kSubFormatOffset = 24;
  34. // A convenience struct for passing WAV parameters around. AudioParameters is
  35. // too heavyweight for this. Keep this class internal to this implementation.
  36. struct WavAudioParameters {
  37. WavAudioHandler::AudioFormat audio_format;
  38. uint16_t num_channels;
  39. uint32_t sample_rate;
  40. uint16_t bits_per_sample;
  41. uint16_t valid_bits_per_sample;
  42. bool is_extensible;
  43. };
  44. bool ParamsAreValid(const WavAudioParameters& params) {
  45. return (
  46. // Check number of channels
  47. params.num_channels != 0u &&
  48. params.num_channels <= static_cast<uint16_t>(limits::kMaxChannels) &&
  49. // Check sample rate
  50. params.sample_rate != 0u &&
  51. (
  52. // Check bits per second for PCM data
  53. (params.audio_format ==
  54. WavAudioHandler::AudioFormat::kAudioFormatPCM &&
  55. (params.bits_per_sample == 8u || params.bits_per_sample == 16u ||
  56. params.bits_per_sample == 32u)) ||
  57. // Check bits per second for float data
  58. (params.audio_format ==
  59. WavAudioHandler::AudioFormat::kAudioFormatFloat &&
  60. (params.bits_per_sample == 32u || params.bits_per_sample == 64u))) &&
  61. // Check extensible format bps
  62. (!params.is_extensible ||
  63. params.valid_bits_per_sample == params.bits_per_sample));
  64. }
  65. // Reads an integer from |data| with |offset|.
  66. template <typename T>
  67. T ReadInt(const base::StringPiece& data, size_t offset) {
  68. CHECK_LE(offset + sizeof(T), data.size());
  69. T result;
  70. memcpy(&result, data.data() + offset, sizeof(T));
  71. #if !defined(ARCH_CPU_LITTLE_ENDIAN)
  72. result = base::ByteSwap(result);
  73. #endif
  74. return result;
  75. }
  76. // Parse a "fmt " chunk from wav data into its parameters.
  77. bool ParseFmtChunk(const base::StringPiece data, WavAudioParameters* params) {
  78. DCHECK(params);
  79. // If the chunk is too small, return false.
  80. if (data.size() < kFmtChunkMinimumSize) {
  81. LOG(ERROR) << "Data size " << data.size() << " is too short.";
  82. return false;
  83. }
  84. // Read in serialized parameters.
  85. params->audio_format =
  86. ReadInt<WavAudioHandler::AudioFormat>(data, kAudioFormatOffset);
  87. params->num_channels = ReadInt<uint16_t>(data, kChannelOffset);
  88. params->sample_rate = ReadInt<uint32_t>(data, kSampleRateOffset);
  89. params->bits_per_sample = ReadInt<uint16_t>(data, kBitsPerSampleOffset);
  90. if (params->audio_format ==
  91. WavAudioHandler::AudioFormat::kAudioFormatExtensible) {
  92. if (data.size() < kFmtChunkExtensibleMinimumSize) {
  93. LOG(ERROR) << "Data size " << data.size() << " is too short.";
  94. return false;
  95. }
  96. params->is_extensible = true;
  97. params->audio_format =
  98. ReadInt<WavAudioHandler::AudioFormat>(data, kSubFormatOffset);
  99. params->valid_bits_per_sample =
  100. ReadInt<uint16_t>(data, kValidBitsPerSampleOffset);
  101. } else {
  102. params->is_extensible = false;
  103. }
  104. return true;
  105. }
  106. bool ParseWavData(const base::StringPiece wav_data,
  107. base::StringPiece* audio_data_out,
  108. WavAudioParameters* params_out) {
  109. DCHECK(audio_data_out);
  110. DCHECK(params_out);
  111. // The header should look like: |R|I|F|F|1|2|3|4|W|A|V|E|
  112. auto reader = base::BigEndianReader::FromStringPiece(wav_data);
  113. // Read the chunk ID and compare to "RIFF".
  114. base::StringPiece chunk_id;
  115. if (!reader.ReadPiece(&chunk_id, 4) || chunk_id != kChunkId) {
  116. DLOG(ERROR) << "missing or incorrect chunk ID in wav header";
  117. return false;
  118. }
  119. // The RIFF chunk length comes next, but we don't actually care what it says.
  120. if (!reader.Skip(sizeof(uint32_t))) {
  121. DLOG(ERROR) << "missing length in wav header";
  122. return false;
  123. }
  124. // Read format and compare to "WAVE".
  125. base::StringPiece format;
  126. if (!reader.ReadPiece(&format, 4) || format != kFormat) {
  127. DLOG(ERROR) << "missing or incorrect format ID in wav header";
  128. return false;
  129. }
  130. bool got_format = false;
  131. // If the number of remaining bytes is smaller than |kChunkHeaderSize|, it's
  132. // just junk at the end.
  133. while (reader.remaining() >= kChunkHeaderSize) {
  134. // We should be at the beginning of a subsection. The next 8 bytes are the
  135. // header and should look like: "|f|m|t| |1|2|3|4|" or "|d|a|t|a|1|2|3|4|".
  136. base::StringPiece chunk_fmt;
  137. uint32_t chunk_length;
  138. if (!reader.ReadPiece(&chunk_fmt, 4) || !reader.ReadU32(&chunk_length))
  139. break;
  140. chunk_length = base::ByteSwap(chunk_length);
  141. // Read |chunk_length| bytes of payload. If that is impossible, try to read
  142. // all remaining bytes as the payload.
  143. base::StringPiece chunk_payload;
  144. if (!reader.ReadPiece(&chunk_payload, chunk_length) &&
  145. !reader.ReadPiece(&chunk_payload, reader.remaining())) {
  146. break;
  147. }
  148. // Parse the subsection header, handling it if it is a "data" or "fmt "
  149. // chunk. Skip it otherwise.
  150. if (chunk_fmt == kFmtSubchunkId) {
  151. got_format = true;
  152. if (!ParseFmtChunk(chunk_payload, params_out))
  153. return false;
  154. } else if (chunk_fmt == kDataSubchunkId) {
  155. *audio_data_out = chunk_payload;
  156. } else {
  157. DVLOG(1) << "Skipping unknown data chunk: " << chunk_fmt << ".";
  158. }
  159. }
  160. // Check that data format has been read in and is valid.
  161. if (!got_format) {
  162. LOG(ERROR) << "Invalid: No \"" << kFmtSubchunkId << "\" header found!";
  163. return false;
  164. } else if (!ParamsAreValid(*params_out)) {
  165. LOG(ERROR) << "Format is invalid. "
  166. << "num_channels: " << params_out->num_channels << " "
  167. << "sample_rate: " << params_out->sample_rate << " "
  168. << "bits_per_sample: " << params_out->bits_per_sample << " "
  169. << "valid_bits_per_sample: " << params_out->valid_bits_per_sample
  170. << " "
  171. << "is_extensible: " << params_out->is_extensible;
  172. return false;
  173. }
  174. return true;
  175. }
  176. } // namespace
  177. WavAudioHandler::WavAudioHandler(base::StringPiece audio_data,
  178. uint16_t num_channels,
  179. uint32_t sample_rate,
  180. uint16_t bits_per_sample,
  181. AudioFormat audio_format)
  182. : data_(audio_data),
  183. num_channels_(num_channels),
  184. sample_rate_(sample_rate),
  185. bits_per_sample_(bits_per_sample),
  186. audio_format_(audio_format) {
  187. DCHECK_NE(num_channels_, 0u);
  188. DCHECK_NE(sample_rate_, 0u);
  189. DCHECK_NE(bits_per_sample_, 0u);
  190. total_frames_ = data_.size() * 8 / num_channels_ / bits_per_sample_;
  191. }
  192. WavAudioHandler::~WavAudioHandler() = default;
  193. // static
  194. std::unique_ptr<WavAudioHandler> WavAudioHandler::Create(
  195. const base::StringPiece wav_data) {
  196. WavAudioParameters params;
  197. base::StringPiece audio_data;
  198. // Attempt to parse the WAV data.
  199. if (!ParseWavData(wav_data, &audio_data, &params))
  200. return nullptr;
  201. return base::WrapUnique(
  202. new WavAudioHandler(audio_data, params.num_channels, params.sample_rate,
  203. params.bits_per_sample, params.audio_format));
  204. }
  205. bool WavAudioHandler::AtEnd(size_t cursor) const {
  206. return data_.size() <= cursor;
  207. }
  208. bool WavAudioHandler::CopyTo(AudioBus* bus,
  209. size_t cursor,
  210. size_t* bytes_written) const {
  211. if (!bus)
  212. return false;
  213. if (bus->channels() != num_channels_) {
  214. DVLOG(1) << "Number of channels mismatch.";
  215. return false;
  216. }
  217. if (AtEnd(cursor)) {
  218. bus->Zero();
  219. return true;
  220. }
  221. const int bytes_per_frame = num_channels_ * bits_per_sample_ / 8;
  222. const int remaining_frames = (data_.size() - cursor) / bytes_per_frame;
  223. const int frames = std::min(bus->frames(), remaining_frames);
  224. const auto* source = data_.data() + cursor;
  225. switch (audio_format_) {
  226. case AudioFormat::kAudioFormatPCM:
  227. switch (bits_per_sample_) {
  228. case 8:
  229. bus->FromInterleaved<UnsignedInt8SampleTypeTraits>(
  230. reinterpret_cast<const uint8_t*>(source), frames);
  231. break;
  232. case 16:
  233. bus->FromInterleaved<SignedInt16SampleTypeTraits>(
  234. reinterpret_cast<const int16_t*>(source), frames);
  235. break;
  236. case 32:
  237. bus->FromInterleaved<SignedInt32SampleTypeTraits>(
  238. reinterpret_cast<const int32_t*>(source), frames);
  239. break;
  240. default:
  241. NOTREACHED()
  242. << "Unsupported bytes per sample encountered for integer PCM: "
  243. << bytes_per_frame;
  244. bus->ZeroFrames(frames);
  245. }
  246. break;
  247. case AudioFormat::kAudioFormatFloat:
  248. switch (bits_per_sample_) {
  249. case 32:
  250. bus->FromInterleaved<Float32SampleTypeTraitsNoClip>(
  251. reinterpret_cast<const float*>(source), frames);
  252. break;
  253. case 64:
  254. bus->FromInterleaved<Float64SampleTypeTraits>(
  255. reinterpret_cast<const double*>(source), frames);
  256. break;
  257. default:
  258. NOTREACHED()
  259. << "Unsupported bytes per sample encountered for float PCM: "
  260. << bytes_per_frame;
  261. bus->ZeroFrames(frames);
  262. }
  263. break;
  264. default:
  265. NOTREACHED() << "Unsupported audio format encountered: "
  266. << static_cast<uint16_t>(audio_format_);
  267. bus->ZeroFrames(frames);
  268. }
  269. *bytes_written = frames * bytes_per_frame;
  270. bus->ZeroFramesPartial(frames, bus->frames() - frames);
  271. return true;
  272. }
  273. base::TimeDelta WavAudioHandler::GetDuration() const {
  274. return base::Seconds(total_frames_ / static_cast<double>(sample_rate_));
  275. }
  276. } // namespace media