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 "chromecast/media/cma/backend/alsa/audio_decoder_alsa.h" | 5 #include "chromecast/media/cma/backend/alsa/audio_decoder_alsa.h" |
6 | 6 |
7 #include <time.h> | 7 #include <time.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <limits> | 10 #include <limits> |
11 | 11 |
12 #include "base/callback_helpers.h" | 12 #include "base/callback_helpers.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/macros.h" | 14 #include "base/macros.h" |
15 #include "base/trace_event/trace_event.h" | 15 #include "base/trace_event/trace_event.h" |
16 #include "chromecast/base/task_runner_impl.h" | 16 #include "chromecast/base/task_runner_impl.h" |
17 #include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" | 17 #include "chromecast/media/cma/backend/alsa/media_pipeline_backend_alsa.h" |
18 #include "chromecast/media/cma/base/decoder_buffer_adapter.h" | |
18 #include "chromecast/media/cma/base/decoder_buffer_base.h" | 19 #include "chromecast/media/cma/base/decoder_buffer_base.h" |
19 #include "chromecast/public/media/cast_decoder_buffer.h" | 20 #include "chromecast/public/media/cast_decoder_buffer.h" |
21 #include "media/base/audio_buffer.h" | |
22 #include "media/base/audio_bus.h" | |
23 #include "media/base/channel_layout.h" | |
24 #include "media/base/decoder_buffer.h" | |
25 #include "media/base/sample_format.h" | |
26 #include "media/filters/audio_renderer_algorithm.h" | |
20 | 27 |
21 #define TRACE_FUNCTION_ENTRY0() TRACE_EVENT0("cma", __FUNCTION__) | 28 #define TRACE_FUNCTION_ENTRY0() TRACE_EVENT0("cma", __FUNCTION__) |
22 | 29 |
23 #define TRACE_FUNCTION_ENTRY1(arg1) \ | 30 #define TRACE_FUNCTION_ENTRY1(arg1) \ |
24 TRACE_EVENT1("cma", __FUNCTION__, #arg1, arg1) | 31 TRACE_EVENT1("cma", __FUNCTION__, #arg1, arg1) |
25 | 32 |
26 #define TRACE_FUNCTION_ENTRY2(arg1, arg2) \ | 33 #define TRACE_FUNCTION_ENTRY2(arg1, arg2) \ |
27 TRACE_EVENT2("cma", __FUNCTION__, #arg1, arg1, #arg2, arg2) | 34 TRACE_EVENT2("cma", __FUNCTION__, #arg1, arg1, #arg2, arg2) |
28 | 35 |
29 namespace chromecast { | 36 namespace chromecast { |
30 namespace media { | 37 namespace media { |
31 | 38 |
32 namespace { | 39 namespace { |
33 | 40 |
41 const int kBitsPerSample = 32; | |
42 const int kDefaultFramesPerBuffer = 1024; | |
43 const int kSilenceBufferFrames = 2048; | |
44 const int kMaxOutputMs = 20; | |
45 | |
46 const double kPlaybackRateEpsilon = 0.001; | |
47 | |
34 const CastAudioDecoder::OutputFormat kDecoderSampleFormat = | 48 const CastAudioDecoder::OutputFormat kDecoderSampleFormat = |
35 CastAudioDecoder::kOutputPlanarFloat; | 49 CastAudioDecoder::kOutputPlanarFloat; |
36 | 50 |
37 const int64_t kInvalidDelayTimestamp = std::numeric_limits<int64_t>::min(); | 51 const int64_t kInvalidTimestamp = std::numeric_limits<int64_t>::min(); |
38 | |
39 AudioDecoderAlsa::RenderingDelay kInvalidRenderingDelay() { | |
40 AudioDecoderAlsa::RenderingDelay delay; | |
41 delay.timestamp_microseconds = kInvalidDelayTimestamp; | |
42 delay.delay_microseconds = 0; | |
43 return delay; | |
44 } | |
45 | 52 |
46 } // namespace | 53 } // namespace |
47 | 54 |
55 AudioDecoderAlsa::RateShifterInfo::RateShifterInfo(float playback_rate) | |
56 : rate(playback_rate), input_frames(0), output_frames(0) {} | |
57 | |
48 AudioDecoderAlsa::AudioDecoderAlsa(MediaPipelineBackendAlsa* backend) | 58 AudioDecoderAlsa::AudioDecoderAlsa(MediaPipelineBackendAlsa* backend) |
49 : backend_(backend), | 59 : backend_(backend), |
50 task_runner_(backend->GetTaskRunner()), | 60 task_runner_(backend->GetTaskRunner()), |
51 delegate_(nullptr), | 61 delegate_(nullptr), |
52 is_eos_(false), | 62 pending_write_pcm_(false), |
63 pending_buffer_complete_(false), | |
64 got_eos_(false), | |
65 pushed_eos_(false), | |
53 error_(false), | 66 error_(false), |
67 rate_shifter_output_( | |
68 ::media::AudioBus::Create(2, kDefaultFramesPerBuffer)), | |
slan
2016/12/07 00:22:27
nit: Can we do "2 /* num_channels */" or kNumChann
kmackay
2016/12/07 22:59:57
Done.
| |
69 current_pts_(kInvalidTimestamp), | |
70 pending_output_frames_(0), | |
54 volume_multiplier_(1.0f), | 71 volume_multiplier_(1.0f), |
55 weak_factory_(this) { | 72 weak_factory_(this) { |
56 TRACE_FUNCTION_ENTRY0(); | 73 TRACE_FUNCTION_ENTRY0(); |
57 DCHECK(backend_); | 74 DCHECK(backend_); |
58 DCHECK(task_runner_.get()); | 75 DCHECK(task_runner_.get()); |
59 DCHECK(task_runner_->BelongsToCurrentThread()); | 76 DCHECK(task_runner_->BelongsToCurrentThread()); |
77 rate_shifter_info_.push_back(RateShifterInfo(1.0f)); | |
slan
2016/12/07 00:22:27
Why do we need this call? The queue is cleared whe
kmackay
2016/12/07 22:59:57
We don't; removed
| |
60 } | 78 } |
61 | 79 |
62 AudioDecoderAlsa::~AudioDecoderAlsa() { | 80 AudioDecoderAlsa::~AudioDecoderAlsa() { |
63 TRACE_FUNCTION_ENTRY0(); | 81 TRACE_FUNCTION_ENTRY0(); |
64 DCHECK(task_runner_->BelongsToCurrentThread()); | 82 DCHECK(task_runner_->BelongsToCurrentThread()); |
65 } | 83 } |
66 | 84 |
67 void AudioDecoderAlsa::SetDelegate( | 85 void AudioDecoderAlsa::SetDelegate( |
68 MediaPipelineBackend::Decoder::Delegate* delegate) { | 86 MediaPipelineBackend::Decoder::Delegate* delegate) { |
69 DCHECK(delegate); | 87 DCHECK(delegate); |
70 delegate_ = delegate; | 88 delegate_ = delegate; |
71 } | 89 } |
72 | 90 |
73 void AudioDecoderAlsa::Initialize() { | 91 void AudioDecoderAlsa::Initialize() { |
74 TRACE_FUNCTION_ENTRY0(); | 92 TRACE_FUNCTION_ENTRY0(); |
75 DCHECK(delegate_); | 93 DCHECK(delegate_); |
76 stats_ = Statistics(); | 94 stats_ = Statistics(); |
77 is_eos_ = false; | 95 pending_write_pcm_ = false; |
78 last_buffer_pts_ = std::numeric_limits<int64_t>::min(); | 96 pending_buffer_complete_ = false; |
97 got_eos_ = false; | |
98 pushed_eos_ = false; | |
99 current_pts_ = kInvalidTimestamp; | |
100 pending_output_frames_ = 0; | |
79 | 101 |
80 last_known_delay_.timestamp_microseconds = kInvalidDelayTimestamp; | 102 last_known_delay_.timestamp_microseconds = kInvalidTimestamp; |
81 last_known_delay_.delay_microseconds = 0; | 103 last_known_delay_.delay_microseconds = 0; |
82 } | 104 } |
83 | 105 |
84 bool AudioDecoderAlsa::Start(int64_t start_pts) { | 106 bool AudioDecoderAlsa::Start(int64_t start_pts) { |
85 TRACE_FUNCTION_ENTRY0(); | 107 TRACE_FUNCTION_ENTRY0(); |
86 current_pts_ = start_pts; | 108 current_pts_ = start_pts; |
87 DCHECK(IsValidConfig(config_)); | 109 DCHECK(IsValidConfig(config_)); |
88 mixer_input_.reset(new StreamMixerAlsaInput( | 110 mixer_input_.reset(new StreamMixerAlsaInput( |
89 this, config_.samples_per_second, backend_->Primary())); | 111 this, config_.samples_per_second, backend_->Primary())); |
90 mixer_input_->SetVolumeMultiplier(volume_multiplier_); | 112 mixer_input_->SetVolumeMultiplier(volume_multiplier_); |
91 // Create decoder_ if necessary. This can happen if Stop() was called, and | 113 // Create decoder_ if necessary. This can happen if Stop() was called, and |
92 // SetConfig() was not called since then. | 114 // SetConfig() was not called since then. |
93 if (!decoder_) | 115 if (!decoder_) { |
94 CreateDecoder(); | 116 CreateDecoder(); |
117 } | |
118 if (!rate_shifter_) { | |
119 CreateRateShifter(config_.samples_per_second); | |
120 } | |
95 return true; | 121 return true; |
96 } | 122 } |
97 | 123 |
98 void AudioDecoderAlsa::Stop() { | 124 void AudioDecoderAlsa::Stop() { |
99 TRACE_FUNCTION_ENTRY0(); | 125 TRACE_FUNCTION_ENTRY0(); |
100 decoder_.reset(); | 126 decoder_.reset(); |
101 mixer_input_.reset(); | 127 mixer_input_.reset(); |
128 rate_shifter_.reset(); | |
129 weak_factory_.InvalidateWeakPtrs(); | |
102 | 130 |
103 Initialize(); | 131 Initialize(); |
104 } | 132 } |
105 | 133 |
106 bool AudioDecoderAlsa::Pause() { | 134 bool AudioDecoderAlsa::Pause() { |
107 TRACE_FUNCTION_ENTRY0(); | 135 TRACE_FUNCTION_ENTRY0(); |
108 DCHECK(mixer_input_); | 136 DCHECK(mixer_input_); |
109 mixer_input_->SetPaused(true); | 137 mixer_input_->SetPaused(true); |
110 return true; | 138 return true; |
111 } | 139 } |
112 | 140 |
113 bool AudioDecoderAlsa::Resume() { | 141 bool AudioDecoderAlsa::Resume() { |
114 TRACE_FUNCTION_ENTRY0(); | 142 TRACE_FUNCTION_ENTRY0(); |
115 DCHECK(mixer_input_); | 143 DCHECK(mixer_input_); |
116 mixer_input_->SetPaused(false); | 144 mixer_input_->SetPaused(false); |
117 return true; | 145 return true; |
118 } | 146 } |
119 | 147 |
148 bool AudioDecoderAlsa::SetPlaybackRate(float rate) { | |
149 if (std::abs(rate - 1.0) < kPlaybackRateEpsilon) { | |
slan
2016/12/07 00:22:27
Why this check? Are we worried about apps setting
kmackay
2016/12/07 22:59:57
AudioRendererAlgorithm treats values close to 1 as
| |
150 rate = 1.0f; | |
151 } | |
152 LOG(INFO) << "SetPlaybackRate to " << rate; | |
153 | |
154 while (!rate_shifter_info_.empty() && | |
155 rate_shifter_info_.back().input_frames == 0) { | |
156 rate_shifter_info_.pop_back(); | |
157 } | |
158 rate_shifter_info_.push_back(RateShifterInfo(rate)); | |
159 return true; | |
160 } | |
161 | |
120 AudioDecoderAlsa::BufferStatus AudioDecoderAlsa::PushBuffer( | 162 AudioDecoderAlsa::BufferStatus AudioDecoderAlsa::PushBuffer( |
121 CastDecoderBuffer* buffer) { | 163 CastDecoderBuffer* buffer) { |
122 TRACE_FUNCTION_ENTRY0(); | 164 TRACE_FUNCTION_ENTRY0(); |
123 DCHECK(task_runner_->BelongsToCurrentThread()); | 165 DCHECK(task_runner_->BelongsToCurrentThread()); |
124 DCHECK(buffer); | 166 DCHECK(buffer); |
125 DCHECK(!is_eos_); | 167 DCHECK(!got_eos_); |
126 DCHECK(!error_); | 168 DCHECK(!error_); |
169 DCHECK(!pending_buffer_complete_); | |
127 | 170 |
128 uint64_t input_bytes = buffer->end_of_stream() ? 0 : buffer->data_size(); | 171 uint64_t input_bytes = buffer->end_of_stream() ? 0 : buffer->data_size(); |
129 scoped_refptr<DecoderBufferBase> buffer_base( | 172 scoped_refptr<DecoderBufferBase> buffer_base( |
130 static_cast<DecoderBufferBase*>(buffer)); | 173 static_cast<DecoderBufferBase*>(buffer)); |
131 if (!buffer->end_of_stream()) { | 174 if (!buffer->end_of_stream()) { |
132 last_buffer_pts_ = buffer->timestamp(); | 175 current_pts_ = buffer->timestamp(); |
133 current_pts_ = std::min(current_pts_, last_buffer_pts_); | |
134 } | 176 } |
135 | 177 |
136 // If the buffer is already decoded, do not attempt to decode. Call | 178 // If the buffer is already decoded, do not attempt to decode. Call |
137 // OnBufferDecoded asynchronously on the main thread. | 179 // OnBufferDecoded asynchronously on the main thread. |
138 if (BypassDecoder()) { | 180 if (BypassDecoder()) { |
139 DCHECK(!decoder_); | 181 DCHECK(!decoder_); |
140 task_runner_->PostTask( | 182 task_runner_->PostTask( |
141 FROM_HERE, | 183 FROM_HERE, |
142 base::Bind(&AudioDecoderAlsa::OnBufferDecoded, | 184 base::Bind(&AudioDecoderAlsa::OnBufferDecoded, |
143 weak_factory_.GetWeakPtr(), input_bytes, | 185 weak_factory_.GetWeakPtr(), input_bytes, |
(...skipping 23 matching lines...) Expand all Loading... | |
167 } | 209 } |
168 | 210 |
169 bool AudioDecoderAlsa::SetConfig(const AudioConfig& config) { | 211 bool AudioDecoderAlsa::SetConfig(const AudioConfig& config) { |
170 TRACE_FUNCTION_ENTRY0(); | 212 TRACE_FUNCTION_ENTRY0(); |
171 DCHECK(task_runner_->BelongsToCurrentThread()); | 213 DCHECK(task_runner_->BelongsToCurrentThread()); |
172 if (!IsValidConfig(config)) { | 214 if (!IsValidConfig(config)) { |
173 LOG(ERROR) << "Invalid audio config passed to SetConfig"; | 215 LOG(ERROR) << "Invalid audio config passed to SetConfig"; |
174 return false; | 216 return false; |
175 } | 217 } |
176 | 218 |
219 if (!rate_shifter_ || | |
220 config.samples_per_second != config_.samples_per_second) { | |
221 CreateRateShifter(config.samples_per_second); | |
222 } | |
223 | |
177 if (mixer_input_ && config.samples_per_second != config_.samples_per_second) { | 224 if (mixer_input_ && config.samples_per_second != config_.samples_per_second) { |
178 // Destroy the old input first to ensure that the mixer output sample rate | 225 // Destroy the old input first to ensure that the mixer output sample rate |
179 // is updated. | 226 // is updated. |
180 mixer_input_.reset(); | 227 mixer_input_.reset(); |
181 mixer_input_.reset(new StreamMixerAlsaInput( | 228 mixer_input_.reset(new StreamMixerAlsaInput( |
182 this, config.samples_per_second, backend_->Primary())); | 229 this, config.samples_per_second, backend_->Primary())); |
183 mixer_input_->SetVolumeMultiplier(volume_multiplier_); | 230 mixer_input_->SetVolumeMultiplier(volume_multiplier_); |
231 pending_write_pcm_ = false; | |
232 pending_output_frames_ = 0; | |
184 } | 233 } |
185 | 234 |
186 config_ = config; | 235 config_ = config; |
187 decoder_.reset(); | 236 decoder_.reset(); |
188 CreateDecoder(); | 237 CreateDecoder(); |
238 | |
239 if (pending_buffer_complete_ && !rate_shifter_->IsQueueFull()) { | |
slan
2016/12/07 00:22:27
Why do we need to check the rate_shifter queue her
kmackay
2016/12/07 22:59:57
We need to have flow control, so the app doesn't p
slan
2016/12/09 00:05:31
Acknowledged.
| |
240 pending_buffer_complete_ = false; | |
241 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferSuccess); | |
242 } | |
189 return true; | 243 return true; |
190 } | 244 } |
191 | 245 |
192 void AudioDecoderAlsa::CreateDecoder() { | 246 void AudioDecoderAlsa::CreateDecoder() { |
193 DCHECK(!decoder_); | 247 DCHECK(!decoder_); |
194 DCHECK(IsValidConfig(config_)); | 248 DCHECK(IsValidConfig(config_)); |
195 | 249 |
196 // No need to create a decoder if the samples are already decoded. | 250 // No need to create a decoder if the samples are already decoded. |
197 if (BypassDecoder()) { | 251 if (BypassDecoder()) { |
198 LOG(INFO) << "Data is not coded. Decoder will not be used."; | 252 LOG(INFO) << "Data is not coded. Decoder will not be used."; |
199 return; | 253 return; |
200 } | 254 } |
201 | 255 |
202 // Create a decoder. | 256 // Create a decoder. |
203 decoder_ = CastAudioDecoder::Create( | 257 decoder_ = CastAudioDecoder::Create( |
204 task_runner_, | 258 task_runner_, |
205 config_, | 259 config_, |
206 kDecoderSampleFormat, | 260 kDecoderSampleFormat, |
207 base::Bind(&AudioDecoderAlsa::OnDecoderInitialized, | 261 base::Bind(&AudioDecoderAlsa::OnDecoderInitialized, |
208 weak_factory_.GetWeakPtr())); | 262 weak_factory_.GetWeakPtr())); |
209 } | 263 } |
210 | 264 |
265 void AudioDecoderAlsa::CreateRateShifter(int samples_per_second) { | |
slan
2016/12/07 00:22:27
Do we want to DCHECK that rate_shifter_ is flushed
kmackay
2016/12/07 22:59:58
No; it might not be in some cases (eg, sample rate
slan
2016/12/09 00:05:31
In that case, wouldn't we want to play out the aud
kmackay
2016/12/09 00:21:16
Ideally yes, but we're already resetting the mixer
| |
266 rate_shifter_info_.clear(); | |
267 rate_shifter_info_.push_back(RateShifterInfo(1.0f)); | |
268 | |
269 rate_shifter_.reset(new ::media::AudioRendererAlgorithm()); | |
270 rate_shifter_->Initialize(::media::AudioParameters( | |
271 ::media::AudioParameters::AUDIO_PCM_LINEAR, | |
272 ::media::CHANNEL_LAYOUT_STEREO, samples_per_second, kBitsPerSample, | |
273 kDefaultFramesPerBuffer)); | |
274 } | |
275 | |
211 bool AudioDecoderAlsa::SetVolume(float multiplier) { | 276 bool AudioDecoderAlsa::SetVolume(float multiplier) { |
212 TRACE_FUNCTION_ENTRY1(multiplier); | 277 TRACE_FUNCTION_ENTRY1(multiplier); |
213 DCHECK(task_runner_->BelongsToCurrentThread()); | 278 DCHECK(task_runner_->BelongsToCurrentThread()); |
214 volume_multiplier_ = multiplier; | 279 volume_multiplier_ = multiplier; |
215 if (mixer_input_) | 280 if (mixer_input_) |
216 mixer_input_->SetVolumeMultiplier(volume_multiplier_); | 281 mixer_input_->SetVolumeMultiplier(volume_multiplier_); |
217 return true; | 282 return true; |
218 } | 283 } |
219 | 284 |
220 AudioDecoderAlsa::RenderingDelay AudioDecoderAlsa::GetRenderingDelay() { | 285 AudioDecoderAlsa::RenderingDelay AudioDecoderAlsa::GetRenderingDelay() { |
221 TRACE_FUNCTION_ENTRY0(); | 286 TRACE_FUNCTION_ENTRY0(); |
222 return last_known_delay_; | 287 AudioDecoderAlsa::RenderingDelay delay = last_known_delay_; |
288 if (delay.timestamp_microseconds != kInvalidTimestamp) { | |
289 double usec_per_sample = 1000000.0 / config_.samples_per_second; | |
290 for (const RateShifterInfo& info : rate_shifter_info_) { | |
slan
2016/12/07 00:22:27
This is dense. Could you put a simple comment insi
kmackay
2016/12/07 22:59:58
Added comments. The last_known_delay_ is the last
slan
2016/12/09 00:05:31
OK, I get it now.
| |
291 double queued_output_frames = | |
292 (info.input_frames / info.rate) - info.output_frames; | |
293 delay.delay_microseconds += queued_output_frames * usec_per_sample; | |
294 } | |
295 | |
296 delay.delay_microseconds += pending_output_frames_ * usec_per_sample; | |
297 } | |
298 | |
299 return delay; | |
223 } | 300 } |
224 | 301 |
225 void AudioDecoderAlsa::OnDecoderInitialized(bool success) { | 302 void AudioDecoderAlsa::OnDecoderInitialized(bool success) { |
226 TRACE_FUNCTION_ENTRY0(); | 303 TRACE_FUNCTION_ENTRY0(); |
227 DCHECK(task_runner_->BelongsToCurrentThread()); | 304 DCHECK(task_runner_->BelongsToCurrentThread()); |
228 LOG(INFO) << "Decoder initialization was " | 305 LOG(INFO) << "Decoder initialization was " |
229 << (success ? "successful" : "unsuccessful"); | 306 << (success ? "successful" : "unsuccessful"); |
230 if (!success) | 307 if (!success) |
231 delegate_->OnDecoderError(); | 308 delegate_->OnDecoderError(); |
232 } | 309 } |
233 | 310 |
234 void AudioDecoderAlsa::OnBufferDecoded( | 311 void AudioDecoderAlsa::OnBufferDecoded( |
235 uint64_t input_bytes, | 312 uint64_t input_bytes, |
236 CastAudioDecoder::Status status, | 313 CastAudioDecoder::Status status, |
237 const scoped_refptr<DecoderBufferBase>& decoded) { | 314 const scoped_refptr<DecoderBufferBase>& decoded) { |
238 TRACE_FUNCTION_ENTRY0(); | 315 TRACE_FUNCTION_ENTRY0(); |
239 DCHECK(task_runner_->BelongsToCurrentThread()); | 316 DCHECK(task_runner_->BelongsToCurrentThread()); |
240 DCHECK(!is_eos_); | 317 DCHECK(!got_eos_); |
241 | 318 DCHECK(!pending_buffer_complete_); |
242 Statistics delta = Statistics(); | 319 DCHECK(rate_shifter_); |
243 | 320 |
244 if (status == CastAudioDecoder::Status::kDecodeError) { | 321 if (status == CastAudioDecoder::Status::kDecodeError) { |
245 LOG(ERROR) << "Decode error"; | 322 LOG(ERROR) << "Decode error"; |
246 task_runner_->PostTask(FROM_HERE, | 323 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferFailed); |
247 base::Bind(&AudioDecoderAlsa::OnWritePcmCompletion, | 324 return; |
248 weak_factory_.GetWeakPtr(), | 325 } |
249 MediaPipelineBackendAlsa::kBufferFailed, | 326 if (error_) { |
slan
2016/12/07 00:22:27
Can we rename this variable to mixer_error_? This
kmackay
2016/12/07 22:59:58
Done.
| |
250 kInvalidRenderingDelay())); | 327 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferFailed); |
251 UpdateStatistics(delta); | |
252 return; | 328 return; |
253 } | 329 } |
254 | 330 |
331 Statistics delta; | |
255 delta.decoded_bytes = input_bytes; | 332 delta.decoded_bytes = input_bytes; |
256 UpdateStatistics(delta); | 333 UpdateStatistics(delta); |
257 | 334 |
258 if (decoded->end_of_stream()) | 335 if (decoded->end_of_stream()) { |
259 is_eos_ = true; | 336 got_eos_ = true; |
337 } else { | |
338 int input_frames = decoded->data_size() / (2 * sizeof(float)); | |
slan
2016/12/07 00:22:27
nit: kNumChannels
kmackay
2016/12/07 22:59:57
Done.
| |
260 | 339 |
340 RateShifterInfo* rate_info = &rate_shifter_info_.front(); | |
341 // Bypass rate shifter if the rate is 1.0. | |
342 if (rate_info->rate == 1.0 && rate_shifter_->frames_buffered() == 0 && | |
343 !pending_write_pcm_) { | |
344 DCHECK_EQ(rate_info->output_frames, rate_info->input_frames); | |
345 pending_buffer_complete_ = true; | |
346 pending_write_pcm_ = true; | |
347 pending_output_frames_ = input_frames; | |
348 if (got_eos_) { | |
halliwell
2016/12/06 17:27:59
I don't think this branch can be hit? DCHECK(!got
slan
2016/12/07 00:22:27
got_eos_ can mutate above (line 336)
meganit, tho
kmackay
2016/12/07 22:59:57
I prefer to set the state variables before calling
slan
2016/12/09 00:05:31
Yes, I suppose that's fair...
| |
349 DCHECK(!pushed_eos_); | |
350 pushed_eos_ = true; | |
351 } | |
352 mixer_input_->WritePcm(decoded); | |
353 return; | |
354 } | |
355 | |
356 const uint8_t* channels[2] = { | |
slan
2016/12/07 00:22:27
Add comment:
// Otherwise, if the rate is not 1.0
kmackay
2016/12/07 22:59:57
Done.
| |
357 decoded->data(), decoded->data() + input_frames * sizeof(float)}; | |
358 scoped_refptr<::media::AudioBuffer> buffer = ::media::AudioBuffer::CopyFrom( | |
359 ::media::kSampleFormatPlanarF32, ::media::CHANNEL_LAYOUT_STEREO, 2, | |
360 config_.samples_per_second, input_frames, channels, base::TimeDelta()); | |
361 rate_shifter_->EnqueueBuffer(buffer); | |
362 rate_shifter_info_.back().input_frames += input_frames; | |
363 } | |
364 | |
365 PushRateShifted(); | |
366 if (decoded->end_of_stream() || (!rate_shifter_->IsQueueFull() && | |
slan
2016/12/07 00:22:27
Why not check got_eos_?
kmackay
2016/12/07 22:59:57
Added comment.
| |
367 rate_shifter_info_.front().rate != 1.0)) { | |
368 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferSuccess); | |
369 } else { | |
370 pending_buffer_complete_ = true; | |
371 } | |
372 } | |
373 | |
374 void AudioDecoderAlsa::PushRateShifted() { | |
261 DCHECK(mixer_input_); | 375 DCHECK(mixer_input_); |
262 mixer_input_->WritePcm(decoded); | 376 |
377 if (pending_write_pcm_) { | |
378 return; | |
379 } | |
380 | |
381 if (got_eos_) { | |
382 // Push some silence into the rate shifter so we can get out any remaining | |
383 // rate-shifted data. | |
slan
2016/12/07 00:22:27
Perhaps make this an anonymous function that takes
kmackay
2016/12/07 22:59:57
Done.
| |
384 scoped_refptr<::media::AudioBuffer> silence_buffer = | |
385 ::media::AudioBuffer::CreateBuffer( | |
386 ::media::kSampleFormatPlanarF32, ::media::CHANNEL_LAYOUT_STEREO, 2, | |
387 config_.samples_per_second, kSilenceBufferFrames); | |
388 for (uint8_t* channel : silence_buffer->channel_data()) { | |
389 float* real_channel = reinterpret_cast<float*>(channel); | |
390 std::fill_n(real_channel, kSilenceBufferFrames, 0.0f); | |
391 } | |
392 | |
393 rate_shifter_->EnqueueBuffer(silence_buffer); | |
394 } | |
395 | |
396 RateShifterInfo* rate_info = &rate_shifter_info_.front(); | |
slan
2016/12/07 00:22:27
It seems to be an implicit assumption everywhere t
kmackay
2016/12/07 22:59:57
Done.
| |
397 int64_t possible_output_frames = rate_info->input_frames / rate_info->rate; | |
398 DCHECK_GE(possible_output_frames, rate_info->output_frames); | |
399 | |
400 int desired_output_frames = possible_output_frames - rate_info->output_frames; | |
401 if (desired_output_frames == 0) { | |
402 if (got_eos_) { | |
403 DCHECK(!pushed_eos_); | |
404 pending_write_pcm_ = true; | |
405 pushed_eos_ = true; | |
406 | |
407 scoped_refptr<DecoderBufferBase> eos_buffer( | |
408 new DecoderBufferAdapter(::media::DecoderBuffer::CreateEOSBuffer())); | |
409 mixer_input_->WritePcm(eos_buffer); | |
410 } | |
411 return; | |
412 } | |
413 // Don't push too many frames at a time. | |
414 desired_output_frames = std::min( | |
415 desired_output_frames, config_.samples_per_second * kMaxOutputMs / 1000); | |
slan
2016/12/07 00:22:27
base::kMillisecondsPerSecond
kmackay
2016/12/07 22:59:57
Added constant.
| |
416 | |
417 if (desired_output_frames > rate_shifter_output_->frames()) { | |
418 rate_shifter_output_ = ::media::AudioBus::Create(2, desired_output_frames); | |
slan
2016/12/07 00:22:27
Is seems inefficient for rate_shifter_ouptut_ to b
kmackay
2016/12/07 22:59:57
It already does that? It only reallocates if it ne
slan
2016/12/09 00:05:31
Yuuuupppp, lgtm
| |
419 } | |
420 | |
421 int out_frames = rate_shifter_->FillBuffer( | |
422 rate_shifter_output_.get(), 0, desired_output_frames, rate_info->rate); | |
423 if (out_frames <= 0) { | |
424 return; | |
425 } | |
426 | |
427 rate_info->output_frames += out_frames; | |
428 DCHECK_GE(possible_output_frames, rate_info->output_frames); | |
429 | |
430 int channel_data_size = out_frames * sizeof(float); | |
slan
2016/12/07 00:22:27
Do we have a more conventional way of going from A
kmackay
2016/12/07 22:59:57
No, we don't. Usually we convert from ::media::Dec
slan
2016/12/09 00:05:31
Acknowledged.
| |
431 scoped_refptr<DecoderBufferBase> output_buffer(new DecoderBufferAdapter( | |
432 new ::media::DecoderBuffer(channel_data_size * 2))); | |
433 for (int c = 0; c < 2; ++c) { | |
434 memcpy(output_buffer->writable_data() + c * channel_data_size, | |
435 rate_shifter_output_->channel(c), channel_data_size); | |
436 } | |
437 pending_write_pcm_ = true; | |
438 pending_output_frames_ = out_frames; | |
439 mixer_input_->WritePcm(output_buffer); | |
440 | |
441 if (rate_shifter_info_.size() > 1 && | |
442 possible_output_frames == rate_info->output_frames) { | |
443 double remaining_input_frames = | |
444 rate_info->input_frames - (rate_info->output_frames * rate_info->rate); | |
445 rate_shifter_info_.pop_front(); | |
446 | |
447 rate_info = &rate_shifter_info_.front(); | |
448 LOG(INFO) << "New playback rate in effect: " << rate_info->rate; | |
449 rate_info->input_frames += remaining_input_frames; | |
450 DCHECK_EQ(0, rate_info->output_frames); | |
451 | |
452 // If new playback rate is 1.0, clear out 'extra' data in the rate shifter. | |
453 if (rate_info->rate == 1.0) { | |
454 int extra_frames = rate_shifter_->frames_buffered() - | |
455 static_cast<int>(rate_info->input_frames); | |
456 if (extra_frames > 0) { | |
slan
2016/12/07 00:22:27
When this condition hits, what has happened? Shoul
kmackay
2016/12/07 22:59:57
They already were. I added more comments.
| |
457 // Clear out extra buffered data. | |
458 std::unique_ptr<::media::AudioBus> dropped = | |
459 ::media::AudioBus::Create(2, extra_frames); | |
460 int cleared_frames = | |
461 rate_shifter_->FillBuffer(dropped.get(), 0, extra_frames, 1.0f); | |
462 DCHECK_EQ(extra_frames, cleared_frames); | |
463 } | |
464 rate_info->input_frames = rate_shifter_->frames_buffered(); | |
465 } | |
466 } | |
263 } | 467 } |
264 | 468 |
265 bool AudioDecoderAlsa::BypassDecoder() const { | 469 bool AudioDecoderAlsa::BypassDecoder() const { |
266 DCHECK(task_runner_->BelongsToCurrentThread()); | 470 DCHECK(task_runner_->BelongsToCurrentThread()); |
267 // The mixer input requires planar float PCM data. | 471 // The mixer input requires planar float PCM data. |
268 return (config_.codec == kCodecPCM && | 472 return (config_.codec == kCodecPCM && |
269 config_.sample_format == kSampleFormatPlanarF32); | 473 config_.sample_format == kSampleFormatPlanarF32); |
270 } | 474 } |
271 | 475 |
272 void AudioDecoderAlsa::OnWritePcmCompletion(BufferStatus status, | 476 void AudioDecoderAlsa::OnWritePcmCompletion(BufferStatus status, |
slan
2016/12/07 00:22:27
Is it OK to ignore |status| here?
kmackay
2016/12/07 22:59:57
Added DCHECK
| |
273 const RenderingDelay& delay) { | 477 const RenderingDelay& delay) { |
274 TRACE_FUNCTION_ENTRY0(); | 478 TRACE_FUNCTION_ENTRY0(); |
275 DCHECK(task_runner_->BelongsToCurrentThread()); | 479 DCHECK(task_runner_->BelongsToCurrentThread()); |
276 if (status == MediaPipelineBackendAlsa::kBufferSuccess && !is_eos_) | 480 pending_write_pcm_ = false; |
277 current_pts_ = last_buffer_pts_; | 481 pending_output_frames_ = 0; |
278 if (delay.timestamp_microseconds != kInvalidDelayTimestamp) | 482 last_known_delay_ = delay; |
279 last_known_delay_ = delay; | 483 |
280 delegate_->OnPushBufferComplete(status); | 484 if (pushed_eos_) { |
281 if (is_eos_) | 485 if (pending_buffer_complete_) { |
486 pending_buffer_complete_ = false; | |
487 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferSuccess); | |
488 } | |
282 delegate_->OnEndOfStream(); | 489 delegate_->OnEndOfStream(); |
490 } else { | |
491 task_runner_->PostTask(FROM_HERE, base::Bind(&AudioDecoderAlsa::PushMorePcm, | |
492 weak_factory_.GetWeakPtr())); | |
493 } | |
494 } | |
495 | |
496 void AudioDecoderAlsa::PushMorePcm() { | |
497 PushRateShifted(); | |
498 | |
499 double rate = rate_shifter_info_.front().rate; | |
slan
2016/12/07 00:22:27
nit: Move inside if (pending_buffer_complete_), an
kmackay
2016/12/07 22:59:58
Done.
| |
500 if (pending_buffer_complete_ && | |
501 ((rate == 1.0 && !pending_write_pcm_) || | |
502 (rate != 1.0 && !rate_shifter_->IsQueueFull()))) { | |
503 pending_buffer_complete_ = false; | |
504 delegate_->OnPushBufferComplete(MediaPipelineBackendAlsa::kBufferSuccess); | |
505 } | |
283 } | 506 } |
284 | 507 |
285 void AudioDecoderAlsa::OnMixerError(MixerError error) { | 508 void AudioDecoderAlsa::OnMixerError(MixerError error) { |
286 TRACE_FUNCTION_ENTRY0(); | 509 TRACE_FUNCTION_ENTRY0(); |
287 DCHECK(task_runner_->BelongsToCurrentThread()); | 510 DCHECK(task_runner_->BelongsToCurrentThread()); |
288 if (error != MixerError::kInputIgnored) | 511 if (error != MixerError::kInputIgnored) |
289 LOG(ERROR) << "Mixer error occurred."; | 512 LOG(ERROR) << "Mixer error occurred."; |
290 error_ = true; | 513 error_ = true; |
291 delegate_->OnDecoderError(); | 514 delegate_->OnDecoderError(); |
292 } | 515 } |
293 | 516 |
294 } // namespace media | 517 } // namespace media |
295 } // namespace chromecast | 518 } // namespace chromecast |
OLD | NEW |