summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorvrk@google.com <vrk@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-20 23:42:21 +0000
committervrk@google.com <vrk@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-20 23:42:21 +0000
commit929ee6479d6016026bc35bc3ecee26d08bbba19b (patch)
tree2eb78d955de7280799343419548805419f87a112 /media
parent0cfea58dc67d34b7c7781613e13ddbea413c23a1 (diff)
downloadchromium_src-929ee6479d6016026bc35bc3ecee26d08bbba19b.zip
chromium_src-929ee6479d6016026bc35bc3ecee26d08bbba19b.tar.gz
chromium_src-929ee6479d6016026bc35bc3ecee26d08bbba19b.tar.bz2
Fire canplaythrough as soon as download defers to fix autoplay
Reenables delayed firing of canplaythrough for media elements, and fixes the bug that had been introduced where a video with autoplay=true sometimes never starts. With this change, a video with autoplay=true should always (though not necessarily immediately) start playback on its own. BUG=106480,73609 TEST=media_unitests, manually checking video files in various conditions Review URL: https://chromiumcodereview.appspot.com/9113023 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@118546 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/download_rate_monitor.cc31
-rw-r--r--media/base/download_rate_monitor.h8
-rw-r--r--media/base/download_rate_monitor_unittest.cc231
-rw-r--r--media/base/pipeline.cc8
4 files changed, 169 insertions, 109 deletions
diff --git a/media/base/download_rate_monitor.cc b/media/base/download_rate_monitor.cc
index f27b2e8..dd3c7ef 100644
--- a/media/base/download_rate_monitor.cc
+++ b/media/base/download_rate_monitor.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -91,8 +91,6 @@ void DownloadRateMonitor::SetBufferedBytes(
if (stopped_)
return;
- is_downloading_data_ = true;
-
// Check monotonically nondecreasing constraint.
base::Time previous_time;
if (!current_sample_.is_null())
@@ -120,12 +118,11 @@ void DownloadRateMonitor::SetBufferedBytes(
}
void DownloadRateMonitor::SetNetworkActivity(bool is_downloading_data) {
- if (is_downloading_data == is_downloading_data_)
- return;
- // Invalidate the current sample if downloading is going from start to stopped
- // or vice versa.
- current_sample_.Reset();
- is_downloading_data_ = is_downloading_data;
+ // Record when download defers for the first time.
+ if (!is_downloading_data && !has_deferred_) {
+ has_deferred_ = true;
+ NotifyCanPlayThroughIfNeeded();
+ }
}
void DownloadRateMonitor::Stop() {
@@ -139,13 +136,13 @@ void DownloadRateMonitor::Reset() {
has_notified_can_play_through_ = false;
current_sample_.Reset();
sample_window_.clear();
- is_downloading_data_ = false;
total_bytes_ = -1;
buffered_bytes_ = 0;
local_source_ = false;
bitrate_ = 0;
stopped_ = true;
streaming_ = false;
+ has_deferred_ = false;
}
DownloadRateMonitor::~DownloadRateMonitor() { }
@@ -210,8 +207,9 @@ bool DownloadRateMonitor::ShouldNotifyCanPlayThrough() {
if (local_source_ || streaming_)
return true;
- // If all bytes are buffered, fire CanPlayThrough.
- if (buffered_bytes_ == total_bytes_)
+ // If all bytes are buffered or if enough bytes were buffered such that
+ // downloading has deferred, fire CanPlayThrough.
+ if (buffered_bytes_ == total_bytes_ || has_deferred_)
return true;
// If bitrate is unknown, optimistically fire CanPlayThrough immediately.
@@ -228,12 +226,9 @@ bool DownloadRateMonitor::ShouldNotifyCanPlayThrough() {
if (download_rate > 0)
return download_rate >= bytes_needed_per_second;
- // If download rate is unknown, it may be because the media is being
- // downloaded so fast that it cannot collect an adequate number of samples
- // before the download gets deferred.
- //
- // To catch this case, we also look at how much data is being downloaded
- // immediately after the download begins.
+ // With very fast connections, we may want to fire CanPlayThrough before
+ // waiting for the sample window size to reach |kNumberOfSamples|. Check for
+ // this scenario.
if (sample_window_.size() < kNumberOfSamples) {
int64 bytes_downloaded_since_start =
bytes_downloaded_in_window() + current_sample_.bytes_downloaded();
diff --git a/media/base/download_rate_monitor.h b/media/base/download_rate_monitor.h
index 4fca328..b26c61b 100644
--- a/media/base/download_rate_monitor.h
+++ b/media/base/download_rate_monitor.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -126,9 +126,6 @@ class MEDIA_EXPORT DownloadRateMonitor {
Sample current_sample_;
std::deque<Sample> sample_window_;
- // True if actively downloading bytes, false otherwise.
- bool is_downloading_data_;
-
// Total number of bytes in the media file, 0 if unknown or undefined.
int64 total_bytes_;
@@ -149,6 +146,9 @@ class MEDIA_EXPORT DownloadRateMonitor {
// True if the data source is a streaming source, false otherwise.
bool streaming_;
+ // True if downloading has been deferred at least once, false otherwise.
+ bool has_deferred_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadRateMonitor);
};
diff --git a/media/base/download_rate_monitor_unittest.cc b/media/base/download_rate_monitor_unittest.cc
index 321ad63..9715526 100644
--- a/media/base/download_rate_monitor_unittest.cc
+++ b/media/base/download_rate_monitor_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,151 +15,216 @@ namespace media {
class DownloadRateMonitorTest : public ::testing::Test {
public:
- DownloadRateMonitorTest() {
- monitor_.set_total_bytes(kMediaSizeInBytes);
- }
+ DownloadRateMonitorTest()
+ : canplaythrough_cb_(base::Bind(&DownloadRateMonitorTest::CanPlayThrough,
+ base::Unretained(this))) { }
virtual ~DownloadRateMonitorTest() { }
MOCK_METHOD0(CanPlayThrough, void());
protected:
- static const int kMediaSizeInBytes = 20 * 1024 * 1024;
-
- // Simulates downloading of the media file. Packets are timed evenly in
- // |ms_between_packets| intervals, starting at |starting_time|, which is
- // number of seconds since unix epoch (Jan 1, 1970).
- // Returns the number of bytes buffered in the media file after the
- // network activity.
- int SimulateNetwork(double starting_time,
- int starting_bytes,
- int bytes_per_packet,
- int ms_between_packets,
- int number_of_packets) {
- int bytes_buffered = starting_bytes;
- base::Time packet_time = base::Time::FromDoubleT(starting_time);
-
- monitor_.SetNetworkActivity(true);
- // Loop executes (number_of_packets + 1) times because a packet needs a
- // starting and end point.
- for (int i = 0; i < number_of_packets + 1; ++i) {
- monitor_.SetBufferedBytes(bytes_buffered, packet_time);
- packet_time += base::TimeDelta::FromMilliseconds(ms_between_packets);
- bytes_buffered += bytes_per_packet;
+ static const int kMediaDuration = 120;
+ static const int kMediaBitrate = 1024 * 1024 * 8;
+ static const int kMediaByterate = kMediaBitrate / 8;
+ static const int kMediaSizeInBytes = kMediaDuration * kMediaByterate;
+ static const int kDeferThreshold = 30 * kMediaByterate;
+
+ // Simulates downloading |bytes_to_download| bytes of the media file, at
+ // |download_speed_in_bps| bytes per second.
+ void SimulateNetwork(int bytes_to_download, int download_speed_in_bps) {
+ int bytes_downloaded = 0;
+ while (bytes_downloaded < bytes_to_download &&
+ !data_source_.is_deferred()) {
+ int bytes_left_to_download = bytes_to_download - bytes_downloaded;
+ int packet_size = std::min(download_speed_in_bps, bytes_left_to_download);
+ time_elapsed_ += base::TimeDelta::FromMilliseconds(
+ 1000 * packet_size / download_speed_in_bps);
+ data_source_.ReceiveData(
+ packet_size, time_elapsed_ + base::Time::UnixEpoch());
+ bytes_downloaded += packet_size;
}
- monitor_.SetNetworkActivity(false);
- return bytes_buffered;
}
- void StartMonitor(int bitrate) {
- StartMonitor(bitrate, false, false);
+ void Initialize() {
+ Initialize(false, false);
+ }
+
+ void Initialize(bool streaming, bool local_source) {
+ data_source_.Initialize(
+ kMediaBitrate, streaming, local_source, canplaythrough_cb_);
+ }
+
+ bool DownloadIsDeferred() {
+ return data_source_.is_deferred();
}
- void StartMonitor(int bitrate, bool streaming, bool local_source) {
- monitor_.Start(base::Bind(&DownloadRateMonitorTest::CanPlayThrough,
- base::Unretained(this)), bitrate, streaming, local_source);
+ void SeekTo(int offset) {
+ data_source_.SeekTo(offset);
}
- DownloadRateMonitor monitor_;
+ // Returns the size of |seconds| seconds of media data in bytes.
+ int SecondsToBytes(int seconds) {
+ return seconds * kMediaByterate;
+ }
private:
+ // Helper class to simulate a buffered data source.
+ class FakeDataSource {
+ public:
+ FakeDataSource()
+ : total_bytes_(kMediaSizeInBytes),
+ buffered_bytes_(0),
+ offset_(0),
+ defer_threshold_(kDeferThreshold),
+ is_downloading_data_(true) { }
+
+ bool is_deferred() { return !is_downloading_data_; }
+
+ void ReceiveData(int bytes_received, base::Time packet_time) {
+ CHECK(is_downloading_data_);
+ buffered_bytes_ += bytes_received;
+ // This simulates that the download is being deferred.
+ if (buffered_bytes_ >= defer_threshold_)
+ is_downloading_data_ = false;
+
+ // Update monitor's state.
+ monitor_.SetNetworkActivity(is_downloading_data_);
+ monitor_.set_total_bytes(total_bytes_);
+ monitor_.SetBufferedBytes(buffered_bytes_ + offset_, packet_time);
+ }
+
+ void Initialize(int bitrate, bool streaming, bool local_source,
+ const base::Closure& canplaythrough_cb) {
+ monitor_.Start(canplaythrough_cb, bitrate, streaming, local_source);
+ }
+
+ void SeekTo(int byte_position) {
+ offset_ = byte_position;
+ // Simulate recreating the buffer after a seek.
+ buffered_bytes_ = 0;
+ is_downloading_data_ = true;
+ }
+
+ private:
+ DownloadRateMonitor monitor_;
+
+ // Size of the media file being downloaded, in bytes.
+ int total_bytes_;
+
+ // Number of bytes currently in buffer.
+ int buffered_bytes_;
+
+ // The byte offset into the file from which the download began.
+ int offset_;
+
+ // The size of |buffered_bytes_| at which downloading should defer.
+ int defer_threshold_;
+
+ // True if download is active (not deferred_, false otherwise.
+ bool is_downloading_data_;
+ };
+
+ FakeDataSource data_source_;
+ base::Closure canplaythrough_cb_;
+
+ // Amount of time elapsed while downloading data.
+ base::TimeDelta time_elapsed_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadRateMonitorTest);
};
TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate) {
- static const int media_bitrate = 1024 * 1024 * 8;
-
// Simulate downloading at double the media's bitrate.
- StartMonitor(media_bitrate);
+ Initialize();
EXPECT_CALL(*this, CanPlayThrough());
- SimulateNetwork(1, 0, 2 * media_bitrate / 8, 1000, 10);
+ SimulateNetwork(SecondsToBytes(20), 2 * kMediaByterate);
}
-// If the user pauses and the pipeline stops downloading data, make sure the
-// DownloadRateMonitor understands that the download is not stalling.
-TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_Pause) {
- static const int media_bitrate = 1024 * 1024 * 8;
- static const int download_byte_rate = 1.1 * media_bitrate / 8;
+TEST_F(DownloadRateMonitorTest, DownloadRateLessThanBitrate_Defer) {
+ Initialize();
- // Start downloading faster than the media's bitrate.
- StartMonitor(media_bitrate);
+ // Download slower than the media's bitrate, but buffer enough data such that
+ // the data source defers.
EXPECT_CALL(*this, CanPlayThrough());
- int buffered = SimulateNetwork(1, 0, download_byte_rate, 1000, 2);
-
- // Then "pause" for 3 minutes and continue downloading at same rate.
- SimulateNetwork(60 * 3, buffered, download_byte_rate, 1000, 4);
+ SimulateNetwork(kDeferThreshold, 0.3 * kMediaByterate);
+ CHECK(DownloadIsDeferred());
}
TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekForward) {
- static const int media_bitrate = 1024 * 1024 * 8;
- static const int download_byte_rate = 1.1 * media_bitrate / 8;
-
// Start downloading faster than the media's bitrate.
- EXPECT_CALL(*this, CanPlayThrough());
- StartMonitor(media_bitrate);
- SimulateNetwork(1, 0, download_byte_rate, 1000, 2);
+ Initialize();
+ SimulateNetwork(SecondsToBytes(3), 1.1 * kMediaByterate);
// Then seek forward mid-file and continue downloading at same rate.
- SimulateNetwork(4, kMediaSizeInBytes / 2, download_byte_rate, 1000, 4);
+ SeekTo(kMediaSizeInBytes / 2);
+ EXPECT_CALL(*this, CanPlayThrough());
+ SimulateNetwork(7 * kMediaByterate, 1.1 * kMediaByterate);
+
+ // Verify deferring is not what caused CanPlayThrough to fire.
+ CHECK(!DownloadIsDeferred());
}
TEST_F(DownloadRateMonitorTest, DownloadRateGreaterThanBitrate_SeekBackward) {
- static const int media_bitrate = 1024 * 1024 * 8;
- static const int download_byte_rate = 1.1 * media_bitrate / 8;
-
// Start downloading faster than the media's bitrate, in middle of file.
- StartMonitor(media_bitrate);
- SimulateNetwork(1, kMediaSizeInBytes / 2, download_byte_rate, 1000, 2);
+ Initialize();
+ SeekTo(kMediaSizeInBytes / 2);
+ SimulateNetwork(SecondsToBytes(3), 1.1 * kMediaByterate);
// Then seek back to beginning and continue downloading at same rate.
+ SeekTo(0);
EXPECT_CALL(*this, CanPlayThrough());
- SimulateNetwork(4, 0, download_byte_rate, 1000, 4);
-}
+ SimulateNetwork(SecondsToBytes(7), 1.1 * kMediaByterate);
-TEST_F(DownloadRateMonitorTest, DownloadRateLessThanBitrate) {
- static const int media_bitrate = 1024 * 1024 * 8;
+ // Verify deferring is not what caused CanPlayThrough to fire.
+ CHECK(!DownloadIsDeferred());
+}
+TEST_F(DownloadRateMonitorTest, DownloadRateLessThanByterate) {
// Simulate downloading at half the media's bitrate.
EXPECT_CALL(*this, CanPlayThrough())
.Times(0);
- StartMonitor(media_bitrate);
- SimulateNetwork(1, 0, media_bitrate / 8 / 2, 1000, 10);
+ Initialize();
+ SimulateNetwork(SecondsToBytes(10), kMediaByterate / 2);
}
TEST_F(DownloadRateMonitorTest, MediaSourceIsLocal) {
- static const int media_bitrate = 1024 * 1024 * 8;
-
// Simulate no data downloaded.
EXPECT_CALL(*this, CanPlayThrough());
- StartMonitor(media_bitrate, false, true);
+ Initialize(false, true);
}
TEST_F(DownloadRateMonitorTest, MediaSourceIsStreaming) {
- static const int media_bitrate = 1024 * 1024 * 8;
-
// Simulate downloading at the media's bitrate while streaming.
EXPECT_CALL(*this, CanPlayThrough());
- StartMonitor(media_bitrate, true, false);
- SimulateNetwork(1, 0, media_bitrate / 8, 1000, 10);
+ Initialize(true, false);
+ SimulateNetwork(SecondsToBytes(10), kMediaByterate);
}
TEST_F(DownloadRateMonitorTest, VeryFastDownloadRate) {
- static const int media_bitrate = 1024 * 1024 * 8;
-
// Simulate downloading half the video very quickly in one chunk.
- StartMonitor(media_bitrate);
+ Initialize();
EXPECT_CALL(*this, CanPlayThrough());
- SimulateNetwork(1, 0, kMediaSizeInBytes / 2, 10, 1);
+ SimulateNetwork(kMediaSizeInBytes / 2, kMediaSizeInBytes * 10);
}
TEST_F(DownloadRateMonitorTest, DownloadEntireVideo) {
- static const int seconds_of_data = 20;
- static const int media_bitrate = kMediaSizeInBytes * 8 / seconds_of_data;
-
// Simulate downloading entire video at half the bitrate of the video.
- StartMonitor(media_bitrate);
+ Initialize();
EXPECT_CALL(*this, CanPlayThrough());
- SimulateNetwork(1, 0, media_bitrate / 8 / 2, 1000, seconds_of_data * 2);
+ SimulateNetwork(kMediaSizeInBytes, kMediaByterate / 2);
+}
+
+TEST_F(DownloadRateMonitorTest, DownloadEndOfVideo) {
+ Initialize();
+ // Seek to 10s before the end of the file, then download the remainder of the
+ // file at half the bitrate.
+ SeekTo((kMediaDuration - 10) * kMediaByterate);
+ EXPECT_CALL(*this, CanPlayThrough());
+ SimulateNetwork(SecondsToBytes(10), kMediaByterate/ 2);
+
+ // Verify deferring is not what caused CanPlayThrough to fire.
+ CHECK(!DownloadIsDeferred());
}
} // namespace media
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc
index 7995796..d1b68fb 100644
--- a/media/base/pipeline.cc
+++ b/media/base/pipeline.cc
@@ -1020,11 +1020,8 @@ void Pipeline::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(
@@ -1139,6 +1136,9 @@ void Pipeline::OnDemuxerBuilt(PipelineStatus status, Demuxer* demuxer) {
}
demuxer_ = demuxer;
+ // Set fields obtained from demuxer.
+ local_source_ = demuxer_->IsLocalSource();
+ streaming_ = !demuxer_->IsSeekable();
demuxer_->set_host(this);
{