diff options
30 files changed, 172 insertions, 160 deletions
diff --git a/media/base/composite_filter.cc b/media/base/composite_filter.cc index f613f36..5c4b1c5 100644 --- a/media/base/composite_filter.cc +++ b/media/base/composite_filter.cc @@ -27,9 +27,7 @@ class CompositeFilter::FilterHostImpl : public FilterHost { virtual void SetTotalBytes(int64 total_bytes) OVERRIDE; virtual void SetBufferedBytes(int64 buffered_bytes) OVERRIDE; virtual void SetNaturalVideoSize(const gfx::Size& size) OVERRIDE; - virtual void SetStreaming(bool streaming) OVERRIDE; virtual void NotifyEnded() OVERRIDE; - virtual void SetLoaded(bool loaded) OVERRIDE; virtual void SetNetworkActivity(bool network_activity) OVERRIDE; virtual void DisableAudioRenderer() OVERRIDE; virtual void SetCurrentReadPosition(int64 offset) OVERRIDE; @@ -515,18 +513,10 @@ void CompositeFilter::FilterHostImpl::SetNaturalVideoSize( host_->SetNaturalVideoSize(size); } -void CompositeFilter::FilterHostImpl::SetStreaming(bool streaming) { - host_->SetStreaming(streaming); -} - void CompositeFilter::FilterHostImpl::NotifyEnded() { host_->NotifyEnded(); } -void CompositeFilter::FilterHostImpl::SetLoaded(bool loaded) { - host_->SetLoaded(loaded); -} - void CompositeFilter::FilterHostImpl::SetNetworkActivity( bool network_activity) { host_->SetNetworkActivity(network_activity); diff --git a/media/base/demuxer.h b/media/base/demuxer.h index a75f248..972d250 100644 --- a/media/base/demuxer.h +++ b/media/base/demuxer.h @@ -61,6 +61,13 @@ class MEDIA_EXPORT Demuxer // approximated. Returns 0 if it is unknown. virtual int GetBitrate() = 0; + // Returns true if the source is from a local file or stream (such as a + // webcam stream), false otherwise. + virtual bool IsLocalSource() = 0; + + // Returns true if seeking is possible; false otherwise. + virtual bool IsSeekable() = 0; + protected: Demuxer(); FilterHost* host() { return host_; } diff --git a/media/base/download_rate_monitor.cc b/media/base/download_rate_monitor.cc index 88916e4..f27b2e8 100644 --- a/media/base/download_rate_monitor.cc +++ b/media/base/download_rate_monitor.cc @@ -73,8 +73,11 @@ DownloadRateMonitor::DownloadRateMonitor() { } void DownloadRateMonitor::Start( - const base::Closure& canplaythrough_cb, int media_bitrate) { + const base::Closure& canplaythrough_cb, int media_bitrate, + bool streaming, bool local_source) { canplaythrough_cb_ = canplaythrough_cb; + streaming_ = streaming; + local_source_ = local_source; stopped_ = false; bitrate_ = media_bitrate; current_sample_.Reset(); @@ -139,9 +142,10 @@ void DownloadRateMonitor::Reset() { is_downloading_data_ = false; total_bytes_ = -1; buffered_bytes_ = 0; - loaded_ = false; + local_source_ = false; bitrate_ = 0; stopped_ = true; + streaming_ = false; } DownloadRateMonitor::~DownloadRateMonitor() { } @@ -198,14 +202,23 @@ bool DownloadRateMonitor::ShouldNotifyCanPlayThrough() { if (has_notified_can_play_through_) return false; - // If the media is from a local file (|loaded_|) or if all bytes are - // buffered, fire CanPlayThrough. - if (loaded_ || buffered_bytes_ == total_bytes_) + // Fire CanPlayThrough immediately if the source is local or streaming. + // + // NOTE: It is a requirement for CanPlayThrough to fire immediately if the + // source is local, but the choice to optimistically fire the event for any + // streaming media element is a design decision that may need to be tweaked. + if (local_source_ || streaming_) + return true; + + // If all bytes are buffered, fire CanPlayThrough. + if (buffered_bytes_ == total_bytes_) return true; - // Cannot approximate when the media can play through if bitrate is unknown. + // If bitrate is unknown, optimistically fire CanPlayThrough immediately. + // This is so a video with an unknown bitrate with the "autoplay" attribute + // will not wait until the entire file is downloaded before playback begins. if (bitrate_ <= 0) - return false; + return true; float bytes_needed_per_second = bitrate_ / 8; float download_rate = ApproximateDownloadByteRate(); diff --git a/media/base/download_rate_monitor.h b/media/base/download_rate_monitor.h index ac88f7f..e3b29dd 100644 --- a/media/base/download_rate_monitor.h +++ b/media/base/download_rate_monitor.h @@ -25,7 +25,8 @@ class MEDIA_EXPORT DownloadRateMonitor { // Begin measuring download rate. The monitor will run |canplaythrough_cb| // when it believes the media can be played back without needing to pause to // buffer. |media_bitrate| is the bitrate of the video. - void Start(const base::Closure& canplaythrough_cb, int media_bitrate); + void Start(const base::Closure& canplaythrough_cb, int media_bitrate, + bool streaming, bool local_source); // Notifies the monitor of the current number of bytes buffered by the media // file at what timestamp. The monitor expects subsequent calls to @@ -40,8 +41,6 @@ class MEDIA_EXPORT DownloadRateMonitor { void set_total_bytes(int64 total_bytes) { total_bytes_ = total_bytes; } - void set_loaded(bool loaded) { loaded_ = loaded; } - // Stop monitoring download rate. This does not discard previously learned // information, but it will no longer factor incoming information into its // canplaythrough estimation. @@ -137,8 +136,9 @@ class MEDIA_EXPORT DownloadRateMonitor { // Amount of bytes buffered. int64 buffered_bytes_; - // True if the media file is a fully loaded source, e.g. file:// protocol. - bool loaded_; + // True if the media file is from a local source, e.g. file:// protocol or a + // webcam stream. + bool local_source_; // Bitrate of the media file, 0 if unknown. int bitrate_; @@ -147,6 +147,9 @@ class MEDIA_EXPORT DownloadRateMonitor { // otherwise. bool stopped_; + // True if the data source is a streaming source, false otherwise. + bool streaming_; + DISALLOW_COPY_AND_ASSIGN(DownloadRateMonitor); }; diff --git a/media/base/download_rate_monitor_unittest.cc b/media/base/download_rate_monitor_unittest.cc index 787a5b4..496d3a0 100644 --- a/media/base/download_rate_monitor_unittest.cc +++ b/media/base/download_rate_monitor_unittest.cc @@ -49,6 +49,15 @@ class DownloadRateMonitorTest : public ::testing::Test { return bytes_buffered; } + void StartMonitor(int bitrate) { + StartMonitor(bitrate, false, false); + } + + void StartMonitor(int bitrate, bool streaming, bool local_source) { + monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, + base::Unretained(this)), bitrate, streaming, local_source); + } + DownloadRateMonitor monitor_; private: @@ -59,8 +68,7 @@ TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate) { static const int media_bitrate = 1024 * 1024 * 8; // Simulate downloading at double the media's bitrate. - monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, - base::Unretained(this)), media_bitrate); + StartMonitor(media_bitrate); EXPECT_CALL(*this, CanPlayThrough()); SimulateNetwork(1, 0, 2 * media_bitrate / 8, 1000, 10); } @@ -72,8 +80,7 @@ TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_Pause) { static const int download_byte_rate = 1.1 * media_bitrate / 8; // Start downloading faster than the media's bitrate. - monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, - base::Unretained(this)), media_bitrate); + StartMonitor(media_bitrate); EXPECT_CALL(*this, CanPlayThrough()); int buffered = SimulateNetwork(1, 0, download_byte_rate, 1000, 2); @@ -87,8 +94,7 @@ TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekForward) { // Start downloading faster than the media's bitrate. EXPECT_CALL(*this, CanPlayThrough()); - monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, - base::Unretained(this)), media_bitrate); + StartMonitor(media_bitrate); SimulateNetwork(1, 0, download_byte_rate, 1000, 2); // Then seek forward mid-file and continue downloading at same rate. @@ -100,8 +106,7 @@ TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekBackward) { static const int download_byte_rate = 1.1 * media_bitrate / 8; // Start downloading faster than the media's bitrate, in middle of file. - monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, - base::Unretained(this)), media_bitrate); + StartMonitor(media_bitrate); SimulateNetwork(1, kMediaSizeInBytes / 2, download_byte_rate, 1000, 2); // Then seek back to beginning and continue downloading at same rate. @@ -115,29 +120,32 @@ TEST_F(DownloadRateMonitorTest, DownloadRateLessThanBitrate) { // Simulate downloading at half the media's bitrate. EXPECT_CALL(*this, CanPlayThrough()) .Times(0); - monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, - base::Unretained(this)), media_bitrate); + StartMonitor(media_bitrate); SimulateNetwork(1, 0, media_bitrate / 8 / 2, 1000, 10); } -TEST_F(DownloadRateMonitorTest, MediaIsLoaded) { +TEST_F(DownloadRateMonitorTest, MediaSourceIsLocal) { static const int media_bitrate = 1024 * 1024 * 8; - monitor_.set_loaded(true); + // Simulate no data downloaded. + EXPECT_CALL(*this, CanPlayThrough()); + StartMonitor(media_bitrate, false, true); +} + +TEST_F(DownloadRateMonitorTest, MediaSourceIsStreaming) { + static const int media_bitrate = 1024 * 1024 * 8; - // Simulate no data downloaded (source is already loaded). + // Simulate downloading at the media's bitrate while streaming. EXPECT_CALL(*this, CanPlayThrough()); - monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, - base::Unretained(this)), media_bitrate); - SimulateNetwork(1, 0, 0, 1000, 10); + StartMonitor(media_bitrate, true, false); + SimulateNetwork(1, 0, media_bitrate / 8, 1000, 10); } TEST_F(DownloadRateMonitorTest, VeryFastDownloadRate) { static const int media_bitrate = 1024 * 1024 * 8; // Simulate downloading half the video very quickly in one chunk. - monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, - base::Unretained(this)), media_bitrate); + StartMonitor(media_bitrate); EXPECT_CALL(*this, CanPlayThrough()); SimulateNetwork(1, 0, kMediaSizeInBytes / 2, 10, 1); } @@ -147,8 +155,7 @@ TEST_F(DownloadRateMonitorTest, DownloadEntireVideo) { static const int media_bitrate = kMediaSizeInBytes * 8 / seconds_of_data; // Simulate downloading entire video at half the bitrate of the video. - monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough, - base::Unretained(this)), media_bitrate); + StartMonitor(media_bitrate); EXPECT_CALL(*this, CanPlayThrough()); SimulateNetwork(1, 0, media_bitrate / 8 / 2, 1000, seconds_of_data * 2); } diff --git a/media/base/filter_host.h b/media/base/filter_host.h index 412fdd7..807fd5f 100644 --- a/media/base/filter_host.h +++ b/media/base/filter_host.h @@ -56,16 +56,10 @@ class MEDIA_EXPORT FilterHost { // Sets the natural size of the video output in pixel units. virtual void SetNaturalVideoSize(const gfx::Size& size) = 0; - // Sets the flag to indicate that we are doing streaming. - virtual void SetStreaming(bool streaming) = 0; - // Notifies that this filter has ended, typically only called by filter graph // endpoints such as renderers. virtual void NotifyEnded() = 0; - // Sets the flag to indicate that our media is now loaded. - virtual void SetLoaded(bool loaded) = 0; - // Sets the flag to indicate current network activity. virtual void SetNetworkActivity(bool is_downloading_data) = 0; diff --git a/media/base/media_log.cc b/media/base/media_log.cc index dead5bd..ea61682 100644 --- a/media/base/media_log.cc +++ b/media/base/media_log.cc @@ -46,10 +46,6 @@ const char* MediaLog::EventTypeToString(MediaLogEvent::Type type) { return "DURATION_SET"; case MediaLogEvent::TOTAL_BYTES_SET: return "TOTAL_BYTES_SET"; - case MediaLogEvent::STREAMING_SET: - return "STREAMING_SET"; - case MediaLogEvent::LOADED_SET: - return "LOADED_SET"; case MediaLogEvent::NETWORK_ACTIVITY_SET: return "NETWORK_ACTIVITY_SET"; case MediaLogEvent::ENDED: diff --git a/media/base/media_log_event.h b/media/base/media_log_event.h index 8dae432..384a2e3 100644 --- a/media/base/media_log_event.h +++ b/media/base/media_log_event.h @@ -54,8 +54,6 @@ struct MediaLogEvent { // the appropriate type. e.g. DURATION_SET: "duration" of type TimeDelta. DURATION_SET, TOTAL_BYTES_SET, - STREAMING_SET, - LOADED_SET, NETWORK_ACTIVITY_SET, // Playback has ended. diff --git a/media/base/mock_filter_host.h b/media/base/mock_filter_host.h index 9b9cd7c..82ab0ac 100644 --- a/media/base/mock_filter_host.h +++ b/media/base/mock_filter_host.h @@ -33,8 +33,6 @@ class MockFilterHost : public FilterHost { MOCK_METHOD1(SetTotalBytes, void(int64 total_bytes)); MOCK_METHOD1(SetBufferedBytes, void(int64 buffered_bytes)); MOCK_METHOD1(SetNaturalVideoSize, void(const gfx::Size& size)); - MOCK_METHOD1(SetStreaming, void(bool streamed)); - MOCK_METHOD1(SetLoaded, void(bool loaded)); MOCK_METHOD1(SetNetworkActivity, void(bool network_activity)); MOCK_METHOD0(NotifyEnded, void()); MOCK_METHOD0(DisableAudioRenderer, void()); diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index f54a114..13a8d2c 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h @@ -113,6 +113,8 @@ class MockDemuxer : public Demuxer { MOCK_METHOD2(Seek, void(base::TimeDelta time, const FilterStatusCB& cb)); MOCK_METHOD0(OnAudioRendererDisabled, void()); MOCK_METHOD0(GetBitrate, int()); + MOCK_METHOD0(IsLocalSource, bool()); + MOCK_METHOD0(IsSeekable, bool()); // Demuxer implementation. MOCK_METHOD2(Initialize, void(DataSource* data_source, diff --git a/media/base/pipeline.h b/media/base/pipeline.h index 1c91f80..1534ea5 100644 --- a/media/base/pipeline.h +++ b/media/base/pipeline.h @@ -163,9 +163,9 @@ class MEDIA_EXPORT Pipeline : public base::RefCountedThreadSafe<Pipeline> { // data source. Seeking may not be possible. virtual bool IsStreaming() const = 0; - // If this method returns true, that means the data source has fully loaded - // the media and that the network is no longer needed. - virtual bool IsLoaded() const = 0; + // If this method returns true, that means the data source is local and + // the network is not needed. + virtual bool IsLocalSource() const = 0; // Gets the current pipeline statistics. virtual PipelineStatistics GetStatistics() const = 0; diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc index 386b064..d4c1b8e 100644 --- a/media/base/pipeline_impl.cc +++ b/media/base/pipeline_impl.cc @@ -251,7 +251,7 @@ base::TimeDelta PipelineImpl::GetBufferedTime() { base::AutoLock auto_lock(lock_); // If media is fully loaded, then return duration. - if (loaded_ || total_bytes_ == buffered_bytes_) { + if (local_source_ || total_bytes_ == buffered_bytes_) { max_buffered_time_ = duration_; return duration_; } @@ -312,9 +312,9 @@ bool PipelineImpl::IsStreaming() const { return streaming_; } -bool PipelineImpl::IsLoaded() const { +bool PipelineImpl::IsLocalSource() const { base::AutoLock auto_lock(lock_); - return loaded_; + return local_source_; } PipelineStatistics PipelineImpl::GetStatistics() const { @@ -358,7 +358,7 @@ void PipelineImpl::ResetState() { buffered_time_ = kZero; buffered_bytes_ = 0; streaming_ = false; - loaded_ = false; + local_source_ = false; total_bytes_ = 0; natural_size_.SetSize(0, 0); volume_ = 1.0f; @@ -547,16 +547,6 @@ void PipelineImpl::SetNaturalVideoSize(const gfx::Size& size) { natural_size_ = size; } -void PipelineImpl::SetStreaming(bool streaming) { - DCHECK(IsRunning()); - media_log_->AddEvent( - media_log_->CreateBooleanEvent( - MediaLogEvent::STREAMING_SET, "streaming", streaming)); - - base::AutoLock auto_lock(lock_); - streaming_ = streaming; -} - void PipelineImpl::NotifyEnded() { DCHECK(IsRunning()); message_loop_->PostTask(FROM_HERE, @@ -564,17 +554,6 @@ void PipelineImpl::NotifyEnded() { media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED)); } -void PipelineImpl::SetLoaded(bool loaded) { - DCHECK(IsRunning()); - media_log_->AddEvent( - media_log_->CreateBooleanEvent( - MediaLogEvent::LOADED_SET, "loaded", loaded)); - - base::AutoLock auto_lock(lock_); - loaded_ = loaded; - download_rate_monitor_.set_loaded(loaded_); -} - void PipelineImpl::SetNetworkActivity(bool is_downloading_data) { DCHECK(IsRunning()); @@ -1044,12 +1023,16 @@ void PipelineImpl::FilterStateTransitionTask() { // Start monitoring rate of downloading. int bitrate = 0; - if (demuxer_.get()) + if (demuxer_.get()) { bitrate = demuxer_->GetBitrate(); + local_source_ = demuxer_->IsLocalSource(); + streaming_ = !demuxer_->IsSeekable(); + } // Needs to be locked because most other calls to |download_rate_monitor_| // occur on the renderer thread. download_rate_monitor_.Start( - base::Bind(&PipelineImpl::OnCanPlayThrough, this), bitrate); + base::Bind(&PipelineImpl::OnCanPlayThrough, this), + bitrate, streaming_, local_source_); download_rate_monitor_.SetBufferedBytes(buffered_bytes_, base::Time::Now()); if (IsPipelineStopPending()) { diff --git a/media/base/pipeline_impl.h b/media/base/pipeline_impl.h index 57f8aebd..5fb8f82 100644 --- a/media/base/pipeline_impl.h +++ b/media/base/pipeline_impl.h @@ -126,7 +126,7 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline, public FilterHost { virtual int64 GetTotalBytes() const OVERRIDE; virtual void GetNaturalVideoSize(gfx::Size* out_size) const OVERRIDE; virtual bool IsStreaming() const OVERRIDE; - virtual bool IsLoaded() const OVERRIDE; + virtual bool IsLocalSource() const OVERRIDE; virtual PipelineStatistics GetStatistics() const OVERRIDE; void SetClockForTesting(Clock* clock); @@ -200,8 +200,6 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline, public FilterHost { virtual void SetTotalBytes(int64 total_bytes) OVERRIDE; virtual void SetBufferedBytes(int64 buffered_bytes) OVERRIDE; virtual void SetNaturalVideoSize(const gfx::Size& size) OVERRIDE; - virtual void SetStreaming(bool streamed) OVERRIDE; - virtual void SetLoaded(bool loaded) OVERRIDE; virtual void SetNetworkActivity(bool is_downloading_data) OVERRIDE; virtual void NotifyEnded() OVERRIDE; virtual void DisableAudioRenderer() OVERRIDE; @@ -385,13 +383,13 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline, public FilterHost { // Video's natural width and height. Set by filters. gfx::Size natural_size_; - // Sets by the filters to indicate whether the data source is a streaming + // Set by the demuxer to indicate whether the data source is a streaming // source. bool streaming_; - // Sets by the filters to indicate whether the data source is a fully - // loaded source. - bool loaded_; + // Indicates whether the data source is local, such as a local media file + // from disk or a local webcam stream. + bool local_source_; // Current volume level (from 0.0f to 1.0f). This value is set immediately // via SetVolume() and a task is dispatched on the message loop to notify the diff --git a/media/base/pipeline_impl_unittest.cc b/media/base/pipeline_impl_unittest.cc index 07f773d..fc9692e 100644 --- a/media/base/pipeline_impl_unittest.cc +++ b/media/base/pipeline_impl_unittest.cc @@ -552,11 +552,6 @@ TEST_F(PipelineImplTest, GetBufferedTime) { pipeline_->SetBufferedBytes(kTotalBytes); EXPECT_EQ(kDuration.ToInternalValue(), pipeline_->GetBufferedTime().ToInternalValue()); - - // If media is loaded, we should return duration of media. - pipeline_->SetLoaded(true); - EXPECT_EQ(kDuration.ToInternalValue(), - pipeline_->GetBufferedTime().ToInternalValue()); } TEST_F(PipelineImplTest, DisableAudioRenderer) { diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc index c27c490..d437d91 100644 --- a/media/filters/chunk_demuxer.cc +++ b/media/filters/chunk_demuxer.cc @@ -369,6 +369,16 @@ int ChunkDemuxer::GetBitrate() { return 0; } +bool ChunkDemuxer::IsLocalSource() { + // TODO(acolwell): Report whether source is local or not. + return false; +} + +bool ChunkDemuxer::IsSeekable() { + // TODO(acolwell): Report whether source is seekable or not. + return true; +} + // Demuxer implementation. scoped_refptr<DemuxerStream> ChunkDemuxer::GetStream( DemuxerStream::Type type) { diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h index a940100..b0f0d02 100644 --- a/media/filters/chunk_demuxer.h +++ b/media/filters/chunk_demuxer.h @@ -39,6 +39,8 @@ class MEDIA_EXPORT ChunkDemuxer : public Demuxer { virtual void SetPreload(Preload preload) OVERRIDE; virtual base::TimeDelta GetStartTime() const OVERRIDE; virtual int GetBitrate() OVERRIDE; + virtual bool IsLocalSource() OVERRIDE; + virtual bool IsSeekable() OVERRIDE; // Methods used by an external object to control this demuxer. void FlushData(); diff --git a/media/filters/dummy_demuxer.cc b/media/filters/dummy_demuxer.cc index 095ffee..30e727f 100644 --- a/media/filters/dummy_demuxer.cc +++ b/media/filters/dummy_demuxer.cc @@ -32,9 +32,10 @@ void DummyDemuxerStream::Read(const ReadCallback& read_callback) {} void DummyDemuxerStream::EnableBitstreamConverter() {} -DummyDemuxer::DummyDemuxer(bool has_video, bool has_audio) +DummyDemuxer::DummyDemuxer(bool has_video, bool has_audio, bool local_source) : has_video_(has_video), - has_audio_(has_audio) { + has_audio_(has_audio), + local_source_(local_source) { streams_.resize(DemuxerStream::NUM_TYPES); if (has_audio) streams_[DemuxerStream::AUDIO] = @@ -60,4 +61,14 @@ base::TimeDelta DummyDemuxer::GetStartTime() const { return base::TimeDelta(); } +bool DummyDemuxer::IsLocalSource() { + return local_source_; +} + +bool DummyDemuxer::IsSeekable() { + // This is always false because DummyDemuxer is only used by WebRTC and such + // streams are not seekable. + return false; +} + } // namespace media diff --git a/media/filters/dummy_demuxer.h b/media/filters/dummy_demuxer.h index 309dded..bf371c5 100644 --- a/media/filters/dummy_demuxer.h +++ b/media/filters/dummy_demuxer.h @@ -4,7 +4,8 @@ // Implements the Demuxer interface. DummyDemuxer returns corresponding // DummyDemuxerStream as signal for media pipeline to construct correct -// playback channels. +// playback channels. Used in WebRTC local video capture pipeline, where +// demuxing is not needed. #ifndef MEDIA_FILTERS_DUMMY_DEMUXER_H_ #define MEDIA_FILTERS_DUMMY_DEMUXER_H_ @@ -40,7 +41,7 @@ class DummyDemuxerStream : public DemuxerStream { class DummyDemuxer : public Demuxer { public: - DummyDemuxer(bool has_video, bool has_audio); + DummyDemuxer(bool has_video, bool has_audio, bool local_source); virtual ~DummyDemuxer(); // Demuxer implementation. @@ -49,10 +50,13 @@ class DummyDemuxer : public Demuxer { virtual void SetPreload(Preload preload) OVERRIDE; virtual base::TimeDelta GetStartTime() const OVERRIDE; virtual int GetBitrate() OVERRIDE; + virtual bool IsLocalSource() OVERRIDE; + virtual bool IsSeekable() OVERRIDE; private: bool has_video_; bool has_audio_; + bool local_source_; std::vector< scoped_refptr<DummyDemuxerStream> > streams_; DISALLOW_COPY_AND_ASSIGN(DummyDemuxer); diff --git a/media/filters/dummy_demuxer_factory.cc b/media/filters/dummy_demuxer_factory.cc index 37495e8..735cf59 100644 --- a/media/filters/dummy_demuxer_factory.cc +++ b/media/filters/dummy_demuxer_factory.cc @@ -9,9 +9,12 @@ namespace media { -DummyDemuxerFactory::DummyDemuxerFactory(bool has_video, bool has_audio) +DummyDemuxerFactory::DummyDemuxerFactory(bool has_video, + bool has_audio, + bool local_source) : has_video_(has_video), - has_audio_(has_audio) { + has_audio_(has_audio), + local_source_(local_source) { } DummyDemuxerFactory::~DummyDemuxerFactory() {} @@ -19,12 +22,12 @@ DummyDemuxerFactory::~DummyDemuxerFactory() {} void DummyDemuxerFactory::Build(const std::string& url, const BuildCallback& cb) { scoped_refptr<DummyDemuxer> demuxer = - new DummyDemuxer(has_video_, has_audio_); + new DummyDemuxer(has_video_, has_audio_, local_source_); cb.Run(PIPELINE_OK, demuxer.get()); } DemuxerFactory* DummyDemuxerFactory::Clone() const { - return new DummyDemuxerFactory(has_video_, has_audio_); + return new DummyDemuxerFactory(has_video_, has_audio_, local_source_); } } // namespace media diff --git a/media/filters/dummy_demuxer_factory.h b/media/filters/dummy_demuxer_factory.h index 6662799..0d8a6f7 100644 --- a/media/filters/dummy_demuxer_factory.h +++ b/media/filters/dummy_demuxer_factory.h @@ -14,7 +14,7 @@ namespace media { class MEDIA_EXPORT DummyDemuxerFactory : public DemuxerFactory { public: - DummyDemuxerFactory(bool has_video, bool has_audio); + DummyDemuxerFactory(bool has_video, bool has_audio, bool local_source); virtual ~DummyDemuxerFactory(); // DemuxerFactory methods. @@ -24,6 +24,7 @@ class MEDIA_EXPORT DummyDemuxerFactory : public DemuxerFactory { private: bool has_video_; bool has_audio_; + bool local_source_; DISALLOW_IMPLICIT_CONSTRUCTORS(DummyDemuxerFactory); }; diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 0c63fde..e33bada 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc @@ -277,8 +277,9 @@ base::TimeDelta FFmpegDemuxerStream::ConvertStreamTimestamp( // // FFmpegDemuxer // -FFmpegDemuxer::FFmpegDemuxer(MessageLoop* message_loop) +FFmpegDemuxer::FFmpegDemuxer(MessageLoop* message_loop, bool local_source) : message_loop_(message_loop), + local_source_(local_source), format_context_(NULL), read_event_(false, false), read_has_failed_(false), @@ -571,6 +572,14 @@ int FFmpegDemuxer::GetBitrate() { return 0; } +bool FFmpegDemuxer::IsLocalSource() { + return local_source_; +} + +bool FFmpegDemuxer::IsSeekable() { + return !IsStreaming(); +} + void FFmpegDemuxer::SeekTask(base::TimeDelta time, const FilterStatusCB& cb) { DCHECK_EQ(MessageLoop::current(), message_loop_); diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h index 0cff00f..3630481 100644 --- a/media/filters/ffmpeg_demuxer.h +++ b/media/filters/ffmpeg_demuxer.h @@ -128,7 +128,7 @@ class FFmpegDemuxerStream : public DemuxerStream { class MEDIA_EXPORT FFmpegDemuxer : public Demuxer, public FFmpegURLProtocol { public: - explicit FFmpegDemuxer(MessageLoop* message_loop); + FFmpegDemuxer(MessageLoop* message_loop, bool local_source); virtual ~FFmpegDemuxer(); // Posts a task to perform additional demuxing. @@ -148,6 +148,8 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer, public FFmpegURLProtocol { virtual void SetPreload(Preload preload) OVERRIDE; virtual base::TimeDelta GetStartTime() const OVERRIDE; virtual int GetBitrate() OVERRIDE; + virtual bool IsLocalSource() OVERRIDE; + virtual bool IsSeekable() OVERRIDE; // FFmpegURLProtocol implementation. virtual size_t Read(size_t size, uint8* data) OVERRIDE; @@ -208,6 +210,10 @@ class MEDIA_EXPORT FFmpegDemuxer : public Demuxer, public FFmpegURLProtocol { MessageLoop* message_loop_; + // True if the media is a local resource, false if the media require network + // access to be loaded. + bool local_source_; + // FFmpeg context handle. AVFormatContext* format_context_; diff --git a/media/filters/ffmpeg_demuxer_factory.cc b/media/filters/ffmpeg_demuxer_factory.cc index 626cded..dddda76b 100644 --- a/media/filters/ffmpeg_demuxer_factory.cc +++ b/media/filters/ffmpeg_demuxer_factory.cc @@ -4,6 +4,7 @@ #include "base/bind.h" #include "base/message_loop.h" +#include "googleurl/src/gurl.h" #include "media/filters/ffmpeg_demuxer.h" #include "media/filters/ffmpeg_demuxer_factory.h" @@ -28,14 +29,14 @@ static void DemuxerInitDone(const DemuxerFactory::BuildCallback& cb, static void InitializeDemuxerBasedOnDataSourceStatus( const DemuxerFactory::BuildCallback& cb, - MessageLoop* loop, + MessageLoop* loop, bool local_source, PipelineStatus status, DataSource* data_source) { if (status != PIPELINE_OK) { cb.Run(status, NULL); return; } DCHECK(data_source); - scoped_refptr<FFmpegDemuxer> demuxer = new FFmpegDemuxer(loop); + scoped_refptr<FFmpegDemuxer> demuxer = new FFmpegDemuxer(loop, local_source); demuxer->Initialize( data_source, base::Bind(&DemuxerInitDone, cb, demuxer)); @@ -43,9 +44,12 @@ static void InitializeDemuxerBasedOnDataSourceStatus( void FFmpegDemuxerFactory::Build(const std::string& url, const BuildCallback& cb) { + GURL gurl = GURL(url); + bool local_source = !gurl.SchemeIs("http") && !gurl.SchemeIs("https"); data_source_factory_->Build( url, - base::Bind(&InitializeDemuxerBasedOnDataSourceStatus, cb, loop_)); + base::Bind(&InitializeDemuxerBasedOnDataSourceStatus, + cb, loop_, local_source)); } DemuxerFactory* FFmpegDemuxerFactory::Clone() const { diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc index b07b8ac..2c46894 100644 --- a/media/filters/ffmpeg_demuxer_unittest.cc +++ b/media/filters/ffmpeg_demuxer_unittest.cc @@ -42,8 +42,8 @@ class FFmpegDemuxerTest : public testing::Test { protected: FFmpegDemuxerTest() { - // Create an FFmpegDemuxer. - demuxer_ = new FFmpegDemuxer(&message_loop_); + // Create an FFmpegDemuxer with local data source. + demuxer_ = new FFmpegDemuxer(&message_loop_, true); demuxer_->disable_first_seek_hack_for_testing(); // Inject a filter host and message loop and prepare a data source. @@ -508,7 +508,7 @@ TEST_F(FFmpegDemuxerTest, DisableAudioStream) { class MockFFmpegDemuxer : public FFmpegDemuxer { public: explicit MockFFmpegDemuxer(MessageLoop* message_loop) - : FFmpegDemuxer(message_loop) { + : FFmpegDemuxer(message_loop, true) { } virtual ~MockFFmpegDemuxer() {} diff --git a/webkit/media/buffered_data_source.cc b/webkit/media/buffered_data_source.cc index 0c005ab..8a5feba 100644 --- a/webkit/media/buffered_data_source.cc +++ b/webkit/media/buffered_data_source.cc @@ -45,7 +45,6 @@ BufferedDataSource::BufferedDataSource( media::MediaLog* media_log) : total_bytes_(kPositionNotSpecified), buffered_bytes_(0), - loaded_(false), streaming_(false), frame_(frame), loader_(NULL), @@ -431,7 +430,6 @@ void BufferedDataSource::HttpInitialStartCallback(int error) { // TODO(hclam): Needs more thinking about supporting servers without range // request or their partial response is not complete. total_bytes_ = instance_size; - loaded_ = false; streaming_ = (instance_size == kPositionNotSpecified) || !loader_->range_supported(); } else { @@ -501,7 +499,6 @@ void BufferedDataSource::NonHttpInitialStartCallback(int error) { if (success) { total_bytes_ = instance_size; buffered_bytes_ = total_bytes_; - loaded_ = true; } else { loader_->Stop(); } @@ -616,7 +613,7 @@ void BufferedDataSource::NetworkEventCallback() { // In case of non-HTTP request we don't need to report network events, // so return immediately. - if (loaded_) + if (!url_.SchemeIs(kHttpScheme) && !url_.SchemeIs(kHttpsScheme)) return; bool is_downloading_data = loader_->is_downloading_data(); @@ -657,11 +654,6 @@ void BufferedDataSource::UpdateHostState_Locked() { if (!filter_host) return; - filter_host->SetLoaded(loaded_); - - if (streaming_) - filter_host->SetStreaming(true); - if (total_bytes_ != kPositionNotSpecified) filter_host->SetTotalBytes(total_bytes_); filter_host->SetBufferedBytes(buffered_bytes_); diff --git a/webkit/media/buffered_data_source.h b/webkit/media/buffered_data_source.h index d7dc37f..1332489 100644 --- a/webkit/media/buffered_data_source.h +++ b/webkit/media/buffered_data_source.h @@ -147,9 +147,6 @@ class BufferedDataSource : public WebDataSource { int64 total_bytes_; int64 buffered_bytes_; - // True if this data source is considered loaded. - bool loaded_; - // This value will be true if this data source can only support streaming. // i.e. range request is not supported. bool streaming_; diff --git a/webkit/media/buffered_data_source_unittest.cc b/webkit/media/buffered_data_source_unittest.cc index 2bcae64..b32bf5c 100644 --- a/webkit/media/buffered_data_source_unittest.cc +++ b/webkit/media/buffered_data_source_unittest.cc @@ -110,7 +110,6 @@ class BufferedDataSourceTest : public testing::Test { void InitializeWith206Response() { Initialize(media::PIPELINE_OK); - EXPECT_CALL(host_, SetLoaded(false)); EXPECT_CALL(host_, SetTotalBytes(response_generator_.content_length())); EXPECT_CALL(host_, SetBufferedBytes(0)); Respond(response_generator_.Generate206(0)); @@ -198,7 +197,6 @@ class BufferedDataSourceTest : public testing::Test { TEST_F(BufferedDataSourceTest, Range_Supported) { Initialize(media::PIPELINE_OK); - EXPECT_CALL(host_, SetLoaded(false)); EXPECT_CALL(host_, SetTotalBytes(response_generator_.content_length())); EXPECT_CALL(host_, SetBufferedBytes(0)); Respond(response_generator_.Generate206(0)); @@ -233,13 +231,12 @@ TEST_F(BufferedDataSourceTest, Range_NotSupported) { Respond(response_generator_.Generate200()); // Now it'll succeed. - EXPECT_CALL(host_, SetLoaded(false)); EXPECT_CALL(host_, SetTotalBytes(response_generator_.content_length())); EXPECT_CALL(host_, SetBufferedBytes(0)); - EXPECT_CALL(host_, SetStreaming(true)); Respond(response_generator_.Generate200()); EXPECT_TRUE(data_source_->loading()); + EXPECT_TRUE(data_source_->IsStreaming()); Stop(); } @@ -265,7 +262,6 @@ TEST_F(BufferedDataSourceTest, Range_MissingContentLength) { Initialize(media::PIPELINE_OK); // It'll manage without a Content-Length response. - EXPECT_CALL(host_, SetLoaded(false)); EXPECT_CALL(host_, SetTotalBytes(response_generator_.content_length())); EXPECT_CALL(host_, SetBufferedBytes(0)); Respond(response_generator_.Generate206( diff --git a/webkit/media/simple_data_source.cc b/webkit/media/simple_data_source.cc index 16d0a9f..04e94d1 100644 --- a/webkit/media/simple_data_source.cc +++ b/webkit/media/simple_data_source.cc @@ -352,8 +352,6 @@ void SimpleDataSource::UpdateHostState() { if (host()) { host()->SetTotalBytes(size_); host()->SetBufferedBytes(size_); - // If scheme is file or data, say we are loaded. - host()->SetLoaded(url_.SchemeIsFile() || url_.SchemeIs(kDataScheme)); } } diff --git a/webkit/media/simple_data_source_unittest.cc b/webkit/media/simple_data_source_unittest.cc index 62b933c3..df6ee03 100644 --- a/webkit/media/simple_data_source_unittest.cc +++ b/webkit/media/simple_data_source_unittest.cc @@ -84,7 +84,7 @@ class SimpleDataSourceTest : public testing::Test { MessageLoop::current()->RunAllPending(); } - void RequestSucceeded(bool is_loaded) { + void RequestSucceeded() { WebURLResponse response(gurl_); response.setExpectedContentLength(kDataSize); @@ -93,11 +93,8 @@ class SimpleDataSourceTest : public testing::Test { EXPECT_TRUE(data_source_->GetSize(&size)); EXPECT_EQ(kDataSize, size); - for (int i = 0; i < kDataSize; ++i) { + for (int i = 0; i < kDataSize; ++i) data_source_->didReceiveData(NULL, data_ + i, 1, 1); - } - - EXPECT_CALL(host_, SetLoaded(is_loaded)); InSequence s; EXPECT_CALL(host_, SetTotalBytes(kDataSize)); @@ -170,21 +167,21 @@ class SimpleDataSourceTest : public testing::Test { TEST_F(SimpleDataSourceTest, InitializeHTTP) { InitializeDataSource(kHttpUrl, media::NewExpectedStatusCB(media::PIPELINE_OK)); - RequestSucceeded(false); + RequestSucceeded(); DestroyDataSource(); } TEST_F(SimpleDataSourceTest, InitializeHTTPS) { InitializeDataSource(kHttpsUrl, media::NewExpectedStatusCB(media::PIPELINE_OK)); - RequestSucceeded(false); + RequestSucceeded(); DestroyDataSource(); } TEST_F(SimpleDataSourceTest, InitializeFile) { InitializeDataSource(kFileUrl, media::NewExpectedStatusCB(media::PIPELINE_OK)); - RequestSucceeded(true); + RequestSucceeded(); DestroyDataSource(); } @@ -197,7 +194,6 @@ TEST_F(SimpleDataSourceTest, InitializeData) { data_source_->set_host(&host_); data_source_->SetURLLoaderForTest(url_loader_); - EXPECT_CALL(host_, SetLoaded(true)); EXPECT_CALL(host_, SetTotalBytes(sizeof(kDataUrlDecoded))); EXPECT_CALL(host_, SetBufferedBytes(sizeof(kDataUrlDecoded))); @@ -233,7 +229,7 @@ TEST_F(SimpleDataSourceTest, StopWhenDownloading) { TEST_F(SimpleDataSourceTest, AsyncRead) { InitializeDataSource(kFileUrl, media::NewExpectedStatusCB(media::PIPELINE_OK)); - RequestSucceeded(true); + RequestSucceeded(); AsyncRead(); DestroyDataSource(); } @@ -245,7 +241,7 @@ TEST_F(SimpleDataSourceTest, HasSingleOrigin) { // Make sure no redirect case works as expected. InitializeDataSource(kHttpUrl, media::NewExpectedStatusCB(media::PIPELINE_OK)); - RequestSucceeded(false); + RequestSucceeded(); EXPECT_TRUE(data_source_->HasSingleOrigin()); DestroyDataSource(); @@ -253,7 +249,7 @@ TEST_F(SimpleDataSourceTest, HasSingleOrigin) { InitializeDataSource(kHttpUrl, media::NewExpectedStatusCB(media::PIPELINE_OK)); Redirect(kHttpRedirectToSameDomainUrl1); - RequestSucceeded(false); + RequestSucceeded(); EXPECT_TRUE(data_source_->HasSingleOrigin()); DestroyDataSource(); @@ -262,7 +258,7 @@ TEST_F(SimpleDataSourceTest, HasSingleOrigin) { media::NewExpectedStatusCB(media::PIPELINE_OK)); Redirect(kHttpRedirectToSameDomainUrl1); Redirect(kHttpRedirectToSameDomainUrl2); - RequestSucceeded(false); + RequestSucceeded(); EXPECT_TRUE(data_source_->HasSingleOrigin()); DestroyDataSource(); @@ -270,7 +266,7 @@ TEST_F(SimpleDataSourceTest, HasSingleOrigin) { InitializeDataSource(kHttpUrl, media::NewExpectedStatusCB(media::PIPELINE_OK)); Redirect(kHttpRedirectToDifferentDomainUrl1); - RequestSucceeded(false); + RequestSucceeded(); EXPECT_FALSE(data_source_->HasSingleOrigin()); DestroyDataSource(); @@ -279,7 +275,7 @@ TEST_F(SimpleDataSourceTest, HasSingleOrigin) { media::NewExpectedStatusCB(media::PIPELINE_OK)); Redirect(kHttpRedirectToSameDomainUrl1); Redirect(kHttpRedirectToDifferentDomainUrl1); - RequestSucceeded(false); + RequestSucceeded(); EXPECT_FALSE(data_source_->HasSingleOrigin()); DestroyDataSource(); } diff --git a/webkit/media/webmediaplayer_impl.cc b/webkit/media/webmediaplayer_impl.cc index 941f88f..7df55e6 100644 --- a/webkit/media/webmediaplayer_impl.cc +++ b/webkit/media/webmediaplayer_impl.cc @@ -291,9 +291,14 @@ void WebMediaPlayerImpl::load(const WebKit::WebURL& url) { } // TODO(wjia): add audio decoder handling when it's available. - if (has_video || has_audio) + if (has_video || has_audio) { + // TODO(vrk/wjia): Setting true for local_source is under the assumption + // that the MediaStream represents a local webcam. This will need to + // change in the future when GetVideoDecoder is no longer hardcoded to + // only return CaptureVideoDecoders. filter_collection_->SetDemuxerFactory( - new media::DummyDemuxerFactory(has_video, has_audio)); + new media::DummyDemuxerFactory(has_video, has_audio, true)); + } } // Handle any volume changes that occured before load(). @@ -746,14 +751,11 @@ void WebMediaPlayerImpl::OnPipelineInitialize(PipelineStatus status) { is_accelerated_compositing_active_); } - if (pipeline_->IsLoaded()) + if (pipeline_->IsLocalSource()) SetNetworkState(WebKit::WebMediaPlayer::Loaded); SetReadyState(WebKit::WebMediaPlayer::HaveMetadata); - // Fire canplaythrough immediately after playback begins because of - // crbug.com/105163. - // TODO(vrk): set ready state to HaveFutureData when bug above is fixed. - SetReadyState(WebKit::WebMediaPlayer::HaveEnoughData); + SetReadyState(WebKit::WebMediaPlayer::HaveFutureData); } else { // TODO(hclam): should use |status| to determine the state // properly and reports error using MediaError. @@ -842,10 +844,7 @@ void WebMediaPlayerImpl::OnNetworkEvent(NetworkEvent type) { SetNetworkState(WebKit::WebMediaPlayer::Idle); break; case media::CAN_PLAY_THROUGH: - // Temporarily disable delayed firing of CAN_PLAY_THROUGH due to - // crbug.com/105163. - // TODO(vrk): uncomment code below when bug above is fixed. - // SetReadyState(WebKit::WebMediaPlayer::HaveEnoughData); + SetReadyState(WebKit::WebMediaPlayer::HaveEnoughData); break; default: NOTREACHED(); |