| 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/message_loop/message_loop_proxy.h" | 10 #include "base/single_thread_task_runner.h" |
| 11 #include "media/base/audio_buffer.h" | 11 #include "media/base/audio_buffer.h" |
| 12 #include "media/base/audio_bus.h" | 12 #include "media/base/audio_bus.h" |
| 13 #include "media/base/audio_decoder_config.h" | 13 #include "media/base/audio_decoder_config.h" |
| 14 #include "media/base/audio_timestamp_helper.h" | 14 #include "media/base/audio_timestamp_helper.h" |
| 15 #include "media/base/bind_to_loop.h" | 15 #include "media/base/bind_to_loop.h" |
| 16 #include "media/base/decoder_buffer.h" | 16 #include "media/base/decoder_buffer.h" |
| 17 #include "media/base/demuxer.h" | 17 #include "media/base/demuxer.h" |
| 18 #include "media/base/limits.h" | 18 #include "media/base/limits.h" |
| 19 #include "media/base/pipeline.h" | 19 #include "media/base/pipeline.h" |
| 20 #include "media/base/sample_format.h" | 20 #include "media/base/sample_format.h" |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 } | 63 } |
| 64 | 64 |
| 65 // Called by FFmpeg's allocation routine to free a buffer. |opaque| is the | 65 // Called by FFmpeg's allocation routine to free a buffer. |opaque| is the |
| 66 // AudioBuffer allocated, so unref it. | 66 // AudioBuffer allocated, so unref it. |
| 67 static void ReleaseAudioBufferImpl(void* opaque, uint8* data) { | 67 static void ReleaseAudioBufferImpl(void* opaque, uint8* data) { |
| 68 scoped_refptr<AudioBuffer> buffer; | 68 scoped_refptr<AudioBuffer> buffer; |
| 69 buffer.swap(reinterpret_cast<AudioBuffer**>(&opaque)); | 69 buffer.swap(reinterpret_cast<AudioBuffer**>(&opaque)); |
| 70 } | 70 } |
| 71 | 71 |
| 72 FFmpegAudioDecoder::FFmpegAudioDecoder( | 72 FFmpegAudioDecoder::FFmpegAudioDecoder( |
| 73 const scoped_refptr<base::MessageLoopProxy>& message_loop) | 73 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) |
| 74 : message_loop_(message_loop), | 74 : task_runner_(task_runner), |
| 75 weak_factory_(this), | 75 weak_factory_(this), |
| 76 demuxer_stream_(NULL), | 76 demuxer_stream_(NULL), |
| 77 bytes_per_channel_(0), | 77 bytes_per_channel_(0), |
| 78 channel_layout_(CHANNEL_LAYOUT_NONE), | 78 channel_layout_(CHANNEL_LAYOUT_NONE), |
| 79 channels_(0), | 79 channels_(0), |
| 80 samples_per_second_(0), | 80 samples_per_second_(0), |
| 81 av_sample_format_(0), | 81 av_sample_format_(0), |
| 82 last_input_timestamp_(kNoTimestamp()), | 82 last_input_timestamp_(kNoTimestamp()), |
| 83 output_frames_to_drop_(0) { | 83 output_frames_to_drop_(0) { |
| 84 } | 84 } |
| 85 | 85 |
| 86 void FFmpegAudioDecoder::Initialize( | 86 void FFmpegAudioDecoder::Initialize( |
| 87 DemuxerStream* stream, | 87 DemuxerStream* stream, |
| 88 const PipelineStatusCB& status_cb, | 88 const PipelineStatusCB& status_cb, |
| 89 const StatisticsCB& statistics_cb) { | 89 const StatisticsCB& statistics_cb) { |
| 90 DCHECK(message_loop_->BelongsToCurrentThread()); | 90 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 91 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); | 91 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); |
| 92 | 92 |
| 93 FFmpegGlue::InitializeFFmpeg(); | 93 FFmpegGlue::InitializeFFmpeg(); |
| 94 | 94 |
| 95 if (demuxer_stream_) { | 95 if (demuxer_stream_) { |
| 96 // TODO(scherkus): initialization currently happens more than once in | 96 // TODO(scherkus): initialization currently happens more than once in |
| 97 // PipelineIntegrationTest.BasicPlayback. | 97 // PipelineIntegrationTest.BasicPlayback. |
| 98 LOG(ERROR) << "Initialize has already been called."; | 98 LOG(ERROR) << "Initialize has already been called."; |
| 99 CHECK(false); | 99 CHECK(false); |
| 100 } | 100 } |
| 101 | 101 |
| 102 weak_this_ = weak_factory_.GetWeakPtr(); | 102 weak_this_ = weak_factory_.GetWeakPtr(); |
| 103 demuxer_stream_ = stream; | 103 demuxer_stream_ = stream; |
| 104 | 104 |
| 105 if (!ConfigureDecoder()) { | 105 if (!ConfigureDecoder()) { |
| 106 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 106 status_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
| 107 return; | 107 return; |
| 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(message_loop_->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 | 118 |
| 119 read_cb_ = BindToCurrentLoop(read_cb); | 119 read_cb_ = BindToCurrentLoop(read_cb); |
| 120 | 120 |
| 121 // 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 |
| 122 // more data from the demuxer to satisfy this read. | 122 // more data from the demuxer to satisfy this read. |
| 123 if (queued_audio_.empty()) { | 123 if (queued_audio_.empty()) { |
| 124 ReadFromDemuxerStream(); | 124 ReadFromDemuxerStream(); |
| 125 return; | 125 return; |
| 126 } | 126 } |
| 127 | 127 |
| 128 base::ResetAndReturn(&read_cb_).Run( | 128 base::ResetAndReturn(&read_cb_).Run( |
| 129 queued_audio_.front().status, queued_audio_.front().buffer); | 129 queued_audio_.front().status, queued_audio_.front().buffer); |
| 130 queued_audio_.pop_front(); | 130 queued_audio_.pop_front(); |
| 131 } | 131 } |
| 132 | 132 |
| 133 int FFmpegAudioDecoder::bits_per_channel() { | 133 int FFmpegAudioDecoder::bits_per_channel() { |
| 134 DCHECK(message_loop_->BelongsToCurrentThread()); | 134 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 135 return bytes_per_channel_ * 8; | 135 return bytes_per_channel_ * 8; |
| 136 } | 136 } |
| 137 | 137 |
| 138 ChannelLayout FFmpegAudioDecoder::channel_layout() { | 138 ChannelLayout FFmpegAudioDecoder::channel_layout() { |
| 139 DCHECK(message_loop_->BelongsToCurrentThread()); | 139 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 140 return channel_layout_; | 140 return channel_layout_; |
| 141 } | 141 } |
| 142 | 142 |
| 143 int FFmpegAudioDecoder::samples_per_second() { | 143 int FFmpegAudioDecoder::samples_per_second() { |
| 144 DCHECK(message_loop_->BelongsToCurrentThread()); | 144 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 145 return samples_per_second_; | 145 return samples_per_second_; |
| 146 } | 146 } |
| 147 | 147 |
| 148 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { | 148 void FFmpegAudioDecoder::Reset(const base::Closure& closure) { |
| 149 DCHECK(message_loop_->BelongsToCurrentThread()); | 149 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 150 base::Closure reset_cb = BindToCurrentLoop(closure); | 150 base::Closure reset_cb = BindToCurrentLoop(closure); |
| 151 | 151 |
| 152 avcodec_flush_buffers(codec_context_.get()); | 152 avcodec_flush_buffers(codec_context_.get()); |
| 153 ResetTimestampState(); | 153 ResetTimestampState(); |
| 154 queued_audio_.clear(); | 154 queued_audio_.clear(); |
| 155 reset_cb.Run(); | 155 reset_cb.Run(); |
| 156 } | 156 } |
| 157 | 157 |
| 158 FFmpegAudioDecoder::~FFmpegAudioDecoder() { | 158 FFmpegAudioDecoder::~FFmpegAudioDecoder() { |
| 159 // TODO(scherkus): should we require Stop() to be called? this might end up | 159 // TODO(scherkus): should we require Stop() to be called? this might end up |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 225 | 225 |
| 226 void FFmpegAudioDecoder::ReadFromDemuxerStream() { | 226 void FFmpegAudioDecoder::ReadFromDemuxerStream() { |
| 227 DCHECK(!read_cb_.is_null()); | 227 DCHECK(!read_cb_.is_null()); |
| 228 demuxer_stream_->Read(base::Bind( | 228 demuxer_stream_->Read(base::Bind( |
| 229 &FFmpegAudioDecoder::BufferReady, weak_this_)); | 229 &FFmpegAudioDecoder::BufferReady, weak_this_)); |
| 230 } | 230 } |
| 231 | 231 |
| 232 void FFmpegAudioDecoder::BufferReady( | 232 void FFmpegAudioDecoder::BufferReady( |
| 233 DemuxerStream::Status status, | 233 DemuxerStream::Status status, |
| 234 const scoped_refptr<DecoderBuffer>& input) { | 234 const scoped_refptr<DecoderBuffer>& input) { |
| 235 DCHECK(message_loop_->BelongsToCurrentThread()); | 235 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 236 DCHECK(!read_cb_.is_null()); | 236 DCHECK(!read_cb_.is_null()); |
| 237 DCHECK(queued_audio_.empty()); | 237 DCHECK(queued_audio_.empty()); |
| 238 DCHECK_EQ(status != DemuxerStream::kOk, !input.get()) << status; | 238 DCHECK_EQ(status != DemuxerStream::kOk, !input.get()) << status; |
| 239 | 239 |
| 240 if (status == DemuxerStream::kAborted) { | 240 if (status == DemuxerStream::kAborted) { |
| 241 DCHECK(!input.get()); | 241 DCHECK(!input.get()); |
| 242 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); | 242 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); |
| 243 return; | 243 return; |
| 244 } | 244 } |
| 245 | 245 |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 // Decoding finished successfully, update statistics. | 529 // Decoding finished successfully, update statistics. |
| 530 if (result > 0) { | 530 if (result > 0) { |
| 531 PipelineStatistics statistics; | 531 PipelineStatistics statistics; |
| 532 statistics.audio_bytes_decoded = result; | 532 statistics.audio_bytes_decoded = result; |
| 533 statistics_cb_.Run(statistics); | 533 statistics_cb_.Run(statistics); |
| 534 } | 534 } |
| 535 } while (packet.size > 0); | 535 } while (packet.size > 0); |
| 536 } | 536 } |
| 537 | 537 |
| 538 } // namespace media | 538 } // namespace media |
| OLD | NEW |