| Index: media/filters/ffmpeg_demuxer.cc
|
| diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
|
| index 404a52a852d1e9a94a91f9c8a3f193c83aa31bf7..64f84011f6918936aaa0e1a7ff3132f26c177077 100644
|
| --- a/media/filters/ffmpeg_demuxer.cc
|
| +++ b/media/filters/ffmpeg_demuxer.cc
|
| @@ -35,6 +35,7 @@ FFmpegDemuxerStream::FFmpegDemuxerStream(
|
| FFmpegDemuxer* demuxer,
|
| AVStream* stream)
|
| : demuxer_(demuxer),
|
| + message_loop_(base::MessageLoopProxy::current()),
|
| stream_(stream),
|
| type_(UNKNOWN),
|
| stopped_(false),
|
| @@ -67,17 +68,15 @@ FFmpegDemuxerStream::FFmpegDemuxerStream(
|
| }
|
|
|
| bool FFmpegDemuxerStream::HasPendingReads() {
|
| - DCHECK(demuxer_->message_loop()->BelongsToCurrentThread());
|
| - base::AutoLock auto_lock(lock_);
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| DCHECK(!stopped_ || read_queue_.empty())
|
| << "Read queue should have been emptied if demuxing stream is stopped";
|
| return !read_queue_.empty();
|
| }
|
|
|
| void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) {
|
| - DCHECK(demuxer_->message_loop()->BelongsToCurrentThread());
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
|
|
| - base::AutoLock auto_lock(lock_);
|
| if (stopped_) {
|
| NOTREACHED() << "Attempted to enqueue packet on a stopped stream";
|
| return;
|
| @@ -105,33 +104,28 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) {
|
| last_packet_timestamp_ != kNoTimestamp() &&
|
| last_packet_timestamp_ < buffer->GetTimestamp()) {
|
| buffered_ranges_.Add(last_packet_timestamp_, buffer->GetTimestamp());
|
| - demuxer_->message_loop()->PostTask(FROM_HERE, base::Bind(
|
| - &FFmpegDemuxer::NotifyBufferingChanged, demuxer_));
|
| + demuxer_->NotifyBufferingChanged();
|
| }
|
| last_packet_timestamp_ = buffer->GetTimestamp();
|
| }
|
|
|
| buffer_queue_.push_back(buffer);
|
| - FulfillPendingRead();
|
| - return;
|
| + SatisfyPendingReads();
|
| }
|
|
|
| void FFmpegDemuxerStream::FlushBuffers() {
|
| - DCHECK(demuxer_->message_loop()->BelongsToCurrentThread());
|
| - base::AutoLock auto_lock(lock_);
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| DCHECK(read_queue_.empty()) << "Read requests should be empty";
|
| buffer_queue_.clear();
|
| last_packet_timestamp_ = kNoTimestamp();
|
| }
|
|
|
| void FFmpegDemuxerStream::Stop() {
|
| - DCHECK(demuxer_->message_loop()->BelongsToCurrentThread());
|
| - base::AutoLock auto_lock(lock_);
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| buffer_queue_.clear();
|
| for (ReadQueue::iterator it = read_queue_.begin();
|
| it != read_queue_.end(); ++it) {
|
| - it->Run(DemuxerStream::kOk,
|
| - scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer()));
|
| + it->Run(DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer());
|
| }
|
| read_queue_.clear();
|
| stopped_ = true;
|
| @@ -146,76 +140,31 @@ DemuxerStream::Type FFmpegDemuxerStream::type() {
|
| }
|
|
|
| void FFmpegDemuxerStream::Read(const ReadCB& read_cb) {
|
| - DCHECK(!read_cb.is_null());
|
| -
|
| - base::AutoLock auto_lock(lock_);
|
| - // Don't accept any additional reads if we've been told to stop.
|
| - // The demuxer_ may have been destroyed in the pipleine thread.
|
| - //
|
| - // TODO(scherkus): it would be cleaner if we replied with an error message.
|
| - if (stopped_) {
|
| - read_cb.Run(DemuxerStream::kOk,
|
| - scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer()));
|
| + if (!message_loop_->BelongsToCurrentThread()) {
|
| + message_loop_->PostTask(FROM_HERE, base::Bind(
|
| + &FFmpegDemuxerStream::Read, this, read_cb));
|
| return;
|
| }
|
|
|
| - // Buffers are only queued when there are no pending reads.
|
| - DCHECK(buffer_queue_.empty() || read_queue_.empty());
|
| -
|
| - if (buffer_queue_.empty()) {
|
| - demuxer_->message_loop()->PostTask(FROM_HERE, base::Bind(
|
| - &FFmpegDemuxerStream::ReadTask, this, read_cb));
|
| - return;
|
| - }
|
| -
|
| - // Send the oldest buffer back.
|
| - scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front();
|
| - buffer_queue_.pop_front();
|
| - read_cb.Run(DemuxerStream::kOk, buffer);
|
| -}
|
| -
|
| -void FFmpegDemuxerStream::ReadTask(const ReadCB& read_cb) {
|
| - DCHECK(demuxer_->message_loop()->BelongsToCurrentThread());
|
| -
|
| - base::AutoLock auto_lock(lock_);
|
| // 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 if we replied with an error message.
|
| + // TODO(scherkus): it would be cleaner to reply with an error message.
|
| if (stopped_) {
|
| - read_cb.Run(DemuxerStream::kOk,
|
| - scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer()));
|
| + read_cb.Run(DemuxerStream::kOk, DecoderBuffer::CreateEOSBuffer());
|
| return;
|
| }
|
|
|
| - // Enqueue the callback and attempt to satisfy it immediately.
|
| read_queue_.push_back(read_cb);
|
| - FulfillPendingRead();
|
| -
|
| - // Check if there are still pending reads, demux some more.
|
| - if (!read_queue_.empty()) {
|
| - demuxer_->PostDemuxTask();
|
| - }
|
| + SatisfyPendingReads();
|
| }
|
|
|
| -void FFmpegDemuxerStream::FulfillPendingRead() {
|
| - DCHECK(demuxer_->message_loop()->BelongsToCurrentThread());
|
| - lock_.AssertAcquired();
|
| - if (buffer_queue_.empty() || read_queue_.empty()) {
|
| +void FFmpegDemuxerStream::EnableBitstreamConverter() {
|
| + if (!message_loop_->BelongsToCurrentThread()) {
|
| + message_loop_->PostTask(FROM_HERE, base::Bind(
|
| + &FFmpegDemuxerStream::EnableBitstreamConverter, this));
|
| return;
|
| }
|
| -
|
| - // Dequeue a buffer and pending read pair.
|
| - scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front();
|
| - ReadCB read_cb(read_queue_.front());
|
| - buffer_queue_.pop_front();
|
| - read_queue_.pop_front();
|
| -
|
| - // Execute the callback.
|
| - read_cb.Run(DemuxerStream::kOk, buffer);
|
| -}
|
| -
|
| -void FFmpegDemuxerStream::EnableBitstreamConverter() {
|
| - base::AutoLock auto_lock(lock_);
|
| CHECK(bitstream_converter_.get());
|
| bitstream_converter_enabled_ = true;
|
| }
|
| @@ -231,7 +180,6 @@ const VideoDecoderConfig& FFmpegDemuxerStream::video_decoder_config() {
|
| }
|
|
|
| FFmpegDemuxerStream::~FFmpegDemuxerStream() {
|
| - base::AutoLock auto_lock(lock_);
|
| DCHECK(stopped_);
|
| DCHECK(read_queue_.empty());
|
| DCHECK(buffer_queue_.empty());
|
| @@ -242,10 +190,28 @@ base::TimeDelta FFmpegDemuxerStream::GetElapsedTime() const {
|
| }
|
|
|
| Ranges<base::TimeDelta> FFmpegDemuxerStream::GetBufferedRanges() const {
|
| - base::AutoLock auto_lock(lock_);
|
| return buffered_ranges_;
|
| }
|
|
|
| +void FFmpegDemuxerStream::SatisfyPendingReads() {
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| + while (!read_queue_.empty() && !buffer_queue_.empty()) {
|
| + ReadCB read_cb = read_queue_.front();
|
| + read_queue_.pop_front();
|
| +
|
| + // Send earliest buffer back on a new execution stack to avoid recursing.
|
| + scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front();
|
| + buffer_queue_.pop_front();
|
| + message_loop_->PostTask(FROM_HERE, base::Bind(
|
| + read_cb, DemuxerStream::kOk, buffer));
|
| + }
|
| +
|
| + // No buffers but pending reads? Ask for more!
|
| + if (!read_queue_.empty() && buffer_queue_.empty()) {
|
| + demuxer_->NotifyHasPendingRead();
|
| + }
|
| +}
|
| +
|
| // static
|
| base::TimeDelta FFmpegDemuxerStream::ConvertStreamTimestamp(
|
| const AVRational& time_base, int64 timestamp) {
|
| @@ -277,11 +243,6 @@ FFmpegDemuxer::FFmpegDemuxer(
|
|
|
| FFmpegDemuxer::~FFmpegDemuxer() {}
|
|
|
| -void FFmpegDemuxer::PostDemuxTask() {
|
| - message_loop_->PostTask(FROM_HERE,
|
| - base::Bind(&FFmpegDemuxer::DemuxTask, this));
|
| -}
|
| -
|
| void FFmpegDemuxer::Stop(const base::Closure& callback) {
|
| // Post a task to notify the streams to stop as well.
|
| message_loop_->PostTask(FROM_HERE,
|
| @@ -329,10 +290,6 @@ base::TimeDelta FFmpegDemuxer::GetStartTime() const {
|
| return start_time_;
|
| }
|
|
|
| -scoped_refptr<base::MessageLoopProxy> FFmpegDemuxer::message_loop() {
|
| - return message_loop_;
|
| -}
|
| -
|
| // Helper for calculating the bitrate of the media based on information stored
|
| // in |format_context| or failing that the size and duration of the media.
|
| //
|
| @@ -600,9 +557,6 @@ void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) {
|
| }
|
|
|
| // Queue the packet with the appropriate stream.
|
| - // TODO(scherkus): should we post this back to the pipeline thread? I'm
|
| - // worried about downstream filters (i.e., decoders) executing on this
|
| - // thread.
|
| DCHECK_GE(packet->stream_index, 0);
|
| DCHECK_LT(packet->stream_index, static_cast<int>(streams_.size()));
|
|
|
| @@ -619,7 +573,8 @@ void FFmpegDemuxer::OnReadFrameDone(ScopedAVPacket packet, int result) {
|
| // Create a loop by posting another task. This allows seek and message loop
|
| // quit tasks to get processed.
|
| if (StreamsHavePendingReads()) {
|
| - PostDemuxTask();
|
| + message_loop_->PostTask(FROM_HERE, base::Bind(
|
| + &FFmpegDemuxer::DemuxTask, this));
|
| }
|
| }
|
|
|
| @@ -681,6 +636,11 @@ void FFmpegDemuxer::StreamHasEnded() {
|
| }
|
| }
|
|
|
| +void FFmpegDemuxer::NotifyHasPendingRead() {
|
| + DCHECK(message_loop_->BelongsToCurrentThread());
|
| + DemuxTask();
|
| +}
|
| +
|
| void FFmpegDemuxer::NotifyBufferingChanged() {
|
| DCHECK(message_loop_->BelongsToCurrentThread());
|
| Ranges<base::TimeDelta> buffered;
|
|
|