| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "content/renderer/media/audio_repetition_detector.h" | 5 #include "content/renderer/media/audio_repetition_detector.h" |
| 6 | 6 |
| 7 #include <string.h> | 7 #include <string.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/ptr_util.h" |
| 12 | 13 |
| 13 namespace { | 14 namespace { |
| 14 | 15 |
| 15 const float kEpsilon = 4.0f / 32768.0f; | 16 const float kEpsilon = 4.0f / 32768.0f; |
| 16 | 17 |
| 17 } // namespace | 18 } // namespace |
| 18 | 19 |
| 19 namespace content { | 20 namespace content { |
| 20 | 21 |
| 21 AudioRepetitionDetector::AudioRepetitionDetector( | 22 AudioRepetitionDetector::AudioRepetitionDetector( |
| (...skipping 11 matching lines...) Expand all Loading... |
| 33 DCHECK(main_thread_checker_.CalledOnValidThread()); | 34 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 34 processing_thread_checker_.DetachFromThread(); | 35 processing_thread_checker_.DetachFromThread(); |
| 35 | 36 |
| 36 // Avoid duplications in |look_back_times| if any. | 37 // Avoid duplications in |look_back_times| if any. |
| 37 std::vector<int> temp(look_back_times); | 38 std::vector<int> temp(look_back_times); |
| 38 std::sort(temp.begin(), temp.end()); | 39 std::sort(temp.begin(), temp.end()); |
| 39 temp.erase(std::unique(temp.begin(), temp.end()), temp.end()); | 40 temp.erase(std::unique(temp.begin(), temp.end()), temp.end()); |
| 40 | 41 |
| 41 max_look_back_ms_ = temp.back(); | 42 max_look_back_ms_ = temp.back(); |
| 42 for (int look_back : temp) | 43 for (int look_back : temp) |
| 43 states_.push_back(new State(look_back)); | 44 states_.push_back(base::MakeUnique<State>(look_back)); |
| 44 } | 45 } |
| 45 | 46 |
| 46 AudioRepetitionDetector::~AudioRepetitionDetector() { | 47 AudioRepetitionDetector::~AudioRepetitionDetector() { |
| 47 DCHECK(main_thread_checker_.CalledOnValidThread()); | 48 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 48 } | 49 } |
| 49 | 50 |
| 50 void AudioRepetitionDetector::Detect(const float* data, size_t num_frames, | 51 void AudioRepetitionDetector::Detect(const float* data, size_t num_frames, |
| 51 size_t num_channels, int sample_rate) { | 52 size_t num_channels, int sample_rate) { |
| 52 DCHECK(processing_thread_checker_.CalledOnValidThread()); | 53 DCHECK(processing_thread_checker_.CalledOnValidThread()); |
| 53 DCHECK(!states_.empty()); | 54 DCHECK(!states_.empty()); |
| 54 | 55 |
| 55 if (num_channels != num_channels_ || sample_rate != sample_rate_) | 56 if (num_channels != num_channels_ || sample_rate != sample_rate_) |
| 56 Reset(num_channels, sample_rate); | 57 Reset(num_channels, sample_rate); |
| 57 | 58 |
| 58 // The maximum number of frames |audio_buffer_| can take in is |max_frames_|. | 59 // The maximum number of frames |audio_buffer_| can take in is |max_frames_|. |
| 59 // Therefore, input data with larger frames needs be divided into chunks. | 60 // Therefore, input data with larger frames needs be divided into chunks. |
| 60 const size_t chunk_size = max_frames_ * num_channels; | 61 const size_t chunk_size = max_frames_ * num_channels; |
| 61 while (num_frames > max_frames_) { | 62 while (num_frames > max_frames_) { |
| 62 Detect(data, max_frames_, num_channels, sample_rate); | 63 Detect(data, max_frames_, num_channels, sample_rate); |
| 63 data += chunk_size; | 64 data += chunk_size; |
| 64 num_frames -= max_frames_; | 65 num_frames -= max_frames_; |
| 65 } | 66 } |
| 66 | 67 |
| 67 if (num_frames == 0) | 68 if (num_frames == 0) |
| 68 return; | 69 return; |
| 69 | 70 |
| 70 AddFramesToBuffer(data, num_frames); | 71 AddFramesToBuffer(data, num_frames); |
| 71 | 72 |
| 72 for (size_t idx = num_frames; idx > 0; --idx, data += num_channels) { | 73 for (size_t idx = num_frames; idx > 0; --idx, data += num_channels) { |
| 73 for (State* state : states_) { | 74 for (const auto& state : states_) { |
| 74 // Look back position depends on the sample rate. It is rounded down to | 75 // Look back position depends on the sample rate. It is rounded down to |
| 75 // the closest integer. | 76 // the closest integer. |
| 76 const size_t look_back_frames = | 77 const size_t look_back_frames = |
| 77 state->look_back_ms() * sample_rate_ / 1000; | 78 state->look_back_ms() * sample_rate_ / 1000; |
| 78 // Equal(data, offset) checks if |data| equals the audio frame located | 79 // Equal(data, offset) checks if |data| equals the audio frame located |
| 79 // |offset| frames from the end of buffer. Now a full frame has been | 80 // |offset| frames from the end of buffer. Now a full frame has been |
| 80 // inserted to the buffer, and thus |offset| should compensate for it. | 81 // inserted to the buffer, and thus |offset| should compensate for it. |
| 81 if (Equal(data, look_back_frames + idx)) { | 82 if (Equal(data, look_back_frames + idx)) { |
| 82 if (!state->reported()) { | 83 if (!state->reported()) { |
| 83 state->Increment(data, num_channels); | 84 state->Increment(data, num_channels); |
| 84 if (HasValidReport(state)) { | 85 if (HasValidReport(state.get())) { |
| 85 repetition_callback_.Run(state->look_back_ms()); | 86 repetition_callback_.Run(state->look_back_ms()); |
| 86 state->set_reported(true); | 87 state->set_reported(true); |
| 87 } | 88 } |
| 88 } | 89 } |
| 89 } else { | 90 } else { |
| 90 state->Reset(); | 91 state->Reset(); |
| 91 } | 92 } |
| 92 } | 93 } |
| 93 } | 94 } |
| 94 } | 95 } |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 void AudioRepetitionDetector::Reset(size_t num_channels, int sample_rate) { | 132 void AudioRepetitionDetector::Reset(size_t num_channels, int sample_rate) { |
| 132 DCHECK(processing_thread_checker_.CalledOnValidThread()); | 133 DCHECK(processing_thread_checker_.CalledOnValidThread()); |
| 133 num_channels_ = num_channels; | 134 num_channels_ = num_channels; |
| 134 sample_rate_ = sample_rate; | 135 sample_rate_ = sample_rate; |
| 135 | 136 |
| 136 // |(xxx + 999) / 1000| is an arithmetic way to round up |xxx / 1000|. | 137 // |(xxx + 999) / 1000| is an arithmetic way to round up |xxx / 1000|. |
| 137 buffer_size_frames_ = | 138 buffer_size_frames_ = |
| 138 (max_look_back_ms_ * sample_rate_ + 999) / 1000 + max_frames_; | 139 (max_look_back_ms_ * sample_rate_ + 999) / 1000 + max_frames_; |
| 139 | 140 |
| 140 audio_buffer_.resize(buffer_size_frames_ * num_channels_); | 141 audio_buffer_.resize(buffer_size_frames_ * num_channels_); |
| 141 for (State* state : states_) | 142 for (const auto& state : states_) |
| 142 state->Reset(); | 143 state->Reset(); |
| 143 } | 144 } |
| 144 | 145 |
| 145 void AudioRepetitionDetector::AddFramesToBuffer(const float* data, | 146 void AudioRepetitionDetector::AddFramesToBuffer(const float* data, |
| 146 size_t num_frames) { | 147 size_t num_frames) { |
| 147 DCHECK(processing_thread_checker_.CalledOnValidThread()); | 148 DCHECK(processing_thread_checker_.CalledOnValidThread()); |
| 148 DCHECK_LE(num_frames, buffer_size_frames_); | 149 DCHECK_LE(num_frames, buffer_size_frames_); |
| 149 const size_t margin = buffer_size_frames_ - buffer_end_index_; | 150 const size_t margin = buffer_size_frames_ - buffer_end_index_; |
| 150 const auto it = audio_buffer_.begin() + buffer_end_index_ * num_channels_; | 151 const auto it = audio_buffer_.begin() + buffer_end_index_ * num_channels_; |
| 151 if (num_frames <= margin) { | 152 if (num_frames <= margin) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 168 const float* buffer = &audio_buffer_[look_back_index * num_channels_]; | 169 const float* buffer = &audio_buffer_[look_back_index * num_channels_]; |
| 169 return memcmp(buffer, frame, num_channels_ * sizeof(audio_buffer_[0])) == 0; | 170 return memcmp(buffer, frame, num_channels_ * sizeof(audio_buffer_[0])) == 0; |
| 170 } | 171 } |
| 171 | 172 |
| 172 bool AudioRepetitionDetector::HasValidReport(const State* state) const { | 173 bool AudioRepetitionDetector::HasValidReport(const State* state) const { |
| 173 return (!state->is_constant() && state->count_frames() >= | 174 return (!state->is_constant() && state->count_frames() >= |
| 174 static_cast<size_t>(min_length_ms_ * sample_rate_ / 1000)); | 175 static_cast<size_t>(min_length_ms_ * sample_rate_ / 1000)); |
| 175 } | 176 } |
| 176 | 177 |
| 177 } // namespace content | 178 } // namespace content |
| OLD | NEW |