OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/filters/ffmpeg_audio_decoder.h" | 5 #include "media/filters/ffmpeg_audio_decoder.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/single_thread_task_runner.h" | 10 #include "base/single_thread_task_runner.h" |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 } | 108 } |
109 | 109 |
110 statistics_cb_ = statistics_cb; | 110 statistics_cb_ = statistics_cb; |
111 initialize_cb.Run(PIPELINE_OK); | 111 initialize_cb.Run(PIPELINE_OK); |
112 } | 112 } |
113 | 113 |
114 void FFmpegAudioDecoder::Read(const ReadCB& read_cb) { | 114 void FFmpegAudioDecoder::Read(const ReadCB& read_cb) { |
115 DCHECK(task_runner_->BelongsToCurrentThread()); | 115 DCHECK(task_runner_->BelongsToCurrentThread()); |
116 DCHECK(!read_cb.is_null()); | 116 DCHECK(!read_cb.is_null()); |
117 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; | 117 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; |
118 DCHECK(reset_cb_.is_null()); | |
119 DCHECK(stop_cb_.is_null()); | |
120 | 118 |
121 read_cb_ = BindToCurrentLoop(read_cb); | 119 read_cb_ = BindToCurrentLoop(read_cb); |
122 | 120 |
123 // If we don't have any queued audio from the last packet we decoded, ask for | 121 // If we don't have any queued audio from the last packet we decoded, ask for |
124 // more data from the demuxer to satisfy this read. | 122 // more data from the demuxer to satisfy this read. |
125 if (queued_audio_.empty()) { | 123 if (queued_audio_.empty()) { |
126 ReadFromDemuxerStream(); | 124 ReadFromDemuxerStream(); |
127 return; | 125 return; |
128 } | 126 } |
129 | 127 |
(...skipping 12 matching lines...) Expand all Loading... |
142 return channel_layout_; | 140 return channel_layout_; |
143 } | 141 } |
144 | 142 |
145 int FFmpegAudioDecoder::samples_per_second() { | 143 int FFmpegAudioDecoder::samples_per_second() { |
146 DCHECK(task_runner_->BelongsToCurrentThread()); | 144 DCHECK(task_runner_->BelongsToCurrentThread()); |
147 return samples_per_second_; | 145 return samples_per_second_; |
148 } | 146 } |
149 | 147 |
150 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { | 148 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { |
151 DCHECK(task_runner_->BelongsToCurrentThread()); | 149 DCHECK(task_runner_->BelongsToCurrentThread()); |
152 reset_cb_ = BindToCurrentLoop(closure); | 150 base::Closure reset_cb = BindToCurrentLoop(closure); |
153 | 151 |
154 // A demuxer read is pending, we'll wait until it finishes. | 152 avcodec_flush_buffers(codec_context_.get()); |
155 if (!read_cb_.is_null()) | 153 ResetTimestampState(); |
156 return; | 154 queued_audio_.clear(); |
157 | 155 reset_cb.Run(); |
158 DoReset(); | |
159 } | 156 } |
160 | 157 |
161 void FFmpegAudioDecoder::Stop(const base::Closure& closure) { | 158 FFmpegAudioDecoder::~FFmpegAudioDecoder() { |
162 DCHECK(task_runner_->BelongsToCurrentThread()); | 159 // TODO(scherkus): should we require Stop() to be called? this might end up |
163 stop_cb_ = BindToCurrentLoop(closure); | 160 // getting called on a random thread due to refcounting. |
164 | 161 ReleaseFFmpegResources(); |
165 // A demuxer read is pending, we'll wait until it finishes. | |
166 if (!read_cb_.is_null()) | |
167 return; | |
168 | |
169 if (!reset_cb_.is_null()) { | |
170 DoReset(); | |
171 return; | |
172 } | |
173 | |
174 DoStop(); | |
175 } | 162 } |
176 | 163 |
177 FFmpegAudioDecoder::~FFmpegAudioDecoder() {} | |
178 | |
179 int FFmpegAudioDecoder::GetAudioBuffer(AVCodecContext* codec, | 164 int FFmpegAudioDecoder::GetAudioBuffer(AVCodecContext* codec, |
180 AVFrame* frame, | 165 AVFrame* frame, |
181 int flags) { | 166 int flags) { |
182 // Since this routine is called by FFmpeg when a buffer is required for audio | 167 // Since this routine is called by FFmpeg when a buffer is required for audio |
183 // data, use the values supplied by FFmpeg (ignoring the current settings). | 168 // data, use the values supplied by FFmpeg (ignoring the current settings). |
184 // RunDecodeLoop() gets to determine if the buffer is useable or not. | 169 // RunDecodeLoop() gets to determine if the buffer is useable or not. |
185 AVSampleFormat format = static_cast<AVSampleFormat>(frame->format); | 170 AVSampleFormat format = static_cast<AVSampleFormat>(frame->format); |
186 SampleFormat sample_format = AVSampleFormatToSampleFormat(format); | 171 SampleFormat sample_format = AVSampleFormatToSampleFormat(format); |
187 int channels = DetermineChannels(frame); | 172 int channels = DetermineChannels(frame); |
188 if ((channels <= 0) || (channels >= limits::kMaxChannels)) { | 173 if ((channels <= 0) || (channels >= limits::kMaxChannels)) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 | 219 |
235 // Now create an AVBufferRef for the data just allocated. It will own the | 220 // Now create an AVBufferRef for the data just allocated. It will own the |
236 // reference to the AudioBuffer object. | 221 // reference to the AudioBuffer object. |
237 void* opaque = NULL; | 222 void* opaque = NULL; |
238 buffer.swap(reinterpret_cast<AudioBuffer**>(&opaque)); | 223 buffer.swap(reinterpret_cast<AudioBuffer**>(&opaque)); |
239 frame->buf[0] = av_buffer_create( | 224 frame->buf[0] = av_buffer_create( |
240 frame->data[0], buffer_size_in_bytes, ReleaseAudioBufferImpl, opaque, 0); | 225 frame->data[0], buffer_size_in_bytes, ReleaseAudioBufferImpl, opaque, 0); |
241 return 0; | 226 return 0; |
242 } | 227 } |
243 | 228 |
244 void FFmpegAudioDecoder::DoStop() { | |
245 DCHECK(task_runner_->BelongsToCurrentThread()); | |
246 DCHECK(!stop_cb_.is_null()); | |
247 DCHECK(read_cb_.is_null()); | |
248 DCHECK(reset_cb_.is_null()); | |
249 | |
250 ResetTimestampState(); | |
251 queued_audio_.clear(); | |
252 ReleaseFFmpegResources(); | |
253 base::ResetAndReturn(&stop_cb_).Run(); | |
254 } | |
255 | |
256 void FFmpegAudioDecoder::DoReset() { | |
257 DCHECK(task_runner_->BelongsToCurrentThread()); | |
258 DCHECK(!reset_cb_.is_null()); | |
259 DCHECK(read_cb_.is_null()); | |
260 | |
261 avcodec_flush_buffers(codec_context_.get()); | |
262 ResetTimestampState(); | |
263 queued_audio_.clear(); | |
264 base::ResetAndReturn(&reset_cb_).Run(); | |
265 | |
266 if (!stop_cb_.is_null()) | |
267 DoStop(); | |
268 } | |
269 | |
270 void FFmpegAudioDecoder::ReadFromDemuxerStream() { | 229 void FFmpegAudioDecoder::ReadFromDemuxerStream() { |
271 DCHECK(!read_cb_.is_null()); | 230 DCHECK(!read_cb_.is_null()); |
272 demuxer_stream_->Read(base::Bind( | 231 demuxer_stream_->Read(base::Bind( |
273 &FFmpegAudioDecoder::BufferReady, weak_this_)); | 232 &FFmpegAudioDecoder::BufferReady, weak_this_)); |
274 } | 233 } |
275 | 234 |
276 void FFmpegAudioDecoder::BufferReady( | 235 void FFmpegAudioDecoder::BufferReady( |
277 DemuxerStream::Status status, | 236 DemuxerStream::Status status, |
278 const scoped_refptr<DecoderBuffer>& input) { | 237 const scoped_refptr<DecoderBuffer>& input) { |
279 DCHECK(task_runner_->BelongsToCurrentThread()); | 238 DCHECK(task_runner_->BelongsToCurrentThread()); |
280 DCHECK(!read_cb_.is_null()); | 239 DCHECK(!read_cb_.is_null()); |
281 DCHECK(queued_audio_.empty()); | 240 DCHECK(queued_audio_.empty()); |
282 DCHECK_EQ(status != DemuxerStream::kOk, !input.get()) << status; | 241 DCHECK_EQ(status != DemuxerStream::kOk, !input.get()) << status; |
283 | 242 |
284 // Pending Reset: ignore the buffer we just got, send kAborted to |read_cb_| | |
285 // and carry out the Reset(). | |
286 // If there happens to also be a pending Stop(), that will be handled at | |
287 // the end of DoReset(). | |
288 if (!reset_cb_.is_null()) { | |
289 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); | |
290 DoReset(); | |
291 return; | |
292 } | |
293 | |
294 // Pending Stop: ignore the buffer we just got, send kAborted to |read_cb_| | |
295 // and carry out the Stop(). | |
296 if (!stop_cb_.is_null()) { | |
297 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); | |
298 DoStop(); | |
299 return; | |
300 } | |
301 | |
302 if (status == DemuxerStream::kAborted) { | 243 if (status == DemuxerStream::kAborted) { |
303 DCHECK(!input.get()); | 244 DCHECK(!input.get()); |
304 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); | 245 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); |
305 return; | 246 return; |
306 } | 247 } |
307 | 248 |
308 if (status == DemuxerStream::kConfigChanged) { | 249 if (status == DemuxerStream::kConfigChanged) { |
309 DCHECK(!input.get()); | 250 DCHECK(!input.get()); |
310 | 251 |
311 // Send a "end of stream" buffer to the decode loop | 252 // Send a "end of stream" buffer to the decode loop |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 // Decoding finished successfully, update statistics. | 532 // Decoding finished successfully, update statistics. |
592 if (result > 0) { | 533 if (result > 0) { |
593 PipelineStatistics statistics; | 534 PipelineStatistics statistics; |
594 statistics.audio_bytes_decoded = result; | 535 statistics.audio_bytes_decoded = result; |
595 statistics_cb_.Run(statistics); | 536 statistics_cb_.Run(statistics); |
596 } | 537 } |
597 } while (packet.size > 0); | 538 } while (packet.size > 0); |
598 } | 539 } |
599 | 540 |
600 } // namespace media | 541 } // namespace media |
OLD | NEW |