Index: media/filters/ffmpeg_demuxer.cc |
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc |
index 326b8818998e8e79d6a4937e144e59a1e6a668ef..3e39708a4f5eb09f8e7d1cd44aae08fe0b224b97 100644 |
--- a/media/filters/ffmpeg_demuxer.cc |
+++ b/media/filters/ffmpeg_demuxer.cc |
@@ -28,6 +28,18 @@ |
namespace media { |
+// Helpers for making ReadCBs always run on a new execution stack. |
+static void RunReadCB(const scoped_refptr<base::MessageLoopProxy>& message_loop, |
+ const DemuxerStream::ReadCB& read_cb, |
+ DemuxerStream::Status status, |
+ const scoped_refptr<DecoderBuffer>& buffer) { |
+ message_loop->PostTask(FROM_HERE, base::Bind(read_cb, status, buffer)); |
+} |
+ |
+static DemuxerStream::ReadCB WrapReadCB(const DemuxerStream::ReadCB& read_cb) { |
+ return base::Bind(&RunReadCB, base::MessageLoopProxy::current(), read_cb); |
+} |
+ |
// |
// FFmpegDemuxerStream |
// |
@@ -134,45 +146,41 @@ base::TimeDelta FFmpegDemuxerStream::duration() { |
} |
DemuxerStream::Type FFmpegDemuxerStream::type() { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
return type_; |
} |
void FFmpegDemuxerStream::Read(const ReadCB& read_cb) { |
- if (!message_loop_->BelongsToCurrentThread()) { |
- message_loop_->PostTask(FROM_HERE, base::Bind( |
- &FFmpegDemuxerStream::Read, this, read_cb)); |
- return; |
- } |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ ReadCB wrapped_read_cb = WrapReadCB(read_cb); |
// Don't accept any additional reads if we've been told to stop. |
// The |demuxer_| may have been destroyed in the pipeline thread. |
// |
// TODO(scherkus): it would be cleaner to reply with an error message. |
if (stopped_) { |
- read_cb.Run(DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer()); |
+ wrapped_read_cb.Run(DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer()); |
return; |
} |
- read_queue_.push_back(read_cb); |
+ read_queue_.push_back(wrapped_read_cb); |
acolwell GONE FROM CHROMIUM
2012/12/03 23:14:21
Do we still need this queue?
scherkus (not reviewing)
2012/12/07 22:18:55
We don't! Removed.
|
SatisfyPendingReads(); |
} |
void FFmpegDemuxerStream::EnableBitstreamConverter() { |
- if (!message_loop_->BelongsToCurrentThread()) { |
- message_loop_->PostTask(FROM_HERE, base::Bind( |
- &FFmpegDemuxerStream::EnableBitstreamConverter, this)); |
- return; |
- } |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
CHECK(bitstream_converter_.get()); |
bitstream_converter_enabled_ = true; |
} |
const AudioDecoderConfig& FFmpegDemuxerStream::audio_decoder_config() { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
CHECK_EQ(type_, AUDIO); |
return audio_config_; |
} |
const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
CHECK_EQ(type_, VIDEO); |
return video_config_; |
} |
@@ -207,8 +215,7 @@ void FFmpegDemuxerStream::SatisfyPendingReads() { |
// Send buffer back on a new execution stack to avoid recursing. |
ReadCB read_cb = read_queue_.front(); |
read_queue_.pop_front(); |
- message_loop_->PostTask(FROM_HERE, base::Bind( |
- read_cb, DemuxerStream::kOk, buffer)); |
+ read_cb.Run(DemuxerStream::kOk, buffer); |
} |
// Have capacity? Ask for more! |
@@ -257,34 +264,78 @@ FFmpegDemuxer::FFmpegDemuxer( |
FFmpegDemuxer::~FFmpegDemuxer() {} |
void FFmpegDemuxer::Stop(const base::Closure& callback) { |
- // Post a task to notify the streams to stop as well. |
- message_loop_->PostTask(FROM_HERE, |
- base::Bind(&FFmpegDemuxer::StopTask, this, callback)); |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ url_protocol_.Abort(); |
+ data_source_->Stop(BindToLoop(message_loop_, base::Bind( |
+ &FFmpegDemuxer::OnDataSourceStopped, this, callback))); |
} |
void FFmpegDemuxer::Seek(base::TimeDelta time, const PipelineStatusCB& cb) { |
- message_loop_->PostTask(FROM_HERE, |
- base::Bind(&FFmpegDemuxer::SeekTask, this, time, cb)); |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ CHECK(!pending_seek_); |
+ |
+ // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|, |
+ // otherwise we can end up waiting for a pre-seek read to complete even though |
+ // we know we're going to drop it on the floor. |
+ |
+ // Always seek to a timestamp less than or equal to the desired timestamp. |
+ int flags = AVSEEK_FLAG_BACKWARD; |
+ |
+ // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg |
+ // will attempt to use the lowest-index video stream, if present, followed by |
+ // the lowest-index audio stream. |
+ pending_seek_ = true; |
+ base::PostTaskAndReplyWithResult( |
+ blocking_thread_.message_loop_proxy(), FROM_HERE, |
+ base::Bind(&av_seek_frame, glue_->format_context(), -1, |
+ time.InMicroseconds(), flags), |
+ base::Bind(&FFmpegDemuxer::OnSeekFrameDone, this, cb)); |
} |
void FFmpegDemuxer::SetPlaybackRate(float playback_rate) { |
- DCHECK(data_source_.get()); |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
data_source_->SetPlaybackRate(playback_rate); |
} |
void FFmpegDemuxer::OnAudioRendererDisabled() { |
- message_loop_->PostTask(FROM_HERE, base::Bind( |
- &FFmpegDemuxer::DisableAudioStreamTask, this)); |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ audio_disabled_ = true; |
+ StreamVector::iterator iter; |
+ for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
+ if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { |
+ (*iter)->Stop(); |
+ } |
+ } |
} |
void FFmpegDemuxer::Initialize(DemuxerHost* host, |
const PipelineStatusCB& status_cb) { |
- message_loop_->PostTask(FROM_HERE, base::Bind( |
- &FFmpegDemuxer::InitializeTask, this, host, status_cb)); |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ host_ = host; |
+ |
+ // TODO(scherkus): DataSource should have a host by this point, |
+ // see http://crbug.com/122071 |
+ data_source_->set_host(host); |
+ |
+ glue_.reset(new FFmpegGlue(&url_protocol_)); |
+ AVFormatContext* format_context = glue_->format_context(); |
+ |
+ // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we |
+ // don't use. FFmpeg will only read ID3v1 tags if no other metadata is |
+ // available, so add a metadata entry to ensure some is always present. |
+ av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); |
+ |
+ // Open the AVFormatContext using our glue layer. |
+ CHECK(blocking_thread_.Start()); |
+ base::PostTaskAndReplyWithResult( |
+ blocking_thread_.message_loop_proxy(), FROM_HERE, |
+ base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), |
+ base::Bind(&FFmpegDemuxer::OnOpenContextDone, this, status_cb)); |
} |
scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( |
DemuxerStream::Type type) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
return GetFFmpegStream(type); |
} |
@@ -300,6 +351,7 @@ scoped_refptr<FFmpegDemuxerStream> FFmpegDemuxer::GetFFmpegStream( |
} |
base::TimeDelta FFmpegDemuxer::GetStartTime() const { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
return start_time_; |
} |
@@ -339,31 +391,6 @@ static int CalculateBitrate( |
return bytes * 8000000.0 / duration_us; |
} |
-void FFmpegDemuxer::InitializeTask(DemuxerHost* host, |
- const PipelineStatusCB& status_cb) { |
- DCHECK(message_loop_->BelongsToCurrentThread()); |
- host_ = host; |
- |
- // TODO(scherkus): DataSource should have a host by this point, |
- // see http://crbug.com/122071 |
- data_source_->set_host(host); |
- |
- glue_.reset(new FFmpegGlue(&url_protocol_)); |
- AVFormatContext* format_context = glue_->format_context(); |
- |
- // Disable ID3v1 tag reading to avoid costly seeks to end of file for data we |
- // don't use. FFmpeg will only read ID3v1 tags if no other metadata is |
- // available, so add a metadata entry to ensure some is always present. |
- av_dict_set(&format_context->metadata, "skip_id3v1_tags", "", 0); |
- |
- // Open the AVFormatContext using our glue layer. |
- CHECK(blocking_thread_.Start()); |
- base::PostTaskAndReplyWithResult( |
- blocking_thread_.message_loop_proxy(), FROM_HERE, |
- base::Bind(&FFmpegGlue::OpenContext, base::Unretained(glue_.get())), |
- base::Bind(&FFmpegDemuxer::OnOpenContextDone, this, status_cb)); |
-} |
- |
void FFmpegDemuxer::OnOpenContextDone(const PipelineStatusCB& status_cb, |
bool result) { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
@@ -478,28 +505,6 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
status_cb.Run(PIPELINE_OK); |
} |
-void FFmpegDemuxer::SeekTask(base::TimeDelta time, const PipelineStatusCB& cb) { |
- DCHECK(message_loop_->BelongsToCurrentThread()); |
- CHECK(!pending_seek_); |
- |
- // TODO(scherkus): Inspect |pending_read_| and cancel IO via |blocking_url_|, |
- // otherwise we can end up waiting for a pre-seek read to complete even though |
- // we know we're going to drop it on the floor. |
- |
- // Always seek to a timestamp less than or equal to the desired timestamp. |
- int flags = AVSEEK_FLAG_BACKWARD; |
- |
- // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg |
- // will attempt to use the lowest-index video stream, if present, followed by |
- // the lowest-index audio stream. |
- pending_seek_ = true; |
- base::PostTaskAndReplyWithResult( |
- blocking_thread_.message_loop_proxy(), FROM_HERE, |
- base::Bind(&av_seek_frame, glue_->format_context(), -1, |
- time.InMicroseconds(), flags), |
- base::Bind(&FFmpegDemuxer::OnSeekFrameDone, this, cb)); |
-} |
- |
void FFmpegDemuxer::OnSeekFrameDone(const PipelineStatusCB& cb, int result) { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
CHECK(pending_seek_); |
@@ -524,17 +529,17 @@ void FFmpegDemuxer::OnSeekFrameDone(const PipelineStatusCB& cb, int result) { |
(*iter)->FlushBuffers(); |
} |
- // Resume demuxing until capacity. |
- DemuxTask(); |
+ // Resume reading until capacity. |
+ ReadFrameIfNeeded(); |
// Notify we're finished seeking. |
cb.Run(PIPELINE_OK); |
} |
-void FFmpegDemuxer::DemuxTask() { |
+void FFmpegDemuxer::ReadFrameIfNeeded() { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
- // Make sure we have work to do before demuxing. |
+ // Make sure we have work to do before reading. |
if (!blocking_thread_.IsRunning() || !StreamsHaveAvailableCapacity() || |
pending_read_ || pending_seek_) { |
return; |
@@ -600,15 +605,8 @@ void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) { |
demuxer_stream->EnqueuePacket(packet.Pass()); |
} |
- // Keep demuxing until we've reached capacity. |
- DemuxTask(); |
-} |
- |
-void FFmpegDemuxer::StopTask(const base::Closure& callback) { |
- DCHECK(message_loop_->BelongsToCurrentThread()); |
- url_protocol_.Abort(); |
- data_source_->Stop(BindToLoop(message_loop_, base::Bind( |
- &FFmpegDemuxer::OnDataSourceStopped, this, callback))); |
+ // Keep reading until we've reached capacity. |
+ ReadFrameIfNeeded(); |
} |
void FFmpegDemuxer::OnDataSourceStopped(const base::Closure& callback) { |
@@ -628,17 +626,6 @@ void FFmpegDemuxer::OnDataSourceStopped(const base::Closure& callback) { |
callback.Run(); |
} |
-void FFmpegDemuxer::DisableAudioStreamTask() { |
- DCHECK(message_loop_->BelongsToCurrentThread()); |
- audio_disabled_ = true; |
- StreamVector::iterator iter; |
- for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
- if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { |
- (*iter)->Stop(); |
- } |
- } |
-} |
- |
bool FFmpegDemuxer::StreamsHaveAvailableCapacity() { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
StreamVector::iterator iter; |
@@ -664,7 +651,7 @@ void FFmpegDemuxer::StreamHasEnded() { |
void FFmpegDemuxer::NotifyCapacityAvailable() { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
- DemuxTask(); |
+ ReadFrameIfNeeded(); |
} |
void FFmpegDemuxer::NotifyBufferingChanged() { |