| 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_demuxer.h" | 5 #include "media/filters/ffmpeg_demuxer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 default: | 52 default: |
| 53 NOTREACHED(); | 53 NOTREACHED(); |
| 54 break; | 54 break; |
| 55 } | 55 } |
| 56 | 56 |
| 57 // Calculate the duration. | 57 // Calculate the duration. |
| 58 duration_ = ConvertStreamTimestamp(stream->time_base, stream->duration); | 58 duration_ = ConvertStreamTimestamp(stream->time_base, stream->duration); |
| 59 } | 59 } |
| 60 | 60 |
| 61 bool FFmpegDemuxerStream::HasPendingReads() { | 61 bool FFmpegDemuxerStream::HasPendingReads() { |
| 62 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 62 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); |
| 63 base::AutoLock auto_lock(lock_); | 63 base::AutoLock auto_lock(lock_); |
| 64 DCHECK(!stopped_ || read_queue_.empty()) | 64 DCHECK(!stopped_ || read_queue_.empty()) |
| 65 << "Read queue should have been emptied if demuxing stream is stopped"; | 65 << "Read queue should have been emptied if demuxing stream is stopped"; |
| 66 return !read_queue_.empty(); | 66 return !read_queue_.empty(); |
| 67 } | 67 } |
| 68 | 68 |
| 69 void FFmpegDemuxerStream::EnqueuePacket( | 69 void FFmpegDemuxerStream::EnqueuePacket( |
| 70 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet) { | 70 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet) { |
| 71 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 71 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); |
| 72 | 72 |
| 73 base::AutoLock auto_lock(lock_); | 73 base::AutoLock auto_lock(lock_); |
| 74 if (stopped_) { | 74 if (stopped_) { |
| 75 NOTREACHED() << "Attempted to enqueue packet on a stopped stream"; | 75 NOTREACHED() << "Attempted to enqueue packet on a stopped stream"; |
| 76 return; | 76 return; |
| 77 } | 77 } |
| 78 | 78 |
| 79 scoped_refptr<DecoderBuffer> buffer; | 79 scoped_refptr<DecoderBuffer> buffer; |
| 80 if (!packet.get()) { | 80 if (!packet.get()) { |
| 81 buffer = DecoderBuffer::CreateEOSBuffer(); | 81 buffer = DecoderBuffer::CreateEOSBuffer(); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 103 } | 103 } |
| 104 last_packet_timestamp_ = buffer->GetTimestamp(); | 104 last_packet_timestamp_ = buffer->GetTimestamp(); |
| 105 } | 105 } |
| 106 | 106 |
| 107 buffer_queue_.push_back(buffer); | 107 buffer_queue_.push_back(buffer); |
| 108 FulfillPendingRead(); | 108 FulfillPendingRead(); |
| 109 return; | 109 return; |
| 110 } | 110 } |
| 111 | 111 |
| 112 void FFmpegDemuxerStream::FlushBuffers() { | 112 void FFmpegDemuxerStream::FlushBuffers() { |
| 113 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 113 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); |
| 114 base::AutoLock auto_lock(lock_); | 114 base::AutoLock auto_lock(lock_); |
| 115 DCHECK(read_queue_.empty()) << "Read requests should be empty"; | 115 DCHECK(read_queue_.empty()) << "Read requests should be empty"; |
| 116 buffer_queue_.clear(); | 116 buffer_queue_.clear(); |
| 117 last_packet_timestamp_ = kNoTimestamp(); | 117 last_packet_timestamp_ = kNoTimestamp(); |
| 118 } | 118 } |
| 119 | 119 |
| 120 void FFmpegDemuxerStream::Stop() { | 120 void FFmpegDemuxerStream::Stop() { |
| 121 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 121 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); |
| 122 base::AutoLock auto_lock(lock_); | 122 base::AutoLock auto_lock(lock_); |
| 123 buffer_queue_.clear(); | 123 buffer_queue_.clear(); |
| 124 for (ReadQueue::iterator it = read_queue_.begin(); | 124 for (ReadQueue::iterator it = read_queue_.begin(); |
| 125 it != read_queue_.end(); ++it) { | 125 it != read_queue_.end(); ++it) { |
| 126 it->Run(DemuxerStream::kOk, | 126 it->Run(DemuxerStream::kOk, |
| 127 scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer())); | 127 scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer())); |
| 128 } | 128 } |
| 129 read_queue_.clear(); | 129 read_queue_.clear(); |
| 130 stopped_ = true; | 130 stopped_ = true; |
| 131 } | 131 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 161 return; | 161 return; |
| 162 } | 162 } |
| 163 | 163 |
| 164 // Send the oldest buffer back. | 164 // Send the oldest buffer back. |
| 165 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front(); | 165 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front(); |
| 166 buffer_queue_.pop_front(); | 166 buffer_queue_.pop_front(); |
| 167 read_cb.Run(DemuxerStream::kOk, buffer); | 167 read_cb.Run(DemuxerStream::kOk, buffer); |
| 168 } | 168 } |
| 169 | 169 |
| 170 void FFmpegDemuxerStream::ReadTask(const ReadCB& read_cb) { | 170 void FFmpegDemuxerStream::ReadTask(const ReadCB& read_cb) { |
| 171 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 171 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); |
| 172 | 172 |
| 173 base::AutoLock auto_lock(lock_); | 173 base::AutoLock auto_lock(lock_); |
| 174 // Don't accept any additional reads if we've been told to stop. | 174 // Don't accept any additional reads if we've been told to stop. |
| 175 // | 175 // |
| 176 // TODO(scherkus): it would be cleaner if we replied with an error message. | 176 // TODO(scherkus): it would be cleaner if we replied with an error message. |
| 177 if (stopped_) { | 177 if (stopped_) { |
| 178 read_cb.Run(DemuxerStream::kOk, | 178 read_cb.Run(DemuxerStream::kOk, |
| 179 scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer())); | 179 scoped_refptr<DecoderBuffer>(DecoderBuffer::CreateEOSBuffer())); |
| 180 return; | 180 return; |
| 181 } | 181 } |
| 182 | 182 |
| 183 // Enqueue the callback and attempt to satisfy it immediately. | 183 // Enqueue the callback and attempt to satisfy it immediately. |
| 184 read_queue_.push_back(read_cb); | 184 read_queue_.push_back(read_cb); |
| 185 FulfillPendingRead(); | 185 FulfillPendingRead(); |
| 186 | 186 |
| 187 // Check if there are still pending reads, demux some more. | 187 // Check if there are still pending reads, demux some more. |
| 188 if (!read_queue_.empty()) { | 188 if (!read_queue_.empty()) { |
| 189 demuxer_->PostDemuxTask(); | 189 demuxer_->PostDemuxTask(); |
| 190 } | 190 } |
| 191 } | 191 } |
| 192 | 192 |
| 193 void FFmpegDemuxerStream::FulfillPendingRead() { | 193 void FFmpegDemuxerStream::FulfillPendingRead() { |
| 194 DCHECK_EQ(MessageLoop::current(), demuxer_->message_loop()); | 194 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); |
| 195 lock_.AssertAcquired(); | 195 lock_.AssertAcquired(); |
| 196 if (buffer_queue_.empty() || read_queue_.empty()) { | 196 if (buffer_queue_.empty() || read_queue_.empty()) { |
| 197 return; | 197 return; |
| 198 } | 198 } |
| 199 | 199 |
| 200 // Dequeue a buffer and pending read pair. | 200 // Dequeue a buffer and pending read pair. |
| 201 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front(); | 201 scoped_refptr<DecoderBuffer> buffer = buffer_queue_.front(); |
| 202 ReadCB read_cb(read_queue_.front()); | 202 ReadCB read_cb(read_queue_.front()); |
| 203 buffer_queue_.pop_front(); | 203 buffer_queue_.pop_front(); |
| 204 read_queue_.pop_front(); | 204 read_queue_.pop_front(); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 if (timestamp == static_cast<int64>(AV_NOPTS_VALUE)) | 248 if (timestamp == static_cast<int64>(AV_NOPTS_VALUE)) |
| 249 return kNoTimestamp(); | 249 return kNoTimestamp(); |
| 250 | 250 |
| 251 return ConvertFromTimeBase(time_base, timestamp); | 251 return ConvertFromTimeBase(time_base, timestamp); |
| 252 } | 252 } |
| 253 | 253 |
| 254 // | 254 // |
| 255 // FFmpegDemuxer | 255 // FFmpegDemuxer |
| 256 // | 256 // |
| 257 FFmpegDemuxer::FFmpegDemuxer( | 257 FFmpegDemuxer::FFmpegDemuxer( |
| 258 MessageLoop* message_loop, | 258 const scoped_refptr<base::MessageLoopProxy>& message_loop, |
| 259 const scoped_refptr<DataSource>& data_source) | 259 const scoped_refptr<DataSource>& data_source) |
| 260 : host_(NULL), | 260 : host_(NULL), |
| 261 message_loop_(message_loop), | 261 message_loop_(message_loop), |
| 262 format_context_(NULL), | 262 format_context_(NULL), |
| 263 data_source_(data_source), | 263 data_source_(data_source), |
| 264 read_event_(false, false), | 264 read_event_(false, false), |
| 265 read_has_failed_(false), | 265 read_has_failed_(false), |
| 266 last_read_bytes_(0), | 266 last_read_bytes_(0), |
| 267 read_position_(0), | 267 read_position_(0), |
| 268 bitrate_(0), | 268 bitrate_(0), |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 DCHECK(data_source_); | 401 DCHECK(data_source_); |
| 402 return data_source_->GetSize(size_out); | 402 return data_source_->GetSize(size_out); |
| 403 } | 403 } |
| 404 | 404 |
| 405 bool FFmpegDemuxer::IsStreaming() { | 405 bool FFmpegDemuxer::IsStreaming() { |
| 406 DCHECK(host_); | 406 DCHECK(host_); |
| 407 DCHECK(data_source_); | 407 DCHECK(data_source_); |
| 408 return data_source_->IsStreaming(); | 408 return data_source_->IsStreaming(); |
| 409 } | 409 } |
| 410 | 410 |
| 411 MessageLoop* FFmpegDemuxer::message_loop() { | 411 scoped_refptr<base::MessageLoopProxy> FFmpegDemuxer::message_loop() { |
| 412 return message_loop_; | 412 return message_loop_; |
| 413 } | 413 } |
| 414 | 414 |
| 415 // Helper for calculating the bitrate of the media based on information stored | 415 // Helper for calculating the bitrate of the media based on information stored |
| 416 // in |format_context| or failing that the size and duration of the media. | 416 // in |format_context| or failing that the size and duration of the media. |
| 417 // | 417 // |
| 418 // Returns 0 if a bitrate could not be determined. | 418 // Returns 0 if a bitrate could not be determined. |
| 419 static int CalculateBitrate( | 419 static int CalculateBitrate( |
| 420 AVFormatContext* format_context, | 420 AVFormatContext* format_context, |
| 421 const base::TimeDelta& duration, | 421 const base::TimeDelta& duration, |
| (...skipping 21 matching lines...) Expand all Loading... |
| 443 | 443 |
| 444 // Do math in floating point as we'd overflow an int64 if the filesize was | 444 // Do math in floating point as we'd overflow an int64 if the filesize was |
| 445 // larger than ~1073GB. | 445 // larger than ~1073GB. |
| 446 double bytes = filesize_in_bytes; | 446 double bytes = filesize_in_bytes; |
| 447 double duration_us = duration.InMicroseconds(); | 447 double duration_us = duration.InMicroseconds(); |
| 448 return bytes * 8000000.0 / duration_us; | 448 return bytes * 8000000.0 / duration_us; |
| 449 } | 449 } |
| 450 | 450 |
| 451 void FFmpegDemuxer::InitializeTask(DemuxerHost* host, | 451 void FFmpegDemuxer::InitializeTask(DemuxerHost* host, |
| 452 const PipelineStatusCB& status_cb) { | 452 const PipelineStatusCB& status_cb) { |
| 453 DCHECK_EQ(MessageLoop::current(), message_loop_); | 453 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 454 host_ = host; | 454 host_ = host; |
| 455 | 455 |
| 456 // TODO(scherkus): DataSource should have a host by this point, | 456 // TODO(scherkus): DataSource should have a host by this point, |
| 457 // see http://crbug.com/122071 | 457 // see http://crbug.com/122071 |
| 458 data_source_->set_host(host); | 458 data_source_->set_host(host); |
| 459 | 459 |
| 460 // Add ourself to Protocol list and get our unique key. | 460 // Add ourself to Protocol list and get our unique key. |
| 461 std::string key = FFmpegGlue::GetInstance()->AddProtocol(this); | 461 std::string key = FFmpegGlue::GetInstance()->AddProtocol(this); |
| 462 | 462 |
| 463 // Open FFmpeg AVFormatContext. | 463 // Open FFmpeg AVFormatContext. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 int64 filesize_in_bytes = 0; | 562 int64 filesize_in_bytes = 0; |
| 563 GetSize(&filesize_in_bytes); | 563 GetSize(&filesize_in_bytes); |
| 564 bitrate_ = CalculateBitrate(format_context_, max_duration, filesize_in_bytes); | 564 bitrate_ = CalculateBitrate(format_context_, max_duration, filesize_in_bytes); |
| 565 if (bitrate_ > 0) | 565 if (bitrate_ > 0) |
| 566 data_source_->SetBitrate(bitrate_); | 566 data_source_->SetBitrate(bitrate_); |
| 567 | 567 |
| 568 status_cb.Run(PIPELINE_OK); | 568 status_cb.Run(PIPELINE_OK); |
| 569 } | 569 } |
| 570 | 570 |
| 571 void FFmpegDemuxer::SeekTask(base::TimeDelta time, const PipelineStatusCB& cb) { | 571 void FFmpegDemuxer::SeekTask(base::TimeDelta time, const PipelineStatusCB& cb) { |
| 572 DCHECK_EQ(MessageLoop::current(), message_loop_); | 572 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 573 | 573 |
| 574 // Tell streams to flush buffers due to seeking. | 574 // Tell streams to flush buffers due to seeking. |
| 575 StreamVector::iterator iter; | 575 StreamVector::iterator iter; |
| 576 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 576 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
| 577 if (*iter) | 577 if (*iter) |
| 578 (*iter)->FlushBuffers(); | 578 (*iter)->FlushBuffers(); |
| 579 } | 579 } |
| 580 | 580 |
| 581 // Always seek to a timestamp less than or equal to the desired timestamp. | 581 // Always seek to a timestamp less than or equal to the desired timestamp. |
| 582 int flags = AVSEEK_FLAG_BACKWARD; | 582 int flags = AVSEEK_FLAG_BACKWARD; |
| 583 | 583 |
| 584 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg | 584 // Passing -1 as our stream index lets FFmpeg pick a default stream. FFmpeg |
| 585 // will attempt to use the lowest-index video stream, if present, followed by | 585 // will attempt to use the lowest-index video stream, if present, followed by |
| 586 // the lowest-index audio stream. | 586 // the lowest-index audio stream. |
| 587 if (av_seek_frame(format_context_, -1, time.InMicroseconds(), flags) < 0) { | 587 if (av_seek_frame(format_context_, -1, time.InMicroseconds(), flags) < 0) { |
| 588 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being | 588 // Use VLOG(1) instead of NOTIMPLEMENTED() to prevent the message being |
| 589 // captured from stdout and contaminates testing. | 589 // captured from stdout and contaminates testing. |
| 590 // TODO(scherkus): Implement this properly and signal error (BUG=23447). | 590 // TODO(scherkus): Implement this properly and signal error (BUG=23447). |
| 591 VLOG(1) << "Not implemented"; | 591 VLOG(1) << "Not implemented"; |
| 592 } | 592 } |
| 593 | 593 |
| 594 // Notify we're finished seeking. | 594 // Notify we're finished seeking. |
| 595 cb.Run(PIPELINE_OK); | 595 cb.Run(PIPELINE_OK); |
| 596 } | 596 } |
| 597 | 597 |
| 598 void FFmpegDemuxer::DemuxTask() { | 598 void FFmpegDemuxer::DemuxTask() { |
| 599 DCHECK_EQ(MessageLoop::current(), message_loop_); | 599 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 600 | 600 |
| 601 // Make sure we have work to do before demuxing. | 601 // Make sure we have work to do before demuxing. |
| 602 if (!StreamsHavePendingReads()) { | 602 if (!StreamsHavePendingReads()) { |
| 603 return; | 603 return; |
| 604 } | 604 } |
| 605 | 605 |
| 606 // Allocate and read an AVPacket from the media. | 606 // Allocate and read an AVPacket from the media. |
| 607 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet(new AVPacket()); | 607 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket> packet(new AVPacket()); |
| 608 int result = av_read_frame(format_context_, packet.get()); | 608 int result = av_read_frame(format_context_, packet.get()); |
| 609 if (result < 0) { | 609 if (result < 0) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 648 } | 648 } |
| 649 | 649 |
| 650 // Create a loop by posting another task. This allows seek and message loop | 650 // Create a loop by posting another task. This allows seek and message loop |
| 651 // quit tasks to get processed. | 651 // quit tasks to get processed. |
| 652 if (StreamsHavePendingReads()) { | 652 if (StreamsHavePendingReads()) { |
| 653 PostDemuxTask(); | 653 PostDemuxTask(); |
| 654 } | 654 } |
| 655 } | 655 } |
| 656 | 656 |
| 657 void FFmpegDemuxer::StopTask(const base::Closure& callback) { | 657 void FFmpegDemuxer::StopTask(const base::Closure& callback) { |
| 658 DCHECK_EQ(MessageLoop::current(), message_loop_); | 658 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 659 StreamVector::iterator iter; | 659 StreamVector::iterator iter; |
| 660 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 660 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
| 661 if (*iter) | 661 if (*iter) |
| 662 (*iter)->Stop(); | 662 (*iter)->Stop(); |
| 663 } | 663 } |
| 664 if (data_source_) { | 664 if (data_source_) { |
| 665 data_source_->Stop(callback); | 665 data_source_->Stop(callback); |
| 666 } else { | 666 } else { |
| 667 callback.Run(); | 667 callback.Run(); |
| 668 } | 668 } |
| 669 } | 669 } |
| 670 | 670 |
| 671 void FFmpegDemuxer::DisableAudioStreamTask() { | 671 void FFmpegDemuxer::DisableAudioStreamTask() { |
| 672 DCHECK_EQ(MessageLoop::current(), message_loop_); | 672 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 673 audio_disabled_ = true; | 673 audio_disabled_ = true; |
| 674 StreamVector::iterator iter; | 674 StreamVector::iterator iter; |
| 675 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 675 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
| 676 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { | 676 if (*iter && (*iter)->type() == DemuxerStream::AUDIO) { |
| 677 (*iter)->Stop(); | 677 (*iter)->Stop(); |
| 678 } | 678 } |
| 679 } | 679 } |
| 680 } | 680 } |
| 681 | 681 |
| 682 bool FFmpegDemuxer::StreamsHavePendingReads() { | 682 bool FFmpegDemuxer::StreamsHavePendingReads() { |
| 683 DCHECK_EQ(MessageLoop::current(), message_loop_); | 683 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 684 StreamVector::iterator iter; | 684 StreamVector::iterator iter; |
| 685 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 685 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
| 686 if (*iter && (*iter)->HasPendingReads()) { | 686 if (*iter && (*iter)->HasPendingReads()) { |
| 687 return true; | 687 return true; |
| 688 } | 688 } |
| 689 } | 689 } |
| 690 return false; | 690 return false; |
| 691 } | 691 } |
| 692 | 692 |
| 693 void FFmpegDemuxer::StreamHasEnded() { | 693 void FFmpegDemuxer::StreamHasEnded() { |
| 694 DCHECK_EQ(MessageLoop::current(), message_loop_); | 694 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 695 StreamVector::iterator iter; | 695 StreamVector::iterator iter; |
| 696 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { | 696 for (iter = streams_.begin(); iter != streams_.end(); ++iter) { |
| 697 if (!*iter || | 697 if (!*iter || |
| 698 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) { | 698 (audio_disabled_ && (*iter)->type() == DemuxerStream::AUDIO)) { |
| 699 continue; | 699 continue; |
| 700 } | 700 } |
| 701 (*iter)->EnqueuePacket( | 701 (*iter)->EnqueuePacket( |
| 702 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket>()); | 702 scoped_ptr_malloc<AVPacket, ScopedPtrAVFreePacket>()); |
| 703 } | 703 } |
| 704 } | 704 } |
| 705 | 705 |
| 706 int FFmpegDemuxer::WaitForRead() { | 706 int FFmpegDemuxer::WaitForRead() { |
| 707 read_event_.Wait(); | 707 read_event_.Wait(); |
| 708 return last_read_bytes_; | 708 return last_read_bytes_; |
| 709 } | 709 } |
| 710 | 710 |
| 711 void FFmpegDemuxer::SignalReadCompleted(int size) { | 711 void FFmpegDemuxer::SignalReadCompleted(int size) { |
| 712 last_read_bytes_ = size; | 712 last_read_bytes_ = size; |
| 713 read_event_.Signal(); | 713 read_event_.Signal(); |
| 714 } | 714 } |
| 715 | 715 |
| 716 void FFmpegDemuxer::NotifyBufferingChanged() { | 716 void FFmpegDemuxer::NotifyBufferingChanged() { |
| 717 DCHECK_EQ(MessageLoop::current(), message_loop_); | 717 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 718 Ranges<base::TimeDelta> buffered; | 718 Ranges<base::TimeDelta> buffered; |
| 719 scoped_refptr<FFmpegDemuxerStream> audio = | 719 scoped_refptr<FFmpegDemuxerStream> audio = |
| 720 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO); | 720 audio_disabled_ ? NULL : GetFFmpegStream(DemuxerStream::AUDIO); |
| 721 scoped_refptr<FFmpegDemuxerStream> video = | 721 scoped_refptr<FFmpegDemuxerStream> video = |
| 722 GetFFmpegStream(DemuxerStream::VIDEO); | 722 GetFFmpegStream(DemuxerStream::VIDEO); |
| 723 if (audio && video) { | 723 if (audio && video) { |
| 724 buffered = audio->GetBufferedRanges().IntersectionWith( | 724 buffered = audio->GetBufferedRanges().IntersectionWith( |
| 725 video->GetBufferedRanges()); | 725 video->GetBufferedRanges()); |
| 726 } else if (audio) { | 726 } else if (audio) { |
| 727 buffered = audio->GetBufferedRanges(); | 727 buffered = audio->GetBufferedRanges(); |
| 728 } else if (video) { | 728 } else if (video) { |
| 729 buffered = video->GetBufferedRanges(); | 729 buffered = video->GetBufferedRanges(); |
| 730 } | 730 } |
| 731 for (size_t i = 0; i < buffered.size(); ++i) | 731 for (size_t i = 0; i < buffered.size(); ++i) |
| 732 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); | 732 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); |
| 733 } | 733 } |
| 734 | 734 |
| 735 } // namespace media | 735 } // namespace media |
| OLD | NEW |