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