Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(199)

Side by Side Diff: media/filters/ffmpeg_audio_decoder.cc

Issue 8763010: Replace AudioDecoder::ProduceAudioSamples/ConsumeAudioSamples with read callbacks. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "media/base/audio_decoder_config.h" 8 #include "media/base/audio_decoder_config.h"
9 #include "media/base/data_buffer.h" 9 #include "media/base/data_buffer.h"
10 #include "media/base/demuxer.h" 10 #include "media/base/demuxer.h"
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 } 45 }
46 46
47 47
48 FFmpegAudioDecoder::FFmpegAudioDecoder(MessageLoop* message_loop) 48 FFmpegAudioDecoder::FFmpegAudioDecoder(MessageLoop* message_loop)
49 : message_loop_(message_loop), 49 : message_loop_(message_loop),
50 codec_context_(NULL), 50 codec_context_(NULL),
51 bits_per_channel_(0), 51 bits_per_channel_(0),
52 channel_layout_(CHANNEL_LAYOUT_NONE), 52 channel_layout_(CHANNEL_LAYOUT_NONE),
53 samples_per_second_(0), 53 samples_per_second_(0),
54 decoded_audio_size_(AVCODEC_MAX_AUDIO_FRAME_SIZE), 54 decoded_audio_size_(AVCODEC_MAX_AUDIO_FRAME_SIZE),
55 decoded_audio_(static_cast<uint8*>(av_malloc(decoded_audio_size_))), 55 decoded_audio_(static_cast<uint8*>(av_malloc(decoded_audio_size_))) {
56 pending_reads_(0) {
57 } 56 }
58 57
59 FFmpegAudioDecoder::~FFmpegAudioDecoder() { 58 FFmpegAudioDecoder::~FFmpegAudioDecoder() {
60 av_free(decoded_audio_); 59 av_free(decoded_audio_);
61 60
62 // XXX: should we require Stop() to be called? this might end up getting 61 // XXX: should we require Stop() to be called? this might end up getting
63 // called on a random thread due to refcounting. 62 // called on a random thread due to refcounting.
64 if (codec_context_) { 63 if (codec_context_) {
65 av_free(codec_context_->extradata); 64 av_free(codec_context_->extradata);
66 avcodec_close(codec_context_); 65 avcodec_close(codec_context_);
(...skipping 13 matching lines...) Expand all
80 const StatisticsCallback& stats_callback) { 79 const StatisticsCallback& stats_callback) {
81 // TODO(scherkus): change Initialize() signature to pass |stream| as a 80 // TODO(scherkus): change Initialize() signature to pass |stream| as a
82 // scoped_refptr<>. 81 // scoped_refptr<>.
83 scoped_refptr<DemuxerStream> ref_stream(stream); 82 scoped_refptr<DemuxerStream> ref_stream(stream);
84 message_loop_->PostTask( 83 message_loop_->PostTask(
85 FROM_HERE, 84 FROM_HERE,
86 base::Bind(&FFmpegAudioDecoder::DoInitialize, this, 85 base::Bind(&FFmpegAudioDecoder::DoInitialize, this,
87 ref_stream, callback, stats_callback)); 86 ref_stream, callback, stats_callback));
88 } 87 }
89 88
90 void FFmpegAudioDecoder::ProduceAudioSamples(scoped_refptr<Buffer> buffer) { 89 void FFmpegAudioDecoder::Read(const ReadCB& callback) {
91 message_loop_->PostTask( 90 // TODO(scherkus): forced task post since AudioRendererBase::SamplesReady()
vrk (LEFT CHROMIUM) 2011/12/03 03:10:17 nit: What's the TODO? Should this just be a commen
scherkus (not reviewing) 2011/12/07 05:25:12 done and updated FFmpegVideoDecoder as well
92 FROM_HERE, 91 // will call Read() on FFmpegAudioDecoder's thread as we executed |read_cb_|.
93 base::Bind(&FFmpegAudioDecoder::DoProduceAudioSamples, this, 92 message_loop_->PostTask(FROM_HERE, base::Bind(
94 buffer)); 93 &FFmpegAudioDecoder::DoRead, this, callback));
95 } 94 }
96 95
97 int FFmpegAudioDecoder::bits_per_channel() { 96 int FFmpegAudioDecoder::bits_per_channel() {
98 return bits_per_channel_; 97 return bits_per_channel_;
99 } 98 }
100 99
101 ChannelLayout FFmpegAudioDecoder::channel_layout() { 100 ChannelLayout FFmpegAudioDecoder::channel_layout() {
102 return channel_layout_; 101 return channel_layout_;
103 } 102 }
104 103
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 148
150 callback.Run(); 149 callback.Run();
151 } 150 }
152 151
153 void FFmpegAudioDecoder::DoFlush(const base::Closure& callback) { 152 void FFmpegAudioDecoder::DoFlush(const base::Closure& callback) {
154 avcodec_flush_buffers(codec_context_); 153 avcodec_flush_buffers(codec_context_);
155 estimated_next_timestamp_ = kNoTimestamp; 154 estimated_next_timestamp_ = kNoTimestamp;
156 callback.Run(); 155 callback.Run();
157 } 156 }
158 157
159 void FFmpegAudioDecoder::DoProduceAudioSamples( 158 void FFmpegAudioDecoder::DoRead(const ReadCB& callback) {
160 const scoped_refptr<Buffer>& output) { 159 DCHECK_EQ(MessageLoop::current(), message_loop_);
161 output_buffers_.push_back(output); 160 CHECK(!callback.is_null());
vrk (LEFT CHROMIUM) 2011/12/03 03:10:17 CHECK? Do you mean DCHECK?
scherkus (not reviewing) 2011/12/07 05:25:12 Done.
161 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported.";
162
163 read_cb_ = callback;
162 ReadFromDemuxerStream(); 164 ReadFromDemuxerStream();
163 } 165 }
164 166
165 void FFmpegAudioDecoder::DoDecodeBuffer(const scoped_refptr<Buffer>& input) { 167 void FFmpegAudioDecoder::DoDecodeBuffer(const scoped_refptr<Buffer>& input) {
166 DCHECK(!output_buffers_.empty()); 168 DCHECK_EQ(MessageLoop::current(), message_loop_);
167 DCHECK_GT(pending_reads_, 0); 169 DCHECK(!read_cb_.is_null());
168 pending_reads_--;
169 170
170 // FFmpeg tends to seek Ogg audio streams in the middle of nowhere, giving us 171 // FFmpeg tends to seek Ogg audio streams in the middle of nowhere, giving us
171 // a whole bunch of AV_NOPTS_VALUE packets. Discard them until we find 172 // a whole bunch of AV_NOPTS_VALUE packets. Discard them until we find
172 // something valid. Refer to http://crbug.com/49709 173 // something valid. Refer to http://crbug.com/49709
173 if (input->GetTimestamp() == kNoTimestamp && 174 if (input->GetTimestamp() == kNoTimestamp &&
174 estimated_next_timestamp_ == kNoTimestamp && 175 estimated_next_timestamp_ == kNoTimestamp &&
175 !input->IsEndOfStream()) { 176 !input->IsEndOfStream()) {
176 ReadFromDemuxerStream(); 177 ReadFromDemuxerStream();
177 return; 178 return;
178 } 179 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
226 } else if (IsEndOfStream(result, decoded_audio_size, input)) { 227 } else if (IsEndOfStream(result, decoded_audio_size, input)) {
227 // Create an end of stream output buffer. 228 // Create an end of stream output buffer.
228 output = new DataBuffer(0); 229 output = new DataBuffer(0);
229 output->SetTimestamp(input->GetTimestamp()); 230 output->SetTimestamp(input->GetTimestamp());
230 output->SetDuration(input->GetDuration()); 231 output->SetDuration(input->GetDuration());
231 } 232 }
232 233
233 // Decoding finished successfully, update stats and execute callback. 234 // Decoding finished successfully, update stats and execute callback.
234 stats_callback_.Run(statistics); 235 stats_callback_.Run(statistics);
235 if (output) { 236 if (output) {
236 DCHECK_GT(output_buffers_.size(), 0u); 237 DeliverSamples(output);
vrk (LEFT CHROMIUM) 2011/12/03 03:10:17 nit: remove {}
scherkus (not reviewing) 2011/12/07 05:25:12 other one-line statements in this file + ffmpegvid
237 output_buffers_.pop_front();
238
239 ConsumeAudioSamples(output);
240 } else { 238 } else {
241 ReadFromDemuxerStream(); 239 ReadFromDemuxerStream();
242 } 240 }
243 } 241 }
244 242
245 void FFmpegAudioDecoder::ReadFromDemuxerStream() { 243 void FFmpegAudioDecoder::ReadFromDemuxerStream() {
246 DCHECK(!output_buffers_.empty()) 244 DCHECK(!read_cb_.is_null());
247 << "Reads should only occur if there are output buffers.";
248 245
249 pending_reads_++;
250 demuxer_stream_->Read(base::Bind(&FFmpegAudioDecoder::DecodeBuffer, this)); 246 demuxer_stream_->Read(base::Bind(&FFmpegAudioDecoder::DecodeBuffer, this));
251 } 247 }
252 248
253 void FFmpegAudioDecoder::DecodeBuffer(const scoped_refptr<Buffer>& buffer) { 249 void FFmpegAudioDecoder::DecodeBuffer(const scoped_refptr<Buffer>& buffer) {
254 message_loop_->PostTask( 250 // TODO(scherkus): forced task post since FFmpegDemuxerStream::Read() can
vrk (LEFT CHROMIUM) 2011/12/03 03:10:17 nit: ditto above comment re: "TODO"
scherkus (not reviewing) 2011/12/07 05:25:12 Done + FFmpegVideoDecoder
255 FROM_HERE, 251 // immediately execute our callback on FFmpegAudioDecoder's thread.
256 base::Bind(&FFmpegAudioDecoder::DoDecodeBuffer, this, buffer)); 252 message_loop_->PostTask(FROM_HERE, base::Bind(
253 &FFmpegAudioDecoder::DoDecodeBuffer, this, buffer));
257 } 254 }
258 255
259 void FFmpegAudioDecoder::UpdateDurationAndTimestamp( 256 void FFmpegAudioDecoder::UpdateDurationAndTimestamp(
260 const Buffer* input, 257 const Buffer* input,
261 DataBuffer* output) { 258 DataBuffer* output) {
262 // Always calculate duration based on the actual number of samples decoded. 259 // Always calculate duration based on the actual number of samples decoded.
263 base::TimeDelta duration = CalculateDuration(output->GetDataSize()); 260 base::TimeDelta duration = CalculateDuration(output->GetDataSize());
264 output->SetDuration(duration); 261 output->SetDuration(duration);
265 262
266 // Use the incoming timestamp if it's valid. 263 // Use the incoming timestamp if it's valid.
(...skipping 12 matching lines...) Expand all
279 } 276 }
280 277
281 base::TimeDelta FFmpegAudioDecoder::CalculateDuration(int size) { 278 base::TimeDelta FFmpegAudioDecoder::CalculateDuration(int size) {
282 int64 denominator = ChannelLayoutToChannelCount(channel_layout_) * 279 int64 denominator = ChannelLayoutToChannelCount(channel_layout_) *
283 bits_per_channel_ / 8 * samples_per_second_; 280 bits_per_channel_ / 8 * samples_per_second_;
284 double microseconds = size / 281 double microseconds = size /
285 (denominator / static_cast<double>(base::Time::kMicrosecondsPerSecond)); 282 (denominator / static_cast<double>(base::Time::kMicrosecondsPerSecond));
286 return base::TimeDelta::FromMicroseconds(static_cast<int64>(microseconds)); 283 return base::TimeDelta::FromMicroseconds(static_cast<int64>(microseconds));
287 } 284 }
288 285
286 void FFmpegAudioDecoder::DeliverSamples(const scoped_refptr<Buffer>& samples) {
287 // Reset the callback before running to protect against reentrancy.
288 ReadCB read_cb = read_cb_;
289 read_cb_.Reset();
290 read_cb.Run(samples);
291 }
292
289 } // namespace media 293 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698