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