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 |