Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/audio/sounds/wav_audio_handler.h" | 5 #include "media/audio/sounds/wav_audio_handler.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cstring> | 8 #include <cstring> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 48 result = base::ByteSwap(result); | 48 result = base::ByteSwap(result); |
| 49 #endif | 49 #endif |
| 50 return result; | 50 return result; |
| 51 } | 51 } |
| 52 | 52 |
| 53 } // namespace | 53 } // namespace |
| 54 | 54 |
| 55 namespace media { | 55 namespace media { |
| 56 | 56 |
| 57 WavAudioHandler::WavAudioHandler(const base::StringPiece& wav_data) | 57 WavAudioHandler::WavAudioHandler(const base::StringPiece& wav_data) |
| 58 : num_channels_(0), sample_rate_(0), bits_per_sample_(0), total_frames_(0) { | 58 : is_valid_(false), |
| 59 CHECK_LE(kWavFileHeaderSize, wav_data.size()) << "wav data is too small"; | 59 num_channels_(0), |
| 60 CHECK(wav_data.starts_with(kChunkId) && | 60 sample_rate_(0), |
| 61 memcmp(wav_data.data() + 8, kFormat, 4) == 0) | 61 bits_per_sample_(0), |
| 62 << "incorrect wav header"; | 62 total_frames_(0) { |
| 63 if (wav_data.size() < kWavFileHeaderSize) { | |
| 64 LOG(ERROR) << "wav_data is too small"; | |
| 65 return; | |
| 66 } | |
| 67 if (!wav_data.starts_with(kChunkId) || | |
| 68 memcmp(wav_data.data() + 8, kFormat, 4) != 0) { | |
| 69 LOG(ERROR) << "incorrect wav header"; | |
| 70 return; | |
| 71 } | |
| 63 | 72 |
| 64 uint32 total_length = std::min(ReadInt<uint32>(wav_data, 4), | 73 uint32 total_length = std::min(ReadInt<uint32>(wav_data, 4), |
| 65 static_cast<uint32>(wav_data.size())); | 74 static_cast<uint32>(wav_data.size())); |
| 66 uint32 offset = kWavFileHeaderSize; | 75 uint32 offset = kWavFileHeaderSize; |
| 67 while (offset < total_length) { | 76 while (offset < total_length) { |
| 68 const int length = ParseSubChunk(wav_data.substr(offset)); | 77 const int length = ParseSubChunk(wav_data.substr(offset)); |
| 69 CHECK_LE(0, length) << "can't parse wav sub-chunk"; | 78 if (length < 0) { |
| 79 LOG(ERROR) << "can't parse wav sub-chunk"; | |
| 80 ResetAll(); | |
| 81 return; | |
| 82 } | |
| 70 offset += length; | 83 offset += length; |
| 71 } | 84 } |
| 72 | 85 |
| 86 if (num_channels_ == 0u || bits_per_sample_ == 0u || sample_rate_ == 0u) { | |
|
tommi (sloooow) - chröme
2015/11/17 20:48:39
nit: could this expression be is_valid() or do we
slan
2015/11/17 21:50:16
Done.
| |
| 87 LOG(ERROR) << "Format is invalid. " | |
| 88 << "num_channels: " << num_channels_ << " " | |
| 89 << "sample_rate: " << sample_rate_ << " " | |
| 90 << "bits_per_sample: " << bits_per_sample_; | |
| 91 ResetAll(); | |
| 92 return; | |
| 93 } | |
| 94 | |
| 95 // The audio chunk has parsed successfully. | |
| 96 is_valid_ = true; | |
| 73 total_frames_ = data_.size() * 8 / num_channels_ / bits_per_sample_; | 97 total_frames_ = data_.size() * 8 / num_channels_ / bits_per_sample_; |
| 74 } | 98 } |
| 75 | 99 |
| 76 WavAudioHandler::~WavAudioHandler() {} | 100 WavAudioHandler::~WavAudioHandler() {} |
| 77 | 101 |
| 78 bool WavAudioHandler::AtEnd(size_t cursor) const { | 102 bool WavAudioHandler::AtEnd(size_t cursor) const { |
| 79 return data_.size() <= cursor; | 103 return is_valid_ ? data_.size() <= cursor : true; |
|
tommi (sloooow) - chröme
2015/11/17 20:48:39
nit: could also do
return !is_valid() || data_.siz
slan
2015/11/17 21:50:16
In practice, this object should not be used if is_
tommi (sloooow) - chröme
2015/11/18 11:52:58
That sounds like a good idea to me and would simpl
| |
| 80 } | 104 } |
| 81 | 105 |
| 82 bool WavAudioHandler::CopyTo(AudioBus* bus, | 106 bool WavAudioHandler::CopyTo(AudioBus* bus, |
| 83 size_t cursor, | 107 size_t cursor, |
| 84 size_t* bytes_written) const { | 108 size_t* bytes_written) const { |
| 85 if (!bus) | 109 if (!is_valid_ || !bus) |
| 86 return false; | 110 return false; |
| 87 if (bus->channels() != num_channels_) { | 111 if (bus->channels() != num_channels_) { |
| 88 DVLOG(1) << "Number of channels mismatch."; | 112 DVLOG(1) << "Number of channels mismatch."; |
| 89 return false; | 113 return false; |
| 90 } | 114 } |
| 91 if (AtEnd(cursor)) { | 115 if (AtEnd(cursor)) { |
| 92 bus->Zero(); | 116 bus->Zero(); |
| 93 return true; | 117 return true; |
| 94 } | 118 } |
| 95 const int bytes_per_frame = num_channels_ * bits_per_sample_ / 8; | 119 const int bytes_per_frame = num_channels_ * bits_per_sample_ / 8; |
| 96 const int remaining_frames = (data_.size() - cursor) / bytes_per_frame; | 120 const int remaining_frames = (data_.size() - cursor) / bytes_per_frame; |
| 97 const int frames = std::min(bus->frames(), remaining_frames); | 121 const int frames = std::min(bus->frames(), remaining_frames); |
| 98 | 122 |
| 99 bus->FromInterleaved(data_.data() + cursor, frames, bits_per_sample_ / 8); | 123 bus->FromInterleaved(data_.data() + cursor, frames, bits_per_sample_ / 8); |
| 100 *bytes_written = frames * bytes_per_frame; | 124 *bytes_written = frames * bytes_per_frame; |
| 101 bus->ZeroFramesPartial(frames, bus->frames() - frames); | 125 bus->ZeroFramesPartial(frames, bus->frames() - frames); |
| 102 return true; | 126 return true; |
| 103 } | 127 } |
| 104 | 128 |
| 105 base::TimeDelta WavAudioHandler::GetDuration() const { | 129 base::TimeDelta WavAudioHandler::GetDuration() const { |
| 106 return base::TimeDelta::FromSecondsD(total_frames_ / | 130 return is_valid_ ? base::TimeDelta::FromSecondsD( |
| 107 static_cast<double>(sample_rate_)); | 131 total_frames_ / static_cast<double>(sample_rate_)) |
| 132 : base::TimeDelta(); | |
| 108 } | 133 } |
| 109 | 134 |
| 110 int WavAudioHandler::ParseSubChunk(const base::StringPiece& data) { | 135 int WavAudioHandler::ParseSubChunk(const base::StringPiece& data) { |
| 111 if (data.size() < kChunkHeaderSize) | 136 if (data.size() < kChunkHeaderSize) |
| 112 return data.size(); | 137 return data.size(); |
| 113 uint32 chunk_length = ReadInt<uint32>(data, 4); | 138 uint32 chunk_length = ReadInt<uint32>(data, 4); |
| 114 if (data.starts_with(kSubchunk1Id)) { | 139 if (data.starts_with(kSubchunk1Id)) { |
| 115 if (!ParseFmtChunk(data.substr(kChunkHeaderSize, chunk_length))) | 140 if (!ParseFmtChunk(data.substr(kChunkHeaderSize, chunk_length))) |
| 116 return -1; | 141 return -1; |
| 117 } else if (data.starts_with(kSubchunk2Id)) { | 142 } else if (data.starts_with(kSubchunk2Id)) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 133 sample_rate_ = ReadInt<uint32>(data, kSampleRateOffset); | 158 sample_rate_ = ReadInt<uint32>(data, kSampleRateOffset); |
| 134 bits_per_sample_ = ReadInt<uint16>(data, kBitsPerSampleOffset); | 159 bits_per_sample_ = ReadInt<uint16>(data, kBitsPerSampleOffset); |
| 135 return true; | 160 return true; |
| 136 } | 161 } |
| 137 | 162 |
| 138 bool WavAudioHandler::ParseDataChunk(const base::StringPiece& data) { | 163 bool WavAudioHandler::ParseDataChunk(const base::StringPiece& data) { |
| 139 data_ = data; | 164 data_ = data; |
| 140 return true; | 165 return true; |
| 141 } | 166 } |
| 142 | 167 |
| 168 void WavAudioHandler::ResetAll() { | |
| 169 DCHECK(!is_valid_); | |
| 170 data_ = base::StringPiece(); | |
|
tommi (sloooow) - chröme
2015/11/17 20:48:39
another potential implementation for is_valid();
slan
2015/11/17 21:50:16
I like the idea you left above. Theoretically, we
| |
| 171 num_channels_ = 0u; | |
| 172 sample_rate_ = 0u; | |
| 173 bits_per_sample_ = 0u; | |
| 174 total_frames_ = 0u; | |
| 175 } | |
| 176 | |
| 143 } // namespace media | 177 } // namespace media |
| OLD | NEW |